It'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.
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.
The 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.)
If 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.
Friendly 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.
Friendly 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)
What was the purpose of that arbitrary limitation again? It's mostly a holdover from the olden days we now have to constantly work around (by mostly having lazy people run things as root everywhere).
setcap solves the problem in the wrong way in this scenario imho: With setcap, any user could run node with a node script using ports < 1024.
What would be more useful is the ability to allow a _user_ to open a privileged port. In my option mappu's answer is the right way to go, i.e. using authbind to allow a certain user to open a port or a range of ports.
(Hmm, did parent just edit his comment ? He didn't mention authbind when I hit reply, did he ?)
From the man page:
authbind allows a program which does not or should not run as root to bind to low-numbered ports in a controlled way.
The shared library loaded using LD_PRELOAD overrides the bind(2) system call. When a program invoked via authbind calls bind to bind a socket to a low-numbered TCP/IP port, and if the program doesn't already have an effective uid of 0, the version of bind supposed by authbind forks and executes a setuid-root helper program.
You can create configuration file like /etc/authbind/byport/port and use standard linux file permissions to allow certain non-root users to bind to ports < 1024
If you are on Solaris (10 or higher works from experience) you can grant a single user the ability to bind to the lower ports:
usermod -K defaultpriv=basic,net_privaddr ${user}
You can off course also assign the privileges to a role, and then assign the user that role so as required they can su to the role and use the privileges.
Actually, 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.
Alternatively, 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
I wrote a similar article a few weeks ago (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.
39 comments
[ 3.0 ms ] story [ 92.5 ms ] threadYou 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.
[1] http://haproxy.1wt.eu
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.
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)
1. Don't use connection tracking
2. If you need to use it, make judicious use of -j NOTRACK
I use this on a few high traffic servers, with good results:
What would be more useful is the ability to allow a _user_ to open a privileged port. In my option mappu's answer is the right way to go, i.e. using authbind to allow a certain user to open a port or a range of ports.
The answer you are looking for in Solaris...
This limits it both on the basis of which user can open ports and which programs can.
(Hmm, did parent just edit his comment ? He didn't mention authbind when I hit reply, did he ?)
From the man page: authbind allows a program which does not or should not run as root to bind to low-numbered ports in a controlled way. The shared library loaded using LD_PRELOAD overrides the bind(2) system call. When a program invoked via authbind calls bind to bind a socket to a low-numbered TCP/IP port, and if the program doesn't already have an effective uid of 0, the version of bind supposed by authbind forks and executes a setuid-root helper program.
You can create configuration file like /etc/authbind/byport/port and use standard linux file permissions to allow certain non-root users to bind to ports < 1024
Here is a pretty neat description of what is possible and why it is pretty awesome: http://www.c0t0d0s0.org/archives/4075-Less-known-Solaris-fea...
---
On FreeBSD if you have the MAC framework enabled, you can use the portacl module to give new privileges:
See http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ma... for more information."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.
http://en.wikipedia.org/wiki/Authbind
Assuming a tcpserver-like program called tcplisten, this would look like
FastCGI works similarly. Multiple workers can run underneath, calling accept(2) on stdin.A simple implementation of tcplisten:
https://gist.github.com/4211098