32

I am trying to setup Nginx as a reverse proxy for accessing a MongoDB Database. By default Mongo listens to 27017 port. What I want to do, is redirect a hostname for example mongodb.mysite.com through nginx and pass it to mongodb server. In that way from the outside network I will have my known 27017 port closed, and access my db from a hidden url like the example I gave.

So I am trying to setup Nginx with this configuration :

server {
        listen 80;
        server_name mongo.mysite.com;
        gzip off;       

        location / {
            proxy_pass http://127.0.0.1:27017;
            proxy_redirect off;
            proxy_buffering off;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }

So after having this I try to connect with mongo shell from my cmd with the command mongo mongo.mysite.com:80 and I get back the following error:

2015-08-06T13:44:32.670+0300 I NETWORK  recv(): message len 1347703880 is invalid. Min 16 Max: 48000000
2015-08-06T13:44:32.670+0300 I NETWORK  DBClientCursor::init call() failed
2015-08-06T13:44:32.674+0300 E QUERY    Error: DBClientBase::findN: transport error: mongo.therminate.com:80 ns: admin.$cmd query: { whatsmyuri: 1 }
    at connect (src/mongo/shell/mongo.js:181:14)
    at (connect):1:6 at src/mongo/shell/mongo.js:181
exception: connect failed

Also in the Nginx access log I get this:

94.66.184.128 - - [06/Aug/2015:10:44:32 +0000] "<\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD4\x07\x00\x00\x00\x00\x00\x00admin.$cmd\x00\x00\x00\x00\x00\x01\x00\x00\x00\x15\x00\x00\x00\x10whatsmyuri\x00\x01\x00\x00\x00\x00" 400 172 "-" "-"

Has anyone got an idea, what is going wrong here? Thanks!

1
  • 2
    I voted to close this question because it is not a programming question. Similar future questions about managing your servers can be asked on Server Fault. Commented Feb 29, 2024 at 11:01

5 Answers 5

38

You're right, you need to use NGINX's stream module by adding a stream section to your .conf file:

stream {
    server {
        listen  <your incoming Mongo TCP port>;
        proxy_connect_timeout 1s;
        proxy_timeout 3s;
        proxy_pass    stream_mongo_backend;
    }

    upstream stream_mongo_backend {
      server <localhost:your local Mongo TCP port>;
  }
}
Sign up to request clarification or add additional context in comments.

4 Comments

can I configure it as mongo.example.co'? If so, how do I specify the address? I tried server_name` and it complains directive not allowed
@KhoPhi How did you manage to add the domain ?
@KhoPhi did you ever manage to get this restricted to a single domain? I can't find any documentation around doing that, but it must be possible.
@Chrift I don't remember getting that to work though. I think I gave up on that area. I went with the usual API approach through a backend to access the DB
31

Adding onto @Néstor's answer, this config should be written to /etc/nginx/nginx.conf just above http section, like this:

stream {
    server {
        listen  <your incoming Mongo TCP port>;
        proxy_connect_timeout 1s;
        proxy_timeout 3s;
        proxy_pass    stream_mongo_backend;
    }

    upstream stream_mongo_backend {
        server <localhost:your local Mongo TCP port>;
    }
}

http {
    ...
}

You should NEVER write it into a .conf file and put the file into /etc/nginx/sites-available folder. Because any config info in the /etc/nginx/sites-available folder belong to the http section.

10 Comments

Thank you very much for this, but how do I specify a server_name ? I have multiple dns records pointing to my nginx for different sites etc, and I would like to point the mongodb stream to a specific domain name.
@AdamD In my example, I set the server_name as localhost, your could change localhost to your domain.
@AdamD How did you manage to add the domain ?
Hi @Kingname, any of tried nginx proxy for mongodb replica set? I tried to add my servers but remotely i couldn't connect to replica-set but only to individual host.
Hi, after writing this, do I still have to write the route in /sites-available as well?
|
29

I left this behind, but after some work done, I had to face this problem again and the solution popped in my mind this time!

NGINX is basically an HTTP server, so by setting redirects and proxies the above way, it wraps all communication in HTTP protocol. So the error that is happening, is that while Mongo is expecting Raw TCP traffic, it is getting HTTP traffic.

So the solution to this is to use NGINX's new stream module that is used for handling raw TCP traffic and setup your upstream server to point to mongodb instance.

More Info : NGINX stream module

4 Comments

Hi @mitsos1os, could you be so gentle to put some code example of this? It would be great to see how you made it as the documentation doesn't talk about how to map the domain name to the server. Any help would be of great help :D
Hello @mitsos1os, would you be kind to elaborate your answer? I'm facing the exact same issue, but when I use the stream module I can't use the default port, I had to use the http interface to make it work, which is not ideal.
Hi @mitsos1os, How would you pass authentication parameters from Nginx to Mongo? Both in case of SCRAM and X.509?
@Viraj I am not 100% sure, but I believe that since you are directly passing the TCP connection from Nginx to Mongo, it will be able to handle any authentication mechanism you would like it to. Check the rest of the examples from Nestor and Kingname
4

I'd like to share one more tip. I just config nginx ssl support for mongodb. It should be more secure. You can see the configureation like below:

stream {
    server {
        listen  <your incoming port> ssl so_keepalive=on;
        ssl_certificate <your path to certificate>;
        ssl_certificate_key  <your path to private key>;
        proxy_connect_timeout 2s;
        proxy_pass stream_mongo_backend;
        proxy_timeout 10m;
    }

    upstream stream_mongo_backend {
         server 127.0.0.1:<your mongodb port>;
    }
}

I tested with python code to access mongodb with:

mng_client = pymongo.MongoClient('mongodb://<your username>:<your password>@<ipaddress or domain name>:<your incoming port as defined above>/?tls=true')

Comments

-3

If you connect to your local instance of mongodb via the usual default ip values it should connect:mongo 10.8.8.10

The issue is with resolving the address via the mongodb shell which is not happening.

2 Comments

I cannot really understand what you say. The address is resolved correctly, because in the nginx log I can see that it is recording the attempt to access the database so the hostname is resolved. Also if i open directly the 27017 port and try to connect using the hostname and skipping nginx, it works correctly. So it is not a matter of address resolving
Sorry if I wasn't clear. Two other things that come to my mind before I edit my post. [1] Can you restart mongod and reconnect to see if this issue is reproduceible [2] If you've already done step 1 then what does your mongod show....does it show the failed attempt that you've posted above...? edit: [3] tail -f /var/log/mongodb/mongodb.log should tell you more

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.