HAProxy SSL/TLS Configuration
Best practices for SSL/TLS termination in HAProxy including load balancing, modern security standards, and performance optimization.
Basic SSL Termination
Basic HTTPS frontend
Minimal SSL termination configuration:
global
log /dev/log local0
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
# SSL settings
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
default_backend web_servers
backend web_servers
balance roundrobin
server web1 192.168.1.10:80 check
server web2 192.168.1.11:80 checkCombined certificate file
HAProxy requires certificate and key in single PEM file:
# Combine certificate, key, and chain
cat example.com.crt example.com.key intermediate.crt > /etc/haproxy/certs/example.com.pem
# Set proper permissions
chmod 600 /etc/haproxy/certs/example.com.pem
chown haproxy:haproxy /etc/haproxy/certs/example.com.pemHTTP to HTTPS redirect
Force all traffic to HTTPS:
frontend http_frontend
bind *:80
redirect scheme https code 301 if !{ ssl_fc }Modern Security Configuration
TLS protocols and ciphers
Recommended SSL/TLS configuration for 2024+:
global
# Modern configuration (TLS 1.2 and 1.3 only)
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
# Server-side SSL configuration
ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-ticketsDH parameters
Generate and use strong Diffie-Hellman parameters:
# Generate DH params (one-time setup)
openssl dhparam -out /etc/haproxy/dhparams.pem 4096
# Add to global section
global
ssl-dh-param-file /etc/haproxy/dhparams.pemCurve preferences
Specify elliptic curve preferences:
global
# HAProxy 2.4+
ssl-default-bind-curves X25519:secp384r1:secp521r1HSTS and Security Headers
Complete security headers
Add security headers to HTTPS frontend:
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/
# HSTS with 2-year max-age
http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# Additional security headers
http-response set-header X-Content-Type-Options "nosniff"
http-response set-header X-Frame-Options "SAMEORIGIN"
http-response set-header X-XSS-Protection "1; mode=block"
http-response set-header Referrer-Policy "strict-origin-when-cross-origin"
# Content Security Policy
http-response set-header Content-Security-Policy "default-src 'self' https:"
default_backend web_serversRemove server headers
Hide server version information:
frontend https_frontend
# Remove server identification
http-response del-header Server
http-response set-header Server "Secure Web Server"
# Remove X-Powered-By
http-response del-header X-Powered-ByOCSP Stapling
Enable OCSP stapling
HAProxy 2.2+ supports OCSP stapling:
# Fetch OCSP response manually
openssl ocsp -issuer intermediate.crt -cert example.com.crt \
-url http://ocsp.example.com -respout example.com.ocsp
# Add OCSP response to bind line
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/example.com.pem ocsp-update onAutomatic OCSP updates
Configure automatic OCSP response updates (HAProxy 2.2+):
global
# Enable OCSP auto-update
ocsp-update.mode on
ocsp-update.maxdelay 3600
ocsp-update.mindelay 300
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/ ocsp-update onMulti-Certificate SNI Configuration
Directory-based certificates
Load all certificates from directory (recommended):
# Place all combined PEM files in /etc/haproxy/certs/
# HAProxy automatically uses SNI to select correct cert
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/
# HAProxy selects certificate based on SNI
# example.com.pem for example.com
# api.example.com.pem for api.example.com
default_backend web_serversExplicit certificate binding
Specify multiple certificates explicitly:
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/example.com.pem crt /etc/haproxy/certs/api.example.com.pem
default_backend web_serversSNI-based routing
Route to different backends based on SNI:
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/
# Route based on hostname
use_backend api_backend if { ssl_fc_sni api.example.com }
use_backend web_backend if { ssl_fc_sni www.example.com }
default_backend web_backend
backend api_backend
balance roundrobin
server api1 192.168.1.20:8080 check
backend web_backend
balance roundrobin
server web1 192.168.1.10:80 check
server web2 192.168.1.11:80 checkClient Certificate Authentication (mTLS)
Require client certificates
Enable mutual TLS authentication:
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/ ca-file /etc/haproxy/ca/client-ca.pem verify required
# Pass client cert info to backend
http-request set-header X-SSL-Client-CN %{+Q}[ssl_c_s_dn(cn)]
http-request set-header X-SSL-Client-DN %{+Q}[ssl_c_s_dn]
http-request set-header X-SSL-Client-Verify %[ssl_c_verify]
default_backend web_serversOptional client certificates
Make client certs optional, check in backend:
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/ ca-file /etc/haproxy/ca/client-ca.pem verify optional
# Only process if client cert is valid
acl client_cert_valid ssl_c_verify 0
http-request set-header X-SSL-Client-Verified true if client_cert_valid
default_backend web_serversCRL checking
Validate client certificates against CRL:
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/ ca-file /etc/haproxy/ca/client-ca.pem crl-file /etc/haproxy/ca/crl.pem verify requiredSSL Passthrough (No Termination)
TCP mode passthrough
Forward encrypted traffic to backend without decryption:
frontend ssl_passthrough
mode tcp
bind *:443
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
# Route based on SNI
use_backend backend_example if { req_ssl_sni -i example.com }
use_backend backend_api if { req_ssl_sni -i api.example.com }
backend backend_example
mode tcp
balance roundrobin
server web1 192.168.1.10:443 check
server web2 192.168.1.11:443 check
backend backend_api
mode tcp
balance roundrobin
server api1 192.168.1.20:443 checkComplete Production Configuration
Hardened HAProxy SSL config
Complete example with all best practices:
global
log /dev/log local0
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
# SSL/TLS Settings
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
ssl-dh-param-file /etc/haproxy/dhparams.pem
# OCSP
ocsp-update.mode on
ocsp-update.maxdelay 3600
# Tuning
tune.ssl.default-dh-param 4096
maxconn 4096
defaults
log global
mode http
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout connect 5000
timeout client 50000
timeout server 50000
# HTTP redirect to HTTPS
frontend http_frontend
bind *:80
redirect scheme https code 301 if !{ ssl_fc }
# HTTPS frontend
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1 ocsp-update on
# Security Headers
http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
http-response set-header X-Content-Type-Options "nosniff"
http-response set-header X-Frame-Options "SAMEORIGIN"
http-response set-header X-XSS-Protection "1; mode=block"
http-response set-header Referrer-Policy "strict-origin-when-cross-origin"
# Remove server identification
http-response del-header Server
http-response del-header X-Powered-By
# Logging
capture request header Host len 64
capture request header User-Agent len 128
# Routing
use_backend api_backend if { path_beg /api }
default_backend web_backend
backend web_backend
balance roundrobin
option httpchk GET /health
http-check expect status 200
server web1 192.168.1.10:80 check
server web2 192.168.1.11:80 check
backend api_backend
balance roundrobin
option httpchk GET /api/health
http-check expect status 200
server api1 192.168.1.20:8080 check
server api2 192.168.1.21:8080 check
# Stats interface
listen stats
bind *:8404 ssl crt /etc/haproxy/certs/stats.pem
stats enable
stats uri /stats
stats refresh 30s
stats auth admin:yourpasswordPerformance Optimization
HTTP/2 and ALPN
Enable HTTP/2 with ALPN negotiation:
frontend https_frontend
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1SSL session cache
Tune SSL session caching:
global
tune.ssl.cachesize 100000
tune.ssl.lifetime 600
tune.ssl.maxrecord 1419 # Optimized for MTUConnection limits
Optimize connection handling:
global
maxconn 4096
maxsslconn 4096
tune.ssl.default-dh-param 2048Testing and Validation
Test configuration
Validate HAProxy config before reload:
# Test configuration syntax
haproxy -c -f /etc/haproxy/haproxy.cfg
# Reload if successful
systemctl reload haproxy
# Or graceful reload
haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid)Check SSL configuration
Verify SSL settings:
# Test TLS connection
openssl s_client -connect example.com:443 -servername example.com
# Test HTTP/2
curl -I --http2 https://example.com
# Test specific TLS version
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3SSL Labs test
Comprehensive SSL analysis:
# Visit: https://www.ssllabs.com/ssltest/
# Target: A+ rating with modern configurationSee Also
Important Notes
HAProxy requires certificate, private key, and chain in a single PEM file. Order: cert → key → intermediates.
HAProxy uses SNI to select certificates automatically when loading from directory. Ensure clients support SNI.
Use `systemctl reload haproxy` for zero-downtime certificate updates. HAProxy transfers active connections to new process.
Requires HAProxy 2.2+ for automatic updates. Earlier versions need manual OCSP response management.
Requires HAProxy 1.8+ and OpenSSL 1.0.2+. Use `alpn h2,http/1.1` on bind line.
For mTLS, use verify required, verify optional, or verify optional_no_ca depending on use case.
PEM files should be readable only by haproxy user (chmod 600, chown haproxy).
HAProxy is extremely efficient at SSL termination. Can handle thousands of concurrent SSL connections on modest hardware.
Official HAProxy docs: haproxy.org/documentation.html
SSL Configuration: cbonte.github.io/haproxy-dconv/configuration-1.9.html#5.1-ssl