Nginx and HAProxy both work as the edge reverse proxy when TLS ownership and upstream health checks are explicit: terminate certificates on one layer only, forward Host and X-Forwarded-Proto so apps mint correct absolute URLs, and keep the proxy on the public listeners while backends stay on a private network the edge alone can dial. For Nginx, prefer explicit server/location blocks over a catch-all proxy_pass when static and API share a Host; for HAProxy, bind frontends with clear ACLs and mark backends down on failed checks instead of silently hashing to a dead peer. Timeouts, maxconn, and buffer sizes should match the slowest legitimate upstream, not defaults copied from a tutorial.
Ops prove-out after a config reload: nginx -t / haproxy -c must succeed, then curl the public Host twice and confirm upstream status plus that the served certificate SAN matches the name clients dial. If you see intermittent 502/504, compare active backend counts and queue depth before blaming the app — a single drained peer or a health check against the wrong port looks like flaky routing. Prefer sticky or consistent-hash only when sessions demand it; otherwise round-robin plus honest health checks keeps failovers boring and measurable.