# Managed by vpsmgr — installed file, do not edit by hand. # Changes are overwritten on the next install. # # This is the STATIC entry configuration: it is installed once by # scripts/30-haproxy.sh and never rewritten by the panel. The unit loads it # FIRST and the generation in service SECOND: # # /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg \ # -f /etc/haproxy/current/domains.cfg # # Layout of the published side (all written by the panel, atomically): # # current -> releases// the generation in service # domains.cfg one backend per domain # maps/http.map Host -> backend (port 80) # maps/sni.map SNI -> backend (port 443) # manifest generation, domain count, timestamp # # Routing uses those maps so that adding or removing a domain never changes a # frontend: a map miss yields an empty backend name, which HAProxy treats as # "no rule matched" and falls through to default_backend (the reject backend). # Keep this file free of anything domain-specific — it is the one part of the # layout a reload cannot change. global log /dev/log local0 log /dev/log local1 notice maxconn 4096 # Started as root by systemd (to bind 80/443), then dropped to 'haproxy'. user haproxy group haproxy # Master-worker is selected with -Ws on the command line, which systemd # needs for Type=notify; the old `master-worker` directive is deprecated. # # A reload keeps the old worker alive until its connections finish. This # bounds how long a stuck worker may linger (5 minutes) so repeated reloads # cannot accumulate processes. It applies to the DRAIN of established # connections, not to new ones, so a long-lived SSH/WebSocket tunnel may in # principle be cut short — raise it if that ever matters more than memory. hard-stop-after 5m # Local admin socket: used by `vps` diagnostics and for graceful reloads. stats socket /run/haproxy/admin.sock mode 660 level admin defaults log global option dontlognull retries 2 timeout connect 5s # Deliberately generous: SSH tunnels and WebSockets live for hours and the # 443 path is a raw TCP passthrough, so there is nothing to time out early. timeout client 1h timeout server 1h timeout tunnel 1h # --------------------------------------------------------------------------- # :80 - HTTP host routing to the containers # --------------------------------------------------------------------------- frontend fe_http mode http bind :80 option httplog # Normalize before the map lookup: lowercase, then drop a ":port" suffix # that a client may have sent. http-request set-var(txn.host) req.hdr(host),lower,regsub(:[0-9]+$,) http-request set-header X-Forwarded-Proto http http-request set-header X-Forwarded-Port 80 # The client address reaches the container as X-Forwarded-For, added by the # backends (option forwardfor). PROXY protocol is never used on :80. use_backend %[var(txn.host),map(/etc/haproxy/current/maps/http.map)] default_backend be_http_reject backend be_http_reject mode http http-request deny deny_status 404 # --------------------------------------------------------------------------- # :443 - TLS SNI routing (PASSTHROUGH: HAProxy never terminates TLS here) # --------------------------------------------------------------------------- frontend fe_tls mode tcp bind :443 option tcplog # The SNI is only available once the ClientHello has arrived; without an # inspect-delay the routing decision would be taken before it is known. tcp-request inspect-delay 2s tcp-request content accept if { req.ssl_hello_type 1 } use_backend %[req.ssl_sni,lower,map(/etc/haproxy/current/maps/sni.map)] default_backend be_tls_reject backend be_tls_reject mode tcp # No SNI, an unregistered host, or anything that is not a TLS ClientHello: # close immediately instead of forwarding. tcp-request content reject