Shami's Blog

DevOps because uptime is not optional

Maintenance Pages With HAProxy

Edit: 31/7/2021: Add content for maintenance pages.

I currently work with a group of very smart individuals and I learn a lot from them on almost daily basis. One thing they have done which I found cool was using Terraform to configure the AWS Application Load Balancer to display the notice during maintenance windows.

I wanted to see if my favorite load balancer HAProxy could do it and turns out it can, and you can find the required configuration below. It assumes running multiple web applications with one server each, modifying the configuration to suit your requirements should be simple to do.

/etc/haproxy/haproxy.cfg

 1global
 2    log /dev/log    local0
 3    log /dev/log    local1 notice
 4    chroot /var/lib/haproxy
 5    user haproxy
 6    group haproxy
 7    daemon
 8
 9    # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
10    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
11    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
12    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
13
14    ssl-dh-param-file /etc/haproxy/dhparams.pem
15
16defaults
17    log     global
18    mode    http
19    option  httplog
20    option  dontlognull
21    timeout connect 500
22    timeout client  5000
23    timeout server  5000
24
25frontend terminator
26    bind PUBLIC_IP:80
27    bind PUBLIC_IP:443 ssl crt-list /etc/haproxy/certs alpn h2,http/1.1
28
29    # LetsEncrypt
30    acl acme path_dir /.well-known/acme-challenge
31
32    acl maintenance_mode hdr(host),map(/etc/haproxy/maintenance) -m found
33    acl whitelist src -f /etc/haproxy/whitelist
34
35    http-response set-header Strict-Transport-Security max-age=15768000 if { ssl_fc }
36    http-request set-header X-Forwarded-Proto https if  { ssl_fc }
37    # The ACME protocol doesn't like it when it gets redirected
38    redirect scheme https code 301 if !{ ssl_fc } !acme
39
40    use_backend acme if acme
41
42    # Actual Routing
43    use_backend %[req.hdr(host),lower,map(/etc/haproxy/maintenance)] if maintenance_mode !whitelist
44    use_backend %[req.hdr(host),lower,map(/etc/haproxy/backends)]
45
46backend acme
47    server acmetool 127.0.0.1:402
48
49# Actual backends
50backend webapp1
51    server server1 127.0.0.1:8080
52
53backend webapp2
54    server server1 127.0.0.1:8081
55
56# Maintenance backends
57backend webapp1_maintenance
58    errorfile 503 /etc/haproxy/maintenance_pages/webapp1.http
59
60backend webapp2_maintenance
61    errorfile 503 /etc/haproxy/maintenance_pages/webapp2.http

/etc/haproxy/whitelist

1# Networks listed here bypass all maintenance pages
2192.168.0.0/24

/etc/haproxy/maintenance

1# Uncomment lines below to enable the maintenance page for the desired web application
2#webapp1.com  webapp1_maintenance
3#webapp2.com  webapp2_maintenance

/etc/haproxy/backends

1webapp1.com  webapp1
2webapp2.com  webapp2

As for the maintenance pages

1HTTP/1.0 503 Service Unavailable
2Cache-Control: no-cache
3Connection: close
4Content-Type: text/html
5
6<html><body><h1>Maintenance</h1>
7The system is undergoing maintenance, sorry for the inconvenience
8</body></html>

About Me

Dev gone Ops gone DevOps. Any views expressed on this blog are mine alone and do not necessarily reflect the views of my employer.

Categories