Skip to main content


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.

  • Apache (19%, 94 votes)
  • nginx (53%, 261 votes)
  • lighttpd (2%, 12 votes)
  • caddy (21%, 104 votes)
  • webfs (0%, 0 votes)
  • Anything else (explain (or name) in thread) (4%, 20 votes)
491 voters. Poll end: 3 months ago

I voted Apache because it's what we use at work (a university department) and it's very flexible; we can do pretty much anything we need to with it (and we know how to). For straightforward or lightweight stuff my impression is that nginx may be cleaner.

I used to really like lighttpd's core pitch and ran it some places, but my sad impression is that it's stagnated, especially in support for the latest TLS things, HTTP/2+, etc. At this point I wouldn't use it for new deployments.

@silverwizard neat: https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/httpd/ https://www.openbsdhandbook.com/services/webserver/basic_webserver/ and looks like it's getting some recent activity.
@Mark Eichin it's been my primary webserver for like a decade. It's got good security bones and easy to configure
@raggi I haven't tried that with caddy, mostly because I tried it with forgejo earlier and it blew up (apparently some code in the dependency graph was old enough that it didn't handle something module-related.) But caddy has a much simpler graph, so I should give that another chance, thanks. (If I understand it correctly it's still the opposite of the general debian go packaging strategy, but if it works it would still do what I need.)

@raggi yeah, npm and python have related issues; rust "plays nicely" with C in ways that probably reduce friction there but I haven't yet run into a reason to dig in enough to see if that's true.

There is a newish "gophian" go→deb auto-packager (like dh-make-golang but from a different angle) but it isn't quite automatic enough for this (I owe someone some bug reports on that of course)

I recently switched from nginx to caddy, and I couldn't be happier, and have no idea why I took so long. It's easier to configure for all common use cases, and automatic LetsEncrypt integration is killer.

@eichin@mastodon.mit.edu

frankenphp is looking great
@sirber
Thanks. (From my perspective, that counts as caddy...)

twisted, obvi

caddy would probably be my second choice, if I had to stick to this list; I don't love the fact that twisted's TLS support is in C, but why would I put a whole-ass C _HTTP_ parser on the internet in 2024?

Oh, huh, ubuntu's twisted package doesn't `Provides: httpd` so I didn't catch it on my "packaged things" pass. Interesting, thanks.
I would be interested in making it do this. I think we did, at one point? There were a series of init scripts and a debian/rules in our repo to try to facilitate it at one point, but this was in the start-stop-daemon era, I don’t know what the interface ‘httpd’ requires at this point

@glyph a little after-dinner poking didn't turn up anything in the package changelog - I did find https://twisted.org/documents/9.0.0/historic/twisted-debian.html and `tap2deb` rang some vague bells from a *long* time ago. (Surprisingly I didn't find any more of a virtual-package-name policy than references to virtual-package-names-list.yaml which has nothing more than

- name: httpd
description: a HTTP server

@glyph caddy was the source of the golang snark: ubuntu and debian are stuck on 2.6, building 2.8 which fixes a bunch of important things runs into the usual severe impedance mismatches between debian packaging and language packaging - I closed a timebox on working that out but if it gets wild acclamation then maybe I get to open it up again 🙂 🕓

@glyph So the problem isn't that you can't build it from source, it's that you can't build Debian source packages from the source and then use Debian tools to build those into a binary?

I've built Caddy from source many times, it's really easy. I run a custom build of it on Debian to host my web site and act as a WebDAV server.

it's more specific than that. I can rebuild the 2.6.2 packages from debian source, in a no-network sandbox, just fine. If I then upgrade that with the delta to 2.8.x, I end up having to upgrade a pile of other debian golang packages first, and get caught in a conflict of the defn of Enums between google/protobuf and cel-go's vendored google/protobuf. If I take a different path, I run into the antlr -> antlr/v4 changes (which I worked through) and some others I ran out of time on
@mathew this is a beautiful case study for my "The Linux Distribution: An Idea Whose Time Has Passed" draft
@mathew @glyph I'm using Caddy on Debian in containers. Should work rootless too.

@glyph Ah, I just cross-compile on a system with a network connection, then rsync the binary since Go binaries are statically linked.

Not sure why Hugo would need protobuf in the first place. I'm guessing it's being dragged in by some other dependency.

@mathew
It's not about "building somewhere else with a network connection" (it's a web server, clearly where I'm running it has net :-) It's about doing "hermetic" builds, where everything is already present (and recorded/traceable/reviewable) at build time, where it doesn't *need* net at all.

There's a lot of not knowing what deps a go project has - and ending up with hundreds of them. "Yay abstraction", but I'm in the "paranoia is a healthy part of this releng breakfast" camp instead.
@glyph

@mathew before I share a Hot Take™ here, I am curious about one of the details — is the Enum conflict between upstream google/protobuf and cel-go an issue because Debian has to decide on a single packaged version of these things?
@glyph
I don't actually know (the compiler errors only had paths, not versions, and I ran out of time figuring out why just deleting the vendored copy wasn't working [*that* was probably non-go-specific debian Quilt flailing though.])
@mathew

@mathew @glyph

For you, what is the "not knowing" part of Go app dependencies?

Is go.mod go.sum not enough to know the full list? Or do you mean more of what's in the dependency itself?

amazed that nobody has mentioned haproxy, it’s pretty great. Unless directly serving a folder of static files was the key use case.
@karppinen oh, I didn't realize it could actually do https termination directly https://www.haproxy.com/blog/haproxy-ssl-termination I assumed it would just be handing off the problem to the "real" server. (Throwing a `python3 -m http.server` behind it for the static files part is fine if the front end is robust enough.) Thanks!
traefik proxy, simple let's encrypt and lets me run one of my non-ssl enabled rust web server behind it.
@gigantos interesting, thanks! The "configuration by service discovery" bit sounds interesting https://doc.traefik.io/traefik/providers/overview/ and I'm going to have to dig into that a bit more...
httpd on #openbsd . easy, secure, light.
@andrethemac for reasons, I do need this to run on linux, and I suspect it (correctly) leans on openbsd's sophisticated security APIs - so I'd be concerned about a naïve port missing things like that. But I'll definitely dig into it further, thanks.

My default is nginx. It's robust, it's everywhere, it's well maintained, and I know it.

But depending on what you're trying to achieve other options might be better. Cadddy seems simpler if you need HTTPS with Let’s Encrypt and just reverse proxy, or static files served.

If you're something dynamic (e.g. Python/Ruby/PHP app) check out nginx unit.

I use nginx, have been dabbling with Caddy, but find it suffers from lacklustre docs. Apache is nice with mod_md for automatic certs, but it doesn't yet support HTTP/3

@Synchro ooh, I'd missed mod_md (or perhaps I saw it and assumed it was something silly with markdown handling :-)

Do you find you actually need HTTP/3 for anything? At first glance, it looks like it only has performance benefits in some extreme cases...

http/3 gives lower latency for everything, and somewhat improved security too, but it will not make any visible difference to those on fast connections. I’ve got a magazine article coming out on it soon, thinking about writing a book on it too!
As a newbie, caddy handles a lot of things on my behalf. I don't know if it scales well with traffic, but for my tiny website, it's wonderful.
I've also more recently been trying out h2o which I've found trivial to set up for my needs (as a front for django)
@FunkyBob First I've seen of it (hmm, actually I seem to have starred it on github and forgotten), https://h2o.examp1e.net/ MIT license, https://github.com/h2o/h2o/ and written in C. Seems to get and respond to CVEs, "... each commit to master branch is considered stable and ready for general use ..." which is an interesting choice. Thanks!