Dynamically choose HAProxy backend depending on the HTTP host header, Lua programming language and environment variable.
HAProxy version.
$ haproxy -v HA-Proxy version 1.7.5-2 2017/05/17 Copyright 2000-2017 Willy Tarreau <willy@haproxy.org>
Default HAProxy configuration.
global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy daemon # Default SSL material locations ca-base /etc/ssl/certs crt-base /etc/ssl/private # Default ciphers to use on SSL-enabled listening sockets. # For more information, see ciphers(1SSL). This list is from: # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ # An alternative list with additional directives can be obtained from # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS ssl-default-bind-options no-sslv3 defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http
Inspect systemd service file to learn that you can use /etc/default/haproxy
file to define additional environment variables.
$ cat /lib/systemd/system/haproxy.service
[Unit] Description=HAProxy Load Balancer Documentation=man:haproxy(1) Documentation=file:/usr/share/doc/haproxy/configuration.txt.gz After=network.target syslog.service Wants=syslog.service [Service] Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid" EnvironmentFile=-/etc/default/haproxy ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS ExecStart=/usr/sbin/haproxy-systemd-wrapper -f $CONFIG -p $PIDFILE $EXTRAOPTS ExecReload=/usr/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS ExecReload=/bin/kill -USR2 $MAINPID KillMode=mixed Restart=always [Install] WantedBy=multi-user.target
Use HAPROXY_SERVER_NAME
variable to define fully qualified domain name of the HAProxy server. Unfortunately, you cannot use $(hostname --fqdn)
command to set it on service start.
$ cat << EOF | sudo tee -a /etc/default/haproxy # pass server name to haproxy HAPROXY_SERVER_NAME="example.org" EOF
# pass server name to haproxy HAPROXY_SERVER_NAME="example.org"
$ cat /etc/default/haproxy
# Defaults file for HAProxy # # This is sourced by both, the initscript and the systemd unit file, so do not # treat it as a shell script fragment. # Change the config file location if needed #CONFIG="/etc/haproxy/haproxy.cfg" # Add extra flags here, see haproxy(1) for a few options #EXTRAOPTS="-de -m 16" # pass server name to haproxy HAPROXY_SERVER_NAME="example.org"
Define Lua function to get hostname defined in HTTP host header.
$ cat << | sudo tee /etc/haproxy/destination_hostname.lua core.register_fetches("destination_hostname", function(txn) local hostname = txn.sf:req_fhdr("host"):lower() return hostname end) EOF
core.register_fetches("destination_hostname", function(txn) local hostname = txn.sf:req_fhdr("host"):lower() return hostname end)
Load Lua script inside global
section.
global [...] lua-load /etc/haproxy/destination_hostname.lua
Define frontend and backends to use default
backend for HAProxy address (this is why we need HAPROXY_SERVER_NAME
environment variable), example.com
and example.net
backends for their respective addresses, nonexistent
backend for every other address.
frontend development-frontend bind :80 #bind :443 ssl crt /etc/ssl/cert/ option httplog option forwardfor except 127.0.0.1 option forwardfor header X-Real-IP #redirect scheme https code 301 if !{ ssl_fc } acl is-host-itself lua.destination_hostname() "${HAPROXY_SERVER_NAME}" http-request set-var(txn.destination_hostname) lua.destination_hostname() use_backend default if is-host-itself use_backend %[var(txn.destination_hostname)] default_backend nonexistent backend default server default 10.66.91.125:80 backend example.com server default 10.66.91.52:80 backend example.net server default 10.66.91.53:80 backend nonexistent server default 10.66.91.50:80
Sample log output for regular query to HAProxy hostname (default backend).
$ curl http://example.org
Jan 21 17:05:21 example haproxy[7858]: 10.66.91.165:32856 [21/Jan/2018:17:05:21.581] development-frontend default/default 0/0/0/4/5 200 9386 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"
Sample log output for regular query to the hosted example.com
domain (example.com backend).
$ curl http://example.com
Jan 21 17:06:09 example haproxy[7858]: 10.66.91.165:32868 [21/Jan/2018:17:06:09.845] development-frontend example.com/default 0/0/0/1/1 301 805 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"
Sample log output for regular query to the hosted example.net
domain (example.net backend).
$ curl http://example.net
Jan 21 17:06:12 example haproxy[7858]: 10.66.91.165:32874 [21/Jan/2018:17:06:12.170] development-frontend example.net/default 0/0/0/123/123 200 29158 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"
Sample log output for regular query to the not hosted example.co.uk
domain (nonexistent backend).
$ curl http://example.co.uk
Jan 21 17:06:46 example haproxy[7858]: 10.66.91.165:32880 [21/Jan/2018:17:06:46.662] development-frontend nonexistent/default 0/0/0/0/0 200 11174 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1"