haproxy certbot lets encrypt letsencrypt pem cert crt http challenge systemd

Certbot com haproxy

Estes são os passos para criar e atualizar os certificados emitidos pelo Let's Encrypt de forma automática integrada com o haproxy.

Inventei eles na época em que o certbot não suportava hooks completamente. Acho que hoje os comandos do renew-hook ficariam em um arquivo em /etc/letsencrypt/renewal-hooks, mas todos os outros passos são idênticos.

Criando certificados

  1. Requisitar o certificado do Let's Encrypt, que vai ser colocado automaticamente em /etc/letsencrypt/live/novo-dominio.example.com/
       certbot certonly \
               --standalone \
               --http01-port 8888 \
               --preferred-challenges http-01 \
               --domain novo-dominio.example.com
    
  2. Copiar e converter para o formato e local esperados pelo haproxy: arquivo único contendo a cadeia completa de certificados da raiz até o seu (sub)domínio, assim como a respectiva chave privada do mesmo (sub)domínio.
       cat /etc/letsencrypt/live/novo-dominio.example.com/fullchain.pem \
           /etc/letsencrypt/live/novo-dominio.example.com/privkey.pem \
           > /etc/letsencrypt/novo-dominio.example.com.pem
    

Atualizando certificados

  1. Criar um serviço no systemd
       # /etc/systemd/system/certbot.service
       [Unit]
       Description=Certbot/Letsencrypt (renova certificados)
       Wants=haproxy.service
    
       [Service]
       Type=oneshot
       ExecStart=/usr/bin/certbot renew -q --standalone --http-01-port 8888 --preferred-challenges http-01 --renew-hook "/bin/sh -c 'for d in $$RENEWED_DOMAINS; do cat \"$$RENEWED_LINEAGE/fullchain.pem\" \"$$RENEWED_LINEAGE/privkey.pem\" >\"/etc/letsencrypt/$${d}.pem\"; done'"
       ExecStartPost=/bin/systemctl reload haproxy.service
    
  2. Criar um timer do systemd
       # /etc/systemd/system/certbot.timer
       [Unit]
       Description=Certbot/Letsencrypt (renova certificados)
    
       [Timer]
       OnCalendar=daily
       Persistent=true
    
       [Install]
       WantedBy=multi-user.target
    
  3. Apontar o haproxy para o diretório de certificados emitidos pelo Let's Encrypt e repassar os challenges para o certbot.
       frontend main
           bind *:80,:::80
           bind *:443,:::443 ssl crt /etc/letsencrypt
    
           # identifica acme challenges
           acl acl_letsencrypt path_beg /.well-known/acme-challenge/
    
           # redireciona http -> https
           redirect scheme https code 301 unless acl_letsencrypt or { ssl_fc }
    
           # responde acme challenges
           use_backend b_letsencrypt if acl_letsencrypt
    
           # ... outras coisas ...
    
       backend b_letsencrypt
           # se esse serviço não responder rápido é porque não está executando,
           # então retorne rápido
           timeout 10ms
    
           server s_letsencrypt localhost:8888