What upsets me about Nginx the most is that it takes the fail-fast approach, which isn't entirely suitable for combining it with a container workflow, at least in situations where you're running it without something like Kubernetes (which has its own customizations).

For example, currently i run my own Nginx ingress with Docker Swarm:

service A / B / C <--> Nginx <--> browser

The reverse proxy configuration feels easier to do than that of Apache2/httpd, for example:

server {
listen 80;
server_name app.test.my-company.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name app.test.my-company.com;

# Configuration for SSL/TLS certificates
ssl_certificate /app/certs/test.my-company.com.crt;
ssl_certificate_key /app/certs/test.my-company.com.key;

# Proxy headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# Reverse proxy
location / {
resolver 127.0.0.11 valid=30s; # Docker DNS
proxy_pass http://my-app:8080/;
proxy_redirect default;
}

}

However, suppose that the "my-app" container has a health check set up for it. What does that mean? Docker Swarm won't route any traffic to it until it's finished initialization. Except that it also means that DNS requests won't return anything for "my-app" until at least one healthcheck passes. That in of itself shouldn't be too problematic, right? Any web server surely would just log that one request as an error and return an error until eventually everything would work.

Wrong. Nginx does throw the error and the request fails, but the ENTIRE web server goes down:

nginx: [emerg] host not found in upstream "my-app"

What does that mean? If you have 1 Nginx instance on the server that needs to proxy 10 apps in total, one app not being available will prevent the other 9 from working! Whoever thought that such defaults would be okay has reasoning that is beyond me, especially considering that the Caddy web server does something similar and will go down if 1 out of 10 sites fails to provision the SSL/TLS certificate, instead of letting the others work - completely opposite of what someone who cares about resiliency would want!

But fear not, supposedly there's a solution!

# Reverse proxy
location / {
resolver 127.0.0.11 valid=30s; # Docker DNS
set $proxy_server my-app;
proxy_pass http://$proxy_server:8080/;
proxy_redirect default;
}

Except that, you know, that also doesn't work:

nginx: [emerg] "proxy_redirect default" cannot be used with "proxy_pass" directive with variables

Now, that's not an issue in my case, since i just jotted down the "proxy_redirect default;" value to remember what it does, but it's unfortunate to hear that it is neither ignored (since it's the default value which is functionally identical to it not being there), nor could other values be used: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#pro...

In summary, it's nice that there are workaround for problems like that, but it's a bit odd that the web server is otherwise so quick to fall over and die, as well as the fact that the defaults aren't oriented towards maximum reliability and resilience. That said, i still do like Nginx and actually wrote about how to use it as a reverse proxy on my blog a while back: https://blog.kronis.dev/tutorials/how-to-use-nginx-to-proxy-...

But at the same time, in situations where load isn't high enough for the web server to be the bottleneck, it's also helpful to evaluate the alternatives, notably: Apache2/httpd, Caddy and Traefik. It was actually pretty recently that Apache2/httpd got mod_md, which allows provisioning Let's Encrypt certificates out of the box, which is certainly promising: https://httpd.apache.org/docs/trunk/mod/mod_md.html