I’m a new user to haproxy and I’m currently configuring it to route to my docker containers. My end goal is to reach an A+ on Qualys SSL Labs and enable my site to be included on the HSTS preload list.
According to HSTS preload, you must redirect to HTTPS and include preload header on base domain too (in the redirect).
The other question I have is: What’s the best way to add www prefix on base domain? I’d like to do this for my primary domain only.
Here’s my entire config:
global
daemon
log stdout format raw daemon warning
maxconn 50000
pidfile /var/run/haproxy.pid
tune.ssl.default-dh-param 2048
# multithreading
nbproc 1
nbthread 8
cpu-map auto:1/all 0
# set minimum SSL requirements
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 no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
ssl-default-server-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-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
ssl-dh-param-file /certs/dhparam.pem
defaults
log global
mode http
maxconn 50000
balance roundrobin
option dontlognull
option redispatch
retries 3
# connection timeouts
timeout check 5s # additional check timeout
timeout client 30s # clientside maximum inactivity time
timeout client-fin 5s # inactivity time for half-closed connections
timeout connect 5s # time for a connection attempt to a server to succeed
timeout http-keep-alive 30s # maximum allowed time to wait for a new HTTP request to appear
timeout http-request 5s # maximum allowed time to wait for a complete HTTP request
timeout queue 30s # maximum time to wait in the queue for a connection slot to be free
timeout server 5s # maximum inactivity time on the server side
timeout server-fin 5s # inactivity timeout on the server side for half-closed connections
timeout tarpit 5s # duration for which tarpitted connections will be maintained
timeout tunnel 1h # maximum inactivity time on the client and server side for tunnels
frontend http-in
bind *:80
bind *:443 ssl crt /certs/example.net.pem alpn h2,http/1.1
# default headers
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
http-response set-header X-Frame-Options "SAMEORIGIN"
http-response set-header X-XSS-Protection "1; mode=block"
http-response set-header X-Content-Type-Options "nosniff"
# redirect all HTTP traffic to HTTPS
http-request redirect scheme https code 301 if !{ ssl_fc }
# route subdomains to backends
acl is_main hdr(host) -i example.net
acl is_www hdr(host) -i www.example.net
use_backend main if is_main
use_backend www if is_www
backend main
# redirect non-www to www
acl has_www hdr_beg(host) -i www
http-request redirect prefix https://www.%[hdr(host)] code 301 if !{ has_www }
backend www
server main main:9200 check
Yeah this is unfortunately a limitation in currently released versions of haproxy, all those add-headers/set-headers rules don’t work for locally emitted responses like error pages or redirects.
This has been implemented (as the http-after-response rule) in the development version of haproxy (v2.2-dev2) and will be released as haproxy 2.2.
If you need this right now with haproxy, you either need to use LUA for the redirect or make secondary frontend/backends for the redirect and use the primary frontend/backend for the HSTS headers adjustment.
All the redirects need to happen in a second proxy layer (in this case, the frontend redirects listening on 127.0.0.1:8081 - so make sure that port is free or use a different one). This also requires another backend, which is needsredirect here that is needed to divert the traffic to the new frontend.
The original frontend http-in must not contain any redirect rules (just the HSTS settings) and must make sure that request that still need to be redirected go through backend needsredirect to frontend redirects.
It should look like this then (untested):
frontend http-in
bind *:80
bind *:443 ssl crt /certs/example.net.pem alpn h2,http/1.1
# default headers
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
http-response set-header X-Frame-Options "SAMEORIGIN"
http-response set-header X-XSS-Protection "1; mode=block"
http-response set-header X-Content-Type-Options "nosniff"
# route subdomains to backends
acl is_main hdr(host) -i example.net
acl is_www hdr(host) -i www.example.net
use_backend needsredirect if !{ ssl_fc }
use_backend needsredirect if is_main
use_backend www if is_www
backend needsredirect
server localredirects 127.0.0.1:8081
frontend redirects
bind 127.0.0.1:8081
# redirect non-www to www
acl has_www hdr_beg(host) -i www.
http-request redirect prefix https://www.%[hdr(host)] code 301 if !{ has_www }
# redirect all HTTP traffic to HTTPS
http-request redirect scheme https code 301 if !{ ssl_fc }
backend www
server main main:9200 check
For anyone else who needs this behavior before HAProxy 2.2, this config works for me and won’t include HSTS headers on the HTTP -> HTTPS redirect too!
Doing all of this will make your domain ready for HSTS preloading if you submit it to the preload list. However, I recommend upgrading to HAProxy 2.2 once it’s stable and released so you don’t have to do this and instead just use the http-after-response rule.