57

To antecipate the question: do I need to get SSL support on Heroku in order to establish a connection between Heroku and Atlas MongoDB Cloud using SSL? (TSL/SSL connection is a requirement to access Atlas MongoDB Cloud service).


I am trying to connect my Heroku App, written in node.js, to a cluster hosted at Atlas MongoDB Cloud.

My current database is hosted at mLab (as a Heroku Add-on), and the MongoDB URI used to access the cluster through mongoose is (using xxx to omit confidential info):

MONGODB_URI="mongodb://xxx:xxx@xxx-a0.mlab.com:23266,xxx-a1.mlab.com:xxx/xxx?replicaSet=rs-xxx"

Now that I've migrated my data from mLab to Atlas MongoDB Cloud, I am currently accessing the cluster using the URI:

MONGODB_URI="mongodb://xxx:xxx@cluster0-shard-xxx.mongodb.net:xxx,cluster0-shard-xxx.mongodb.net:xxx,cluster0-shard-xxx.mongodb.net:xxx/xxx?replicaSet=xxx&ssl=true&authSource=admin"

When running my Heroku App locally in my machine I can access the database with no problem. I'm also able to connect to the cluster using mongo shell.

However, when running the App in Heroku, the connection cannot be established. In the Browser JS console, I get the 503 service unavailable message. In heroku, I get the error:

no primary found in replica set

I am aware that Atlas MongoDB Cloud requires SSL connection, differently from mLab. In my local machine, I suppose a self signed certificate is being used to connect successfully to the cluster.

My question is: do I need to get SSL support in Heroku in order to be able to access establish the secure connection between Heroku and MongoDB Atlas? Or the SSL suport in Heroku is only required to client/Heroku secure connection?

amaralbf
  • 900
  • 1
  • 6
  • 12

6 Answers6

71

What I think might fix your problem

Disclaimer: I have used neither Heroku nor MongoDB Atlas but I am looking into them.

According to a Github issue I found, you will get that error message if you haven't whitelisted the server IP addresses in MongoDB Atlas.

Reading the MongoDB Atlas docs, the only way I see to do this in combination with Heroku dynos is to add 0.0.0.0/0 (i.e. all addresses) to your MongoDB Atlas whitelist.

Give that a try and please report back whether you can instantiate a connection.

On SSL

Trying to reply to the SSL question, I do not think that you need to enable it on Heroku based on what I read, although I am not totally sure.

If the MongoDB server performed certificate validation, the Node.js code for connecting to it would have to look like the following (taken from the Node.js driver documentation):

var MongoClient = require('mongodb').MongoClient,
  f = require('util').format,
  fs = require('fs');

// Read the certificates
var ca = [fs.readFileSync(__dirname + "/ssl/ca.pem")];
var cert = fs.readFileSync(__dirname + "/ssl/client.pem");
var key = fs.readFileSync(__dirname + "/ssl/client.pem");

// Connect validating the returned certificates from the server
MongoClient.connect("mongodb://localhost:27017/test?ssl=true", {
  server: {
      sslValidate:true
    , sslCA:ca
    , sslKey:key
    , sslCert:cert
    , sslPass:'10gen'
  }
}, function(err, db) {
  db.close();
});

If the MongoDB server does not check for any SSL certificates, you can simply use code like the following (also taken from the Node.js driver documentation):

var MongoClient = require('mongodb').MongoClient;

MongoClient.connect("mongodb://localhost:27017/test?ssl=true", function(err, db) {
  db.close();
});

Given that the Atlas documentation contains the following example code for connecting to it from Node.js, I think that you do not have to enable SSL on Heroku:

var MongoClient = require('mongodb').MongoClient;

var uri = "mongodb://kay:myRealPassword@mycluster0-shard-00-00-wpeiv.mongodb.net:27017,mycluster0-shard-00-01-wpeiv.mongodb.net:27017,mycluster0-shard-00-02-wpeiv.mongodb.net:27017/admin?ssl=true&replicaSet=Mycluster0-shard-0&authSource=admin";
MongoClient.connect(uri, function(err, db) {
  db.close();
});

