Popular Web servers
I posted1 a poll on mastodon:
What's your choice for an internet-facing web server, in 2024? Security over performance, ease (or lack) of configuration is a bonus; presence in Debian or Ubuntu preferred but anything I can build from source (so, probably not written in go) and has a good CVE story is of interest.
In the initial set I included Apache, nginx
, lighttpd
, caddy
,
and webfs
(based on them showing up in
popcon.) So far nginx
is in the lead
with caddy
and Apache surprisingly close to tied, but the
fascinating bit was the followups about servers that either I hadn't
heard of, or didn't realize qualified. (It got boosted early on by
Tim Bray and
Glyph which got it much broader
attention than I expected, which I believed really helped reach people
who provided some of the more unusual followups.)
Twisted Python
Twisted is actually packaged and has decades of usage - it just wasn't
tagged with the httpd
virtual package in debian so it didn't come up
in my original search. (It also doesn't currently include any config
to run by default, but really it would just be a basic .service
file
to invoke twisted web
with some arguments.) Glyph points
out
that twisted's TLS support is in C, but that parsing HTTP with C in
2024 is just asking for trouble.
Kestrel+YARP
Kestrel is the web server component of DotNet Core - this combination handles all of the app service front end traffic for Azure
YARP itself is a standalone MIT-licensed reverse proxy written in C# (nothing to do with Edgar Wright.)
Thanks to Blake Coverett for pointing this one out (they used it under Debian and Ubuntu in production!) but the DotNet ecosystem is pretty far outside my comfort zone/tech bubble.
OpenBSD httpd
OpenBSD ships a default http server with strong security and simple configuration. This does look solid and would be high on the list if I were running OpenBSD - there's some risk that it uses OpenBSD's advanced isolation features in ways that a naïve Linux port might not get right, but if I find an active one I'll look further.
There's an AsiaBSDCon 2015
paper which
describes the history of it replacing nginx
(which itself replaced
an Apache 1 fork) as the native OpenBSD web server; this includes a
long discussion of their attempts to harden nginx
that are worth a
look in terms of secure software development challenges.
haproxy
Marko
Karppinen
pointed out that haproxy
(which is packaged but doesn't Provides:
httpd
either) actually works directly as a web server - no direct
file support, but it can terminate HTTPS
connections and
pass the connections on to HTTP backends. (As of haproxy 2.8,
acme.sh can update a running
haproxy
directly, without disruptive restarts.)
Traefik
Gigantos pointed out that Traefik can also terminate HTTPS directly, and has builtin ACME (Let's Encrypt) support as well as being able to do service discovery instead of needing direct per-site configuration - depending on the shape of those providers that might not end up being less work but it's arguably putting the information in a more correct place.
NGINX Unit
PointlessOne suggested that for very dynamic backends, NGINX Unit was worth a look - it supports a huge variety of languages while still having attention on security and performance.
Apache with mod_md
Most of the comments on apache were about how "it still works" and had
decades of attention, but Marcus
Bointon
pointed out
mod_md
which adds ACME support directly as an Apache Module (shipped with
apache since 2.4.30, which predates Ubuntu 20.04, it's been around for
a while) defaulting to Let's Encrypt. (He goes on to complain about
the lack of HTTP/3 support, but from my perspective it's evidence that
Apache isn't standing still after all.)
Lighttpd
There was actually one vote against lighttpd from Chris Siebenmann as having stagnated too much to seriously consider for new deployments. (It does still get active development but I'm going for general impressions here and this one was interesting.)
h2o
FunkyBob chimed in near the end of the survey with h2o (in front of Django.) h2o turns out to be
- MIT licensed
- Written in C
- Responds reasonably to CVEs
- Used to do releases on github but now takes the interesting approach that ... each commit to master branch is considered stable and ready for general use ...
- Packaged in ubuntu and debian (also without
Provides: httpd
, but it's a 2018 version with a bunch of cherry-picked fixes the look like upstream, so I'm not sure how "actually" up-to-date that version is (late 2023 best-case though.) - Also available as a library, which is common in go projects but a lot more unusual in C servers.
I thought I'd never heard of it, but I'd starred it on github at some unknown point.
Conclusions
Primarily Confirmation
- There's more life in Apache than I'd realized (
mod_md
in particular) nginx
is still the mainstream choicecaddy
is definitely up-and-coming with an enthusiastic community
Actual final numbers: 491 people responded.
- 19% Apache
- 53%
nginx
- 2%
lighttpd
- 21% Caddy
- 0%
webfs
- 4% other/explain
Unexpected Highlights
Not going to do another survey on them, but I was pleased (and surprised) at the number of serious alternatives that turned up, including a few things that I knew about but didn't realize were legitimate answers to my question:
- Twisted Web (including
python3-txacme
) - Nginx UNIT
haproxy
- Traefik
- Kestrel+YARP (dotnet)
Personal Decisions
Part of the motivation for the survey was that I was stuck on an upgrade path for some old blogs and project sites. While that sounds low-value, it's also my playground for professional builds and recommendations, so I take it way more seriously than I probably should...
While the survey results didn't give me a final answer (nor were they intended to) they did reduce some fretting and lead me to a more direct plan:
- put a bounded amount of time into building
caddy
to my latest-from-source standards - prototype something with Twisted Web, particularly for the fast path "idea → domain registration → publication" projects, and see how it feels for more conventional use
- fall back to
nginx
if I don't get anywhere in a week.
What Actually Happened
Since I wanted to get at least one blog up and running quickly to publish this article, I took a shorter path:
- Installed blag which is probably the least-effort markdown blog to get going2
- Used my draft caddy-in-podman notes to do a quick nginx-in-podman, rootless
- Used
nftables
NAT support to forward 80/443 to the podman published ports.
That's just on my laptop but by the time you read this it'll be transplanted to a real server.
The key here is that the nginx-in-podman bit is just the server:
- it bind-mounts nginx.conf
- it bind-mounts a multiple-domain content directory
so content and operation are relatively separated, a new server can be
tested with the live content, and more importantly - if I succeed in
my caddy building efforts, I can drop in a caddy-in-podman container
and "effortlessly" swap from nginx to caddy without actually any real
sysadmin effort beyond a podman stop
/podman run
(which also leaves
me a quick path to rolling back to the working version.) Yes, this is
the whole promise of container-based modularity, but I needed to see
it scale down without a bunch of larger scale complexity.3