Why is sudo required to start up a webserver on a given ip:port?

I'm setting up a Python-based webserver on my Debian box.

Setup:

  • The Debian OS is VM based, but I've switched the VirtualBox from NAT to Bridged.
  • IP of the VM setup = 192.168.1.7 (per my router's admin screen or ifconfig).
  • I've succesfully set up my router's port forwarding for both ssh and HTTP.
  • I've successfully set up my router's dynamic dns using dyndns.com.

Regardless of the specific Python webserver I'm using (Django, CherryPy, standard library), I have to start the webserver @ 192.168.1.7:80 using sudo. Otherwise I get an error about not having permission to access the port. None of the webserver tutorials mention needing to use sudo when specifying an ip:port.

Question: why do I need to use sudo to start these webservers? Is it an indication that I shouldn't be using 192.168.1.7? Or that I'm not setting a config file properly somewhere?


Only processes with root permissions can listen on privileged ports. This is a standard Unix security convention.


It is standard behavior that non-privileged users are not allowed to bind to privileged ports (port numbers below 1024). Therefore an application which would like to bind to port 80 for example will have to run privileged (usually this means to run as root) in order to bind to this port.

A common approach is to run a small "listener" process with privileged user which accepts the connection and then spawns a non-privileged process to handle the request. Dropping privileges for request processing is done for security reason. If somebody is able to exploit the process which handles the request, then usually it allows an intruder to execute commands using the same privileges as the processing process. Therefore it would be bad to handle the whole request using a privileged process.

However for many applications it's common nowadays to run as non-root; but such processes of course cannot bind to privileged ports then in standard configuration. So servers like Tomcat or JBoss used to bind to high-ports like 8080 instead so they don't need a privileged listener.

Of course if you expose such a process to the internet you would likely provide access on port 80 as each browser would first try to connect to port 80 when HTTP protocol is used. W common work-around to provide this is to use a firewall or port-translator in between the application and the public internet. So requests hit the firewall requesting port 80 but the firewall forwards the request to some internal host on port 8080. This way the real web-server can operate on high-ports while being publicly available on port 80.

- (internet request) ----> (port 80)[Firewall] ------> (port 8080)[Webserver]

Sometimes this redirect is simply done using iptables NAT rule:

iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080

This allows running an unprivileged application listening on port 8080 while all incoming requests for port 80 are just redirected to port 8080.

However using modern Linux kernels there is another possibility: Use capabilities.

setcap CAP_NET_BIND_SERVICE=+ep /some/webserver/binary

This would allow binary to bind to privileged ports even when started as from non-root user. See man capabilities for more details.