6 ms·
Drop Root Privileges in Node.js after Binding to Port 80
- wonnage 14y agoIt's probably a better idea to just run nginx on port 80 and proxy requests through in any sort of real environment. And if you're not in production...well, it doesn't really matter which port you choose anyway.
- trebor 14y agoVery true. This will also let you run multiple instances of node and do load balancing.
- parasight 14y agoPlease excuse my ignorance, but why would I want to run nginx to proxy requests through?
- onewland 14y ago[This response is a guess, and very generalized] You probably won't handle every HTTP edge case as well as nginx defaults, and you don't really need the control at that level to implement a functional, high performance web app.
- javis 14y agoPossibly because Nginx serves static content much faster than Node.
- cparedes 14y agoThe reasons that other folks have mentioned (static files, nginx is built for lots of HTTP requests), as well as basic load balancing between several 'worker processes'. Sometimes you'll want to have several app server processes running with several ports open, and have nginx load balance between all of those processes (then load balance again at a higher tier between all of the different nginx processes.)
- Wintamute 14y agoIf you're running a few services and sites on the same box you need some sort of proxy listening on port 80 reverse proxying incoming requests to the correct internal port. i.e. an incoming request looking for "www.mynodeapi.com" could be internally routed to "127.0.0.1:8080" (or wherever your node app is listening). The proxy could be nginx, haproxy or perhaps even a node app using node-http-proxy. AFAIK, if you need proper web sockets support your proxy has to be node based or haproxy.
- m0th87 14y agoUnless you want websocket support. Then it gets a little more complicated: http://stackoverflow.com/questions/10329281/nginx-1-2-0-socket-io-http-1-1-proxy-websocket-connections http://stackoverflow.com/questions/10329281/nginx-1-2-0-sock...
- jeromeparadis 14y agoHAProxy works Wellington for node.js websocket apps.
- Pewpewarrows 14y agoAfaik, Disqus uses websockets with Nginx fine. I believe they recently mentioned writing and using this module: https://github.com/wandenberg/nginx-push-stream-module https://github.com/wandenberg/nginx-push-stream-module
- jaytaylor 14y agoOr better yet, use HAProxy [1] instead of nginx. [1] http://haproxy.1wt.eu http://haproxy.1wt.eu
- ejdyksen 14y agoAlternatively, you could grant the node binary the ability bind ports < 1024, using setcap (Linux only): sudo setcap 'cap_net_bind_service=+ep' /path/to/nodejs Then you don't have to ever run it as root (at least not for the purpose of binding to the right port).
- hahainternet 14y agoEndless bonus points to you for mentioning capabilities. They're so unknown but gems to come across.
- typpo 14y agoOr route port 80 to your node port (eg. 8080): sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
- seiji 14y agoFriendly reminder: iptables has a significant performance penalty on high traffic servers. If your service gets a few thousand hits per day, it'll be okay. If you're trying to survive a few thousand hits per second, your clients will suffer less than optimal throughput.
- toong 14y agoFriendly reminder @ seiji: don't make those kind of statements without backing these, please ? In what use case would iptables give a performance penalty ? I have iptable-setups running with hundreds of rules and 800-1000 concurrent(!) users. During traffic peaks times my 5-6(?) year old Xeon does a good job, cpu usage barely touches 3-4%. Throughput downstream at that point around 350Mbit/s (admitted, downstream just matched by conntrack:matched/established) and upstream around 20Mbit/s, working through hundreds of rules. iptables runs in the kernel-space and is very, very, VERY performant. (well, I lied, iptables itself is just a configuration tool for the kernel - but it is incredibly fast). Following that kind of traffic with tcpdump (userland) just drops about half of the packets because it maxes out that poor CPU instantly. (yes, that depends on the args). And don't even thinkg about using iptraf :-) (That reminds me: please, some one, send me better server hardware :-x)
- Hello71 14y agoNot a good idea to hardcode the name of the "owner". Standard practice is to setuid/gid to 65535 (nobody).
- zorked 14y agoActually, even in the classical Unix security model, setuid'ing to nobody is considered a bad idea. Because so many services do it, giving an attacker an opportunity to become nobody will likely grant him access to those other services as well.
- Hello71 14y agoPoint taken. Allow me to revise my statement. "In production, one should create a specialized user to run any service." And if you have lots of money to waste, stick 'em all in separate VMs too.
- darklajid 14y agoLooking at the snippet of code: Isn't that sample (probably) confusing group and user? process.setgid('tlhunter'); process.setuid('users'); I'd expect that 'users' is the group here and 'tlhunter' the user 'thomas l. hunter'?
- renownedmedia 14y agoYep; A typo I made when converting variables to strings for the example.
- jeremiep 14y agoYou could also create a unix socket and have node.js bind on it.
- mappu 14y agoAnother technique is to launch the service via authbind, in your repositories. It's especially useful if you aren't able to recompile the target. http://en.wikipedia.org/wiki/Authbind http://en.wikipedia.org/wiki/Authbind
- sigil 14y agoAlternatively, if you don't trust a large program with dropping root, you can factor out the binding and listening into a separate program. Then accepting and everything beyond can be done with normal privileges. Assuming a tcpserver-like program called tcplisten, this would look like sudo tcplisten 0.0.0.0 80 setuidgid nobody \ program-that-accepts-on-stdin FastCGI works similarly. Multiple workers can run underneath, calling accept(2) on stdin. A simple implementation of tcplisten: https://gist.github.com/4211098 https://gist.github.com/4211098
- olalonde 14y agoI wrote a similar article a few weeks ago (http://syskall.com/dont-run-node-dot-js-as-root/ http://syskall.com/dont-run-node-dot-js-as-root/) but have since then realized that changing the process' UID brings a lot of unexpected problems and a much simpler solution is to use a higher port and proxy via nginx. For example, if you initialize a logger before starting your HTTP server and changing the process UID, you will might create root owned files and eventually run into permission conflicts.