HAProxy Reverse Proxy
HAProxy Reverse Proxy
L4 TLS Passthrough
Forward raw TCP traffic to the controller without terminating TLS. The controller handles mTLS directly with agents.
frontend tcp_front
bind *:443
mode tcp
default_backend uptrakit_tcp
backend uptrakit_tcp
mode tcp
server uptrakit uptrakit:8443
No controller configuration changes needed for passthrough mode.
L7 TLS Termination
HAProxy terminates TLS, extracts client certificate details, and forwards them to the controller.
frontend https_front
bind *:443 ssl crt /etc/haproxy/ssl/server.pem ca-file /etc/haproxy/ssl/ca.crt verify optional
mode http
option forwardfor
# Forward client certificate info as a single structured header.
# The value MUST be quoted to prevent HAProxy 3.x from misinterpreting
# semicolons as ACL separators.
http-request set-header X-Forwarded-Client-Cert-Info "Subject=%[ssl_c_s_dn];SerialNumber=%[ssl_c_serial,hex];Issuer=%[ssl_c_i_dn]" if { ssl_c_used }
# Strip the header if no client cert was presented
http-request del-header X-Forwarded-Client-Cert-Info unless { ssl_c_used }
default_backend uptrakit_https
backend uptrakit_https
mode http
server uptrakit uptrakit:8443 ssl ca-file /etc/haproxy/ssl/ca.crt verify required
Controller Configuration
The controller needs to know the proxy's IP and which header carries the client certificate info.
Option A — CLI flags:
uptrakit-controller \
--trusted-proxy=<haproxy-ip> \
--forwarded-client-cert-info-header=X-Forwarded-Client-Cert-Info
Option B — Web UI: Navigate to Settings > Network and set:
- Trusted Proxies: the HAProxy server's IP or CIDR
- Forwarded Client Cert Info Header:
X-Forwarded-Client-Cert-Info
Option C — API:
curl -s -X PUT -H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
https://controller:8443/api/v1/settings/network \
-d '{
"trusted_proxies": ["<haproxy-ip>"],
"forwarded_client_cert_info_header": "X-Forwarded-Client-Cert-Info"
}'
Changes via Web UI or API apply immediately without a restart.
Notes
verify optionalon the frontend bind makes client certificates optional (browsers work without one).option forwardforis recommended. It adds theX-Forwarded-Forheader so the controller can resolve the real client IP for logging and rate limiting.ssl_c_s_dnreturns the client certificate subject DN.ssl_c_serial,hexreturns the certificate serial number as a hex string. The,hexconverter is required to get a consistent hex format.ssl_c_i_dnreturns the client certificate issuer DN.- The
set-headervalue must be quoted (enclosed in"...") in HAProxy 3.x. Unquoted semicolons in the value are interpreted as ACL separators, causing the header to be silently truncated. - The backend uses
ssl ca-fileto trust the controller's internal CA. - HAProxy's
server.pemfile should contain both the public certificate and private key concatenated.
WebSocket Support
HAProxy supports WebSocket natively in HTTP mode. For long-lived connections, increase timeouts:
defaults
timeout client 86400s
timeout server 86400s
timeout tunnel 86400s
CRL Revocation Checking
HAProxy supports CRL checking for client certificates. CRL files are static snapshots — you must periodically download a fresh CRL and reload. The controller rebuilds CRLs hourly and immediately on every revocation event.
Add crl-file to the frontend bind directive:
bind *:443 ssl crt /etc/haproxy/ssl/server.pem ca-file /etc/haproxy/ssl/ca.crt crl-file /etc/haproxy/ssl/ca.crl verify optional
Periodic refresh example:
# crontab entry: refresh CRL every 30 minutes
*/30 * * * * curl -sk https://controller:8443/api/v1/pki/ca.crl -o /etc/haproxy/ssl/ca.crl && echo "set ssl crl-file /etc/haproxy/ssl/ca.crl" | socat stdio /var/run/haproxy/admin.sock
Alternatively, reload HAProxy entirely:
*/30 * * * * curl -sk https://controller:8443/api/v1/pki/ca.crl -o /etc/haproxy/ssl/ca.crl && systemctl reload haproxy
HAProxy does not support OCSP checking for client certificates.
Obtaining the CA Certificate
curl -k https://uptrakit:8443/api/v1/pki/ca.crt -o /etc/haproxy/ssl/ca.crt