This is largely inspired from https://phansch.net/posts/haproxy-letsencrypt-certbot/
I recently changed my setup such that haproxy listens on 80 and 443 and proxies into various services. I like it MUCH better now. IMO, it is far easier to manage.
One outstanding issue is certificate renewal. The certbot package on ubuntu (and probably debian, but I'm on ubuntu) includes /lib/systemd/system/certbot.service and /lib/systemd/system/certbot.timer files and I would like to work with them. Systemd is awesome and allows me to do so using overrides. I don't even have to think about how to manage the overrides. I use sudo systemctl edit certbot.
I add this to the editor which starts:
[Service]
ExecStart=
ExecStart=-/usr/bin/certbot -q renew --preferred-challenges http --http-01-port 9785
ExecStartPost=/etc/haproxy/certs/certbot-renew
There is an excellent post here which describes why the blank = and the -=. I shall not repeat it here. Go read the reply. It is great: https://askubuntu.com/a/659268/1668
To my haproxy.cfg I added to both frontends:
acl letsencrypt-req path_beg /.well-known/acme-challenge/
use_backend letsencrypt if letsencrypt-req
and that letsencrypt backend:
backend letsencrypt
server letsencrypt 127.0.0.1:9785
Cool, now when letsencrypt tries to verify on my system, that request for /.well-known/acme-challenge/ will be redirected to the certbot process listening on port 9785.
There is also that ExecStartPost= which I must explain.
My haproxy.cfg is setup with crt-base /etc/haproxy/certs in the global section and an HTTPS frontend which starts like this:
frontend https-in
bind :::443 v4v6 ssl crt one.example.com crt two.example.com crt e.example.net alpn h2,ht
tp/1.1
Yes, I have a few different certificates from letsencrypt. One with a dozen or so SNI names and the other two as wildcard certificates. I use the haproxy features of reading all pem files in a directory to load them. I'd like any certbot renew to automatically configure them for haproxy.
This is done with that ExecStartPost=/etc/haproxy/certs/certbot-renew script:
#!/bin/bash
set -e
cd /etc/haproxy/certs
LELIVE=/etc/letsencrypt/live
RELOAD=false
for d in $(find . -type d -not -name .) ; do
if [[ $LELIVE/$d/fullchain.pem -nt $d/fullchain.pem ]] ; then
RELOAD=true
cp $LELIVE/$d/fullchain.pem $d/fullchain.pem
cp $LELIVE/$d/privkey.pem $d/fullchain.pem.key
chown haproxy:haproxy $d/fullchain.pem $d/fullchain.pem.key
fi
done
if [[ $RELOAD == true ]] ; then
systemctl reload haproxy
fi
The script looks at each directory in /etc/letsencrypt/live and if the fullchain.pem in that directory is newer than the one in /etc/haproxy/certs then it copies the pem file and keys into the haproxy directory with a filename which haproxy will read. If it did anything then it calls systemctl to reload haproxy.
It is possible that I won't have to deal with certificate renewal every again.
Top comments (0)