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: 4 months ago

in reply to Mark Eichin

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.

in reply to silverwizard

@silverwizard neat: cvsweb.openbsd.org/cgi-bin/cvs… openbsdhandbook.com/services/w… and looks like it's getting some recent activity.
in reply to Mark Eichin

@Mark Eichin it's been my primary webserver for like a decade. It's got good security bones and easy to configure
Unknown parent

Mark Eichin
@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.)
Unknown parent

Mark Eichin

@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)

in reply to Mark Eichin

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

in reply to Mark Eichin

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?

in reply to Glyph

Oh, huh, ubuntu's twisted package doesn't `Provides: httpd` so I didn't catch it on my "packaged things" pass. Interesting, thanks.
in reply to Mark Eichin

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
in reply to Glyph

@glyph a little after-dinner poking didn't turn up anything in the package changelog - I did find twisted.org/documents/9.0.0/hi… 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

in reply to Glyph

@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 🙂 🕓
in reply to Mark Eichin

@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.

in reply to mathew

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
in reply to Mark Eichin

@mathew this is a beautiful case study for my "The Linux Distribution: An Idea Whose Time Has Passed" draft
in reply to Mark Eichin

@mathew @glyph I'm using Caddy on Debian in containers. Should work rootless too.
in reply to Mark Eichin

@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.

in reply to mathew

@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

in reply to Mark Eichin

@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?
in reply to Glyph

@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
in reply to Mark Eichin

@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?

in reply to Mark Eichin

amazed that nobody has mentioned haproxy, it’s pretty great. Unless directly serving a folder of static files was the key use case.
in reply to Marko Karppinen

@karppinen oh, I didn't realize it could actually do https termination directly haproxy.com/blog/haproxy-ssl-t… 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!
in reply to Mark Eichin

traefik proxy, simple let's encrypt and lets me run one of my non-ssl enabled rust web server behind it.
in reply to gigantos

@gigantos interesting, thanks! The "configuration by service discovery" bit sounds interesting doc.traefik.io/traefik/provide… and I'm going to have to dig into that a bit more...
in reply to andrethemac

@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.
in reply to Mark Eichin

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.

in reply to Mark Eichin

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
in reply to Marcus Bointon

@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...

in reply to Mark Eichin

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!
in reply to Mark Eichin

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.
in reply to Mark Eichin

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)
in reply to Funky Bob

@FunkyBob First I've seen of it (hmm, actually I seem to have starred it on github and forgotten), h2o.examp1e.net/ MIT license, 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!