Why are web servers traditionally started as superuser?

Thinking about a future web server setup, it struck me that for some reason web servers usually start as root and then drop certain rights (setuid) for the worker processes. In addition there is often chroot involved, which isn't exactly meant as a security measure.

What I was wondering, why can web servers (I have administrated everything from Apache, lighttpd to nginx) not use the capability system (capabilities(7)), such as CAP_NET_BIND_SERVICE, on Linux and simply start as non-root user? ... this way still listening on a privileged port below 1024.

Or better, I think most of them could, but why isn't that common practice? Why not ...

• use setcap(8) with CAP_NET_BIND_SERVICE on the binary being run?
• set up the log folders to allow the (non-root) user to write there
• ..., if you felt like chroot helps at all, use chroot or lxc to "jail" the web server?

There is nothing other than (worker) child process may kill parent that I could come up with that would make this less beneficial than starting outright as root.

So why are they traditionally being started as root when afterwards everything is done to get rid of implied security issues that come with it?

• For what it's worth, IBM's WebSphere product can install either as a system-level service or a user application, and even in system mode can be configured to launch as a particular user and/or group ID. – keshlam Apr 13 '14 at 17:55
• I'm not sure why no answer is talking about SSL key here. If webserver needs server https (443) then it need to load SSL cert and key in memory. key file mostly stored with 600 permission so only root can read. Like in Ubuntu key file(s) stored in /etc/ssl/private/ dir. I'm writing a webserver (re-inventing a square wheel :-) that is why I come to this page. – Mera India Aug 16 '18 at 1:35
• @MeraIndia: even though the file mode may typically be 600, there's no reason why not a specific unprivileged user (e.g. nginx or www-data) should own said file. So that's not a good reason at all. And it was named before in an answer. – 0xC0000022L Aug 16 '18 at 8:15

Although POSIX has a standard for capabilities which I think includes CAP_NET_BIND_SERVICE, these are not required for conformance and may in some ways be incompatible with the implementation on, e.g., linux.

Since webservers like apache are not written for only one platform, using root privileges is the most portable method. I suppose it could do this specifically on linux and BSD (or wherever support is detected), but this would mean the behaviour would vary from platform to platform, etc.

It seems to me you could configure your system so that any web server could be used this way; there are some (perhaps clumsy) suggestions about this WRT apache here: NonRootPortBinding.

So why are they traditionally being started as root when afterwards everything is done to get rid of implied security issues that come with it?

They're started as root because they usually need to access a privileged port, and traditionally this was the only way to do it. The reason they downgrade afterward is because they do not need privileges subsequently, and to limit the damage potential introduced by the myriad of third party add-on software commonly used by the server.

This is not unreasonable, since the privileged activity is very limited, and by convention many other system daemons run root continuously, including other inet daemons (e.g., sshd).

Keep in mind that if the server were packaged so that it could be run as an unprivileged user with CAP_NET_BIND_SERVICE, this would allow any non-privileged user to start HTTP(S) service, which is perhaps a greater risk.

• Thanks, first of all. Alright, this explains it for non-Linux. However, given the package management systems, it would arguably be possible and almost trivial to support either. Also, I added linux specifically because my question referred to a Linux-specific facility. That is to say, your answer dodges the main point of my question (or maybe it really doesn't, but this is how it comes across) :) – 0xC0000022L Apr 13 '14 at 13:50
• @0xC0000022L This is going to change soon, and you can go ahead and start now. With unshare and nsenter in util-linux you can now use the net namespace as an unprivileged user. So you can assign a privileged port to a namespace as root, and start your web-server in the net namespace unprivileged. CAPs are a pain, anyway. – mikeserv Apr 13 '14 at 14:05
• "given the package management system" -> if you mean, by adding a feature on that level, no, it would be not be trivial (or sane). However, if you mean, simply configure the server by default to use capabilities instead, yes, I would think that could be done in many cases (I've added a comment about this WRT apache). the main point of my question -> If you mean, the bolded question at the bottom, I've added an explicit response to that. – goldilocks Apr 13 '14 at 14:07
• @mikeserv: would you mind putting that into an answer? Thanks :) – 0xC0000022L Apr 13 '14 at 14:08
• @0xC0000022L Yes, I would. I know it can be done, but I'm unfamiliar with the specific details of how to do this thing. So far I've only played with the pid namespace - and only this weekend. But you can see: lwn.net/Articles/531114 and unix.stackexchange.com/questions/124162/… – mikeserv Apr 13 '14 at 14:10

On Unix based systems, services listening on privileged ports require the blessing of the system administrator. This indicates that the service is being run by a trusted (at least by the administrator) user. Users of such services can then trust there is some administrative oversight of the server application. The value of this trust may not be as great as it was in previous decades.

Many web servers run on older operating system kernels which may not support the capabilities require to allow it to start and run as a non-privileged user. The kernel changes required are relatively new, and not standardized across operating system kernels. It is possible to conditionally compile the software for such environments. However, such changes could not be used in most platforms and may not well-tested or as secure as desired.

It is common for daemon processes to run as root to do everything that requires root access, and then switch to an unprivileged UID. This allows resources to be secured, while preventing the program from doing much damage once it is running. In the case of a web server SSL keys should be secured from being read by a rouge server application, but must be read to configure the SSL listener. Split privilege allow split-brained access to resources which can be used to significantly increase security.

While it possible to jail a web server, on many systems the jail could contain significant portions of the file system. This can be both difficult to configure and error prone. Jailing an application generally implies that it is a safer configuration. In this case, that trust may be misplaced due to the risk in that the jail is incorrectly configured. Even without a jail it can be difficult to diagnose access problems. Having large chunks of the file system excluded from the jail would make this more difficult.

There are several reasons to start a web server as root:

• to bind to port 80 (ports below 1024 are reserved to root, so that if a remote user is connecting to a service on a low port, they know that this service is approved by root);
• to set up confinement, e.g. chroot;
• to read and serve users' web pages, where applicable.

That least reason is a poor setup; the simplest way to secure such a setup is to require users to make web pages public. This doesn't work when users may want to have private web pages with access control (e.g. a university machine where professors want to share exam texts via the web but don't want to let students see them). In this case, a more sophisticated approach is needed (for example, require that web pages have an ACL that allows the web server to read them).

Web servers that are started as root often only start as root, but then drop privileges down to a dedicates user. Before dropping privileges, they bind port 80, possibly read some files (e.g. SSL private key file), and possibly perform other containment.

[Why not] use setcap(8) with CAP_NET_BIND_SERVICE on the binary being run?

That can be done, but requires a system that supports capabilities. Relative to the history of Unix, and even to web servers, this is relatively recent.

[Why not] set up the log folders to allow the (non-root) user to write there?

That is usually done; or else the web server process logs through a Unix or Internet socket to a logging daemon.

[Why not] if you felt like chroot helps at all, use chroot or lxc to "jail" the web server?

This means that the web server will be able to read all of its configuration files, such as SSL private keys. Sometimes vulnerabilities allow remote attackers to retrieve arbitrary files; confining the server in a way that prevents it from accessing configuration files avoids exposure in this case.

It is a weakness of most unix systems that they don't allow an unprivileged process to set up a confinement area that it won't be able to break out of. Under Linux, this is possible since the namespace improvements in kernel 3.8, which are not yet widely available.