Niklas Wenzel
  • 888
  • 7
  • 6
  • 5
    Niklas, you were right! The problem was in the whitelist access. About the SSL question, I guess you're right, because I got the following reply from Herkou support: "(...) using SSL for the app is completely separate to the mongo connection so I don't think it would be an issue here." – amaralbf Feb 13 '17 at 12:17
  • 25
    **Update ([source](https://kb.heroku.com/i-need-to-whitelist-heroku-dynos-what-are-ip-address-ranges-in-use-at-heroku)):** as Heroku dynos use a subset of IP range of AWS EC2 instances, one can add the [AWS IP ranges](http://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html) to the Cloud Atlas' whitelist, or get an add-on to provide a static outbound IP address, or to use a secure communication via TLS. – amaralbf Feb 13 '17 at 13:47
  • 1
    Awesome! Thank you for reporting back, Bruno. :) – Niklas Wenzel Feb 13 '17 at 18:15
7

You can find all IP ranges for Heroku with this command:

HEROKU_REGION=eu; sudo apt -qqy install curl jq 2>/dev/null 1>/dev/null; heroku regions --json 2>/dev/null | jq ".[] | select(.name==\"$HEROKU_REGION\") | .provider.region" | (REGION=$(cat); curl -s https://ip-ranges.amazonaws.com/ip-ranges.json |  jq ".prefixes[] | select(.region==$REGION) | .ip_prefix")
ehpc
  • 1,034
  • 1
  • 9
  • 16
  • Amazing answer. If someone wants to do it manually since he doesn't have apt - find out what your heroku region is then go to https://ip-ranges.amazonaws.com/ip-ranges.json and find the ip range of that region – MatanCo Dec 01 '20 at 22:38
4

Also had to add 0.0.0.0/0 to the Mongo IP whitelist AND redeploy my app on Heroku for it to finally work (before changing IP, a CORS error was thrown).

Abi
  • 49
  • 1
  • 3
3

I solved this by installing an addon(i used Fixie Socks) for Static IP addresses for database requests and other TCP connections. More options here: https://elements.heroku.com/addons#network

magicgregz
  • 7,471
  • 3
  • 35
  • 27
  • 7
    Thanks for sharing, seems useful. Free tier is month 100 requests 100MB, sounds low, what counts as a "request"? – citynorman Dec 30 '18 at 17:39
  • 3
    Can you share some code on how you did this ? I'm trying to understand what I need to change in my node.js express code in order to use fixie socks and connect via mongoose. – matrix4use Apr 22 '20 at 22:00
  • Would also love to see this. I emailed Fixie Socks earlier today too. – shaunmwa Dec 28 '20 at 20:21
  • 1
    I looked into using Fixie Socks but it was only for the US region – AndyW Jan 11 '21 at 15:01
  • 1
    Fixie socks worked? I'm trying the exact same setup and it fails everytime. – GN. Feb 13 '21 at 03:51
3

very simple solution! just add to the white list IP in mongo atlas the adress "0.0.0.0/0"

it will open the mongo atlas to all the world..... so it os not for production but it helps for small tests

yehonatan yehezkel
  • 1,116
  • 18
  • 28
1

Since allowing access from anywhere is not secure and IP ranges could change, I ended up installing add-on QuotaGuard Static IP's (it provides 2 IP addresses for IP whitelist) so SOCKS5 Proxy can be used with QGTunnel.

QGTunnel should be downloaded and included in the codebase

curl https://s3.amazonaws.com/quotaguard/qgtunnel-latest.tar.gz | tar xz

Procfile should be updated

web: bin/qgtunnel npm start

Let’s say you want to access a replicated MongoDB cluster using QGTunnel with 3 replicas located on the hosts: rs01.mongodb.net:52115, rs02.mongodb.net:52115, and rs1.mongodb.net:52115. For this configuration, you will need to create 3 separate tunnels for each host on port 52115 in transparent mode. Once this is done, QGTunnel will alter the DNS resolution process to resolve these hostnames to the appropriate loopback address and auto-discovery for your replicated cluster should work as intended.

Željko Šević
  • 3,743
  • 2
  • 26
  • 23