Some good answers in here already. It boils down to a couple points for me:
Back when I started selfhosting, it was either nginx or apache, and I found nginx better and easier to set up
All the nginx knowledge I learned years ago still works just the same as it did back then, so why potentially mess things up by switching if it all still works
Basically every project has an example nginx config for reference, that can't be said about other proxies
It is easier to find support online for edge cases that might pop up with nginx due to the ubiquity of its use and years of history
And also because for me it started from web hosting where Apache and Nginx dominate and later because of many easy to understand example configs from the net including many "docker letsencrypt" examples.
It just works and it's in every distros default repo, it's pretty easy to set up and can be a webserver for static files, PHP sites, etc.. It can be a reverse proxy for HTTP(s) traffic or just forward TCP/UDP.
There's also endless documentation out there for how to do something in nginx.
HAProxy is a nightmare to use in my experience. It just feels so clunky and old.
Caddy is nice, but downloading and updating it is a pain because you need modules that aren't included in the repo version.
HAproxy cannot serve static files directly. You need a webserver behind it for that.
Apache is slow.
Nginx is both a capable, fast reverse-proxy, and a capable, fast webserver. It can do everything HAproxy does, and what Apache does, and more.
I am not saying it is absolutely best for every use-case, but this flexibility is a large part of why I use it in my infra (nad have been using it for a decade).
NGINX can really do a lot of things out of the box while being pretty easy to configure. NGINX can serve static files, it can proxy emails, it can do FastCGI, it can do UWSGI, it can do HTTP proxying, you can run Lua code inside NGINX to do things, there's a module for RTMP live streaming. You can also implement some stuff like external authentication to protect your services/authenticate them at the proxy level. It can also do caching. Not all that useful with all those Rust and Go apps with their own built-in web server but if you run large legacy apps at scale it's great, you can offload a lot of stuff away from your slow ass PHP app.
Caddy's simpler but the current battle tested popular option is NGINX.
HAproxy is good at what it does but it's only good at proxying and simple rules. For the most part, it's used as a load balancer and router and doesn't really process the requests itself. It can alter some things in it but it's limited, and it only does HTTP and TCP. So you can't really run PHP or Python or Ruby or whatever applications directly behind HAproxy. That makes NGINX a better choice there because NGINX deals with HTTP and only passes the request details to the application which doesn't have to do HTTP on its own. I usually see HAproxy load balancing to NGINX hosts with some PHP/Python/Ruby app behind them.
Apache is old. It's gotten better but the way it works just doesn't reflect most modern use cases. I remember when NGINX popped off like 15 years ago and just how much more resource efficient it was and how happy I was with the upgrade. So it exists and still works but not very popular anymore. It's a bit easier to set up but also a bit weird with things like mod_php which runs directly inside Apache instead of a dedicated user that can be better sandboxed.
Traefik is getting traction in big part because it fits well with the Docker ecosystem and just sets itself up automatically.
There's also Envoy if you want some serious proxying and meshing but setting that one up is truely headache inducing.
They're all pretty good web servers regardless, it comes down to preference. There's no right choice because everyone's needs are different.
It's easy to use, reliable, and doubles as a webserver so I only need one software to host my websites and also do the reverse proxying to the other webservices.
Good question. I chose it initially because it was open source and way easier (in my eyes) than Apache. I don't recall the others being an option at the time, or I was not aware of them. nginx does what I need without complaint, so I haven't switched.
I have run it in so many different scenarios, both professionally and personally, its crazy. Nginx has never failed me, literally. My homeserver is quite limited but nginx has a very small footprint, it performs beautifully well and it satisfies all my hosting, proxying, redirecting and streaming needs.
It works for modern and legacy applications, custom code, webhosting, supports all the modern features and its configuration is very easy with literal thousandsof examples available online.
Apache probably can do all that but I hate how unintuitive its configuration is to me personally. HAproxy cant do half the stuff nginx does.
As for caddy Ive heard of it but never really used it. What does it offer that nginx doesnt?
When NGINX showed up it beat the then dominant apache on resource utilzation hands-down.
It's also very configurable and has a lot of modules, both in-house and third party.
The only downside for me: as of late the whole commercial part of the project has been gobbling up everything to shove the non-free version to the point where it's hard to find info on the free version, e.g., the wiki page that lists all the third-party modules. The nginxtutorials site seems to be a good resource.
Dounin writes in his announcement that "new non-technical management" at F5 "recently decided that they know better how to run open source projects. In particular, they decided to interfere with security policy nginx uses for years, ignoring both the policy and developers' position." While it was "quite understandable," given their ownership, Dounin wrote that it means he was "no longer able to control which changes are made in nginx," hence his departure and fork.
Also, fun fact: this is probably the only instance of russian software muricans don't cry Commie! all the time (maybe because the parent company was acquired).
I think a large factor is because so many people use it. A lot of people come to self hosting without much knowledge and just copy configs etc. from a Tutorial. Those tutorials will 90% of the time use Apache or nginx. I remember back when I set up my first servers I mostly followed instructions and copied configs. Years later I understood I had set up Apache with virtual hosts and what that means/how it works but it might as well just have been nginx.
As for why so many people use these two I think it also has to do with "adoption" in another way. Back before nginx Apache was the standard everything else was "different". Then nginx appeared to solve the Problems of Apache and then there were 2 ... These days you can probably do anything you want/need with the 2 servers so no reason to use anything else.
Professionaly I usually use either HAProxy and Apache or Nginx (or sometimes HAProxy and Nginx) but if there are special requirements that might change.
Caddy is good but it tried to do to much. This means that security bugs could be way more common. It has been audited by outside people and the issues they found were fixed but I am will very doubtful that it is secure yet
nginx is mature and has a lot of support online. A lot of server projects assume you're using nginx, as well. I've only ever seen caddy instructions on newer projects and even then, they usually also have nginx instructions.
nginx has more features and flexibility than haproxy, such as being a web server. If I wanted just a pure proxy, I'd use haproxy. Apache is primarily a web server, and a pain to configure.
Personally I use Traefik. Add it to docker-compose, set up LE certs, add a few lines to each container, and it Just Works. No extra config on Traefik itself.
Why not? Why should I use Apache instead of Nginx? I don't know about Caddy, Nginx is simple enough not to care about simpler solutions. But in general, I know Nginx and it does the job.
Nginx handles more connections than Apache, given the same resources. HAProxy does not have web server functionality like the former two, so Nginx is the natural upgrade from Apache. Caddy is relatively new, I'm not sure how it compares other than being easier to set up.
Because I have it in use as my main webserver, sure I could put that behind haproxy too but why?
I like to keep my server setup small and easy, without unnecessary duplications.
Nginx can everything that haproxy can, and more.
I'll probably look into newer fancier options such as Caddy one day, but as far as I remember Nginx has never failed me : it's stable, battle tested, and extremely mature. I can't remember a single time when I've been affected by a breaking change (I could not even find one by searching changelogs) and the feature set makes it very versatile. Newer alternatives seem really interesting, but it seems to me they have quite frequent breaking changes and are not as feature rich.
That being said, I'd love to see side-by-side comparison of Nginx and Caddy configs (if anyone wants to translate to Caddy the Nginx caching proxy for OSM I shared earlier this week, that would make a good and useful example), as well as examples of features missing from Nginx. This may give me enough motivation to actually try Caddy :)
NGINX is a bit more hands on than some other options but it's mature, configurable and there's a huge amount of information out there for setting it up for various use cases.
in my case, its what I set up when i was first getting into this and it works, so I don't want to go through setting up anything else.
TLDR: probably a lot of people continue using the thing that they know if it just works as long as it works well enough not to be a bother.
Many many years ago when I learned, I think the only ones I found were Apache and IIS. I had a Mac at the time which came pre installed with Apache2, so I learned Apache2 and got okay at it. While by release dates Nginx and HAProxy most definitely existed, I don't think I came across either in my research. I don't have any notes from the time because I didn't take any because I was in high school.
When I started Linux things, I kept using Apache for a while because I knew it. Found Nginx, learned it in a snap because the config is more natural language and hierarchical than Apache's XMLish monstrosity. Then for the next decade I kept using Nginx whenever I needed a webserver fast because I knew it would work with minimal tinkering.
Now, as of a few years ago, I knew that haproxy, caddy, and traefik all existed. I even tried out Caddy on my homelab reverse proxy server (which has about a dozen applications routed through it), and the first few sites were easy - just let the auto-LetsEncrypt do its job - but once I got to the sites that needed manual TLS (I have both an internal CA and utilize Cloudflare' origin HTTPS cert), and other special config, Caddy started becoming as cumbersome as my Nginx conf.d directory. At the time, I also didn't have a way to get software updates easily on my then-CentOS 7 server, so Caddy was okay-enough, but it was back to Nginx with me because it was comparatively easier to manage.
HAProxy is something I've added to my repertoire more recently. It took me quite a while and lots of trial and error to figure out the config syntax which is quite different from anything I'd used before (except maybe kinda like Squid, which I had learned not a year prior...), but once it clicked, it clicked. Now I have an internal high availability (+keepalived) load balancer than can handle so many backend servers and do wildcard TLS termination and validate backend TLS certs. I even got LDAP and LDAPS load balancing to AD working on that for services like Gitea that don't behave well when there's more than one LDAPS backend server.
So, at some point I'll get around to converting that everything reverse proxy to HAProxy. But I'll probably need to deploy another VM or two because the existing one also has a static web server and I've been meaning to break up that server's roles anyways (long ago, it was my everything server before I used VMs).
I was coming from Lighttpd which at the time had a very similar config syntax to Nginx. It was pretty much a no brainer, considering I wanted to shift to an automated Letsencrypt renewal process at the same time.
Sadly I wrote some python web services for CGI (not django/flask) that cannot be run anymore, since NGINX only supports FCGI, rather than just CGI as far as I can tell
Me personally, as a newb regarding proxy and homelab, I use nginx because it was super easy to set up (proxmox script) there were many tutorials available and it just works great. I had to debug some things and this also worked great, so just a perfect package.
There's a lot of good resources for Nginx, it's fast (faster than Caddy), and has a ton of features, so you can use it for pretty much anything HAProxy, Apache, or Caddy can do, and not sacrifice much in performance.
That said, I mostly use HAProxy and Caddy. Here's my basic setup:
HAProxy at the edge VPS - routes requests to machines based on SNI
WireGuard VPN - connects my internal devices to my VPS
Caddy in Docker - runs on internal network on my NAS/homelab - manages LetsEncrypt renewals and reverse proxies to internal Docker network
Nginx in Docker - FE for NextCloud; this simplifies things so all my TLS is handled in one place, and Caddy doesn't need to touch files
I use a local DNS server on my router so my domains can route directly to Caddy instead of going over the internet when on my network, otherwise I may just have HAProxy handle LetsEncrypt certificates.
From what I can tell, Nginx is a little more efficient than Caddy, but Caddy is plenty fast for my needs. I'm considering switching from NextCloud to the new ownCloud Infinite Scale, and if I do, I'd ditch nginx completely.
I learned nginx when I was hosting websites. I had it set up and running when it was time to add reverse proxies into my setup. It didn't take much more from the virtual hosts I was already using.
Now, I don't host many individual sites anymore and haproxy has a plugin on my firewall for the handful of services I run now.
I use Traefik because it solved a problem with the static configuration approach which Nginx had / still has.
In a scenario with multiple services behind Nginx, taking one down or replacing an instance is massive headache. I tried to script around it, but basically the Nginx container would choke on the fact that a service does not [yet / anymore] exist, and together with the docker networking stack it turned out to be an insurmountable problem.
Traefik otoh discovers services based on (in my case) labels on the docker containers running locally. And then updates the configuration on the fly.
Basically the static approach to configuration resulted in massive headache when I needed to enable zero downtime deployments and updates behind Nginx. And Traefik handled it perfectly without dropping a single request.
Nowadays I manage my dynamic configuration with ansible and update the values in for the file-based configuration provider with a playbook. I don't need a UI to manage my inventory, I use ansible for that. Traefik handles the rest perfectly.
@Findmysec
Contrary to most, I never made the Apache-to-nginx switch. I actually don't find nginx that much easier to configure, so the effort of rewriting all my templates was too high.
Caddy is a different story. I can replace swathes of configuration lines with just two? And get letsencrypt automatically without having to give it a single thought? Gimme!
I use nginx & docker-proxy. Because the model I copied used that setup. Having messed with it a bit, I’m understanding it more and more. Before that, the last time I messed with a web server (Apache), nginx wasn’t around. Lately, I’ve seen a similar docker setup to mine that doesn’t use docker-proxy. If I find time, I’ll probably play with that some on my dev rig.
I'm reminded of this blog/article on Ars about ripping out OLS and reverting to NGINX. There's some good info there, and also links to other of his posts on the subject and references. Good read.
The only reason that I tend to use it is because of the included webserver. It's not bad but the paywalling of functionality needed for it to be a proper LB left a bad taste in my mouth. That and HAProxy blows out of the water in all tests that I've done over the years where availability is at all a concern. HAProxy also is much more useful when routing TCP.