Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nodejs app accessible on port 3000 behind nginx reverse proxy

I am running a nodejs application with nodejs app an server listening on port 3000. I use nginx as a reverse proxy which also handles ssl. the configuration is listed below (and it seems to me after reading several tutorials and forum posts it is pretty standard). Everything works as expected except from the fact that i am still able to accesss the app under "http://example.com:3000". Does that mean i need to add another server listening on port 3000 for redirects to https? This could either mean that the tutorials i read so far are somewhat incomplete or I am overlooking something fundamental. Can anyone help me figure out what it is?

 # app server upstream

upstream app {
    server 127.0.0.1:3000;
}

# default http server. Redirect to https server

server {
    listen 80;
    server_name www.example.com example.com;
    return 301 https://example.com$request_uri;  
}

# https server

server {
    listen 443;
    server_name www.example.com example.com;

    ssl on;
    ssl_certificate ssl.crt;
    ssl_certificate_key ssl.key;

    ssl_session_timeout 5m;

    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://app;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;   
    }
}   
like image 551
Macs Avatar asked Feb 18 '16 11:02

Macs


2 Answers

If you can reach the port 3000 from the outside of the computer this means that you program your Node.js application in a way that the HTTP server is listening on all interfaces. This is not bad per se and by default you should program your applications in this way, because you can't anticipate future changes of the final deployment topology. Leave the responsibility of hiding the port from outside world to the firewall (iptables comes to mind here) as suggested by Oxi.

This way you don't need to change your code on the future to adapt it to a different deployment topology.

I for example has a similar case. I use Haproxy as load balancer and for SSL termination. But in my case Haproxy instance run on a different host for performance considerations. If in the development stage i have restricted my application to listen just for local connections then i will have to update my code once on development just to adapt to the new topology.

I hope this helps you.

like image 179
yeiniel Avatar answered Oct 26 '22 17:10

yeiniel


Configuring Nginx to bind to the port Node is running on will throw an error:

$ nginx: [emerg] bind() to 0.0.0.0:3000 failed (98: Address already in use)

This is because multiple services can't bind the same port. Which one is responsible for handling that request?

You can instead bind your node script to listen to a specific IP address. If you bind your node script to the local interface IP (127.0.0.1) instead of all IP's you can effectively prevent Node from accepting external connections on the Node port (eg. 3000).

You're probably doing something like this already,

const server = app.listen(port)

Try this instead

const server = app.listen(port, '127.0.0.1')

I am using this solution with Nginx running as a proxy on port 443. Nginx can still connect to the Node service while preventing it from accepting connections from external requests; effectively blocking requests at http://example.com:3000

You could also solved this with iptables.

With iptables you have two approaches; block everything and then open the internal interface only. You can also redirect requests, eg. from 3000 to 443 (or 80) which is an interesting idea.

I haven't tested these personally, so consider them theoretical examples. Perhaps someone has a proven example?

iptables -A INPUT -p tcp --dport 3000 -j DROP
iptables -A INPUT -s 127.0.0.1 -p tcp --dport 3000 -j ACCEPT

OR

iptables -A OUTPUT -o lo -p tcp -m tcp --dport 3000 -j REDIRECT --to-ports 443
like image 34
Strixy Avatar answered Oct 26 '22 17:10

Strixy