Haproxy med Let's Encrypt

Det kan verka som voodoo att få vissa saker att fungera men genom att mecka, mecka och mecka lite till har jag fått fram en fungerande modell för hur man får Let’s Encrypt att fungera med Haproxy. Värt att notera är att jag baserar denna guide på Haproxy v2.0.5 kompilerad på CentOS 7.6.1810. Det finns saker jag gör i min konfigurationsfil som kommer tas bort i framtida versioner av Haproxy (i synnerhet användandet av ‘reqadd’) så det kommer jag behöva skriva om, men det är då det.

Det första du gör är, givetvis, att installera Haproxy. Hur din konfiguration ser ut varierar givetvis från fall till fall men det finns ett par saker du kan ha med som gör livet lite enklare. Som jag sa så har jag kompilerat upp Haproxy på CentOS 7 från källkoden. Jag använde följande parametrar för det för att få in stöd för SystemD och lite annat:

make -j 4 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_CRYPT_H=1 USE_LIBCRYPT=1 USE_SYSTEMD=1

I övrigt finns det guider för hur du gör installationen på bästa sätt med CentOS 7, och det är varmt rekommenderat att göra installationen från källkod då den version som finns i CentOS 7-repot är gammal som gatan och saknar stöd för en hel del roliga saker, exempelvis stöd för http/2 vilket kom i version 1.8 av Haproxy, vilket är trevligt i kombination med SSL.

Väl att notera är också att Haproxy gärna vill använda /var/run/haproxy/ när den startar för sin socket. Det går givetvis att ändra i /etc/haproxy/haproxy.cfg om man vill det men som standard kan denna inställning finnas i konfigurationsfilen.

Under inställningarna för global kan du lägga in inställningarna för hur SSL-certen ska hanteras av Haproxy. Mina ser ut så här:

tune.ssl.default-dh-param 4096
   ssl-default-bind-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AE
S128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-
DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
   ssl-default-bind-options no-sslv3 no-tls-tickets
   ssl-default-server-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-
AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDS
A-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
   ssl-default-server-options no-sslv3 no-tls-tickets

Genom att använda ACL:er kan du göra redirects redan i Haproxy för att skicka trafiken från http till https.

Under avsnittet för frontend sätter du följande (hämtat från min egna konfiguration):

  acl is_joacimmelin            hdr_end(host) -i www.melin.org
  acl is_joacimmelin            hdr_end(host) -i melin.org

Därefter lägger du in följande i samma kodavsnitt:

  redirect scheme https if { hdr(Host) -i www.melin.org } !{ ssl_fc }
 redirect scheme https if { hdr(Host) -i melin.org } !{ ssl_fc }

Vill du ändå tillåta både http och https-trafik kan du lägga in följande i samma kodavsnitt:

use_backend  nginx if is_joacimmelin

Namnet “nginx” är namnet på min backend där alla webbservrarna ligger inlagda. Du kan givetvis döpa den till vad du vill.

Nu kommer vi till det lite knepigare avsnittet, frontend för https.

Jag börjar det så här:

frontend https_front
  compression algo gzip
  compression type text/html text/plain text/javascript application/javascript application/xml text/css
  bind *:443 ssl crt-list /etc/ssl/crt-list.txt alpn h2,http/1.1
  reqadd X-Forwarded-Proto:\ https
  acl is_joacimmelin             hdr_end(host) -i www.melin.org
  acl is_joacimmelin             hdr_end(host) -i melin.org
  use_backend             nginx if is_joacimmelin

Den kanske viktigaste raden av den alla är rad fyra där vi binder en fil som heter /etc/ssl/crt-list.txt till ssl-hanteringen i Haproxy. Där finns för övrigt också en parameter som heter h2 som slår på http/2, vilket varmt rekommenderas.

Certifikathantering i Let’s Encrypt

Filen jag nämnde ovan (crt-list.txt) ser i mitt fall ut så här:

 /etc/letsencrypt/live/melin.org/melin.org

Sökvägen till filen är väl ganska tydlig, men filnamnet (melin.org)? För att detta ska fungera måste man göra ett kombinerat cert av de filer man får från Let’s Encrypt och det gör man på detta sätt:

DOMAIN='melin.org' bash -c 'cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/letsencrypt/live/$DOMAIN/privkey.pem > /etc/letsencrypt/live/$DOMAIN/melin.org'

I filen /etc/ssl/crt-list.txt kan jag sedan lista hur många certifikat jag vill för hur många domäner eller subdomäner jag vill och Haproxy kommer kolla i filen varje gång när den https-request ska hanteras och därmed skyffla över certifikatet och ladda sidan. Eftersom jag terminerar certifikatet i Haproxy kan jag skicka webbtrafiken bakåt till backend över port 80 och förutom att Wordpress behöver lite smisk för att det ska fungera (löses enklast i form av en plugin, givetvis…) så är det riktigt smidigt att bygga sin webbplattform på detta sätt.

Eftersom man skapar sina certifikat med Let’s Encrypt och certbot på Haproxy-maskinen kan man hantera den biten på lite olika sätt. Det enklaste, men kanske inte snyggaste, är att lägga in ett script i Crontab som var tredje-femte dag eller så helt sonika stoppar Haproxy, exekvererar Certbots renew-funktion, sedan kör man sammanslagningen av certifikatfilerna till ett kombinerat cert (som jag visade tidigare) och slutligen startar man Haproxy igen. Ungefär så här kan det se ut:

 #!/bin/bash
systemctl start haproxy
/usr/bin/certbot renew --standalone
DOMAIN='melin.org' bash -c 'cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/letsencrypt/live/$DOMAIN/privkey.pem > /etc/letsencrypt/live/$DOMAIN/melin.org'
systemctl start haproxy  

Lycka till!

Relaterade texter

  • Äntligen ny skärm (2021-08-06)
    Efter att ha hankat mig fram på skärmar jag fått av vänner och bekanta genom åren så ställdes jag efter nyligen genomförd flytt inför det faktum att en av mina två skärmar skadats. Eftersom jag inte överlever med en enda 24-tumsskärm, inte vill ha två olika 24-tumsskärmar bredvid varandra eller...

  • Skrota skrivaren (2021-06-21)
    Jag sprang på en bloggpost av Terence Eden som jag tyckte var ganska vettig: hur man hindrar att folk skriver ut ens webbsajt eller bloggposter. Syftet är inte att djävlas med sina läsare, utan att spara papper. Vettigt, tyckte jag, så jag har nu implementerat detta på denna blogg. Vad...

  • Så installerar du Jekyll i Fedora 31 (2020-02-15)
    Världen som Linuxanvändare blir inte enklare ju längre tiden går, snarare tvärt-om. Istället för att ha en gemensam plats för Linuxanvändare som kör Gnome att installera sina applikationer finns det givetvis två. Minst. Tidigare kunde man som Fedora-användare installera programpaket med hjälp av Snap där applikationer som inte hanterades av...

  • Kom igång med ett MD3200i (2019-12-23)
    Jag är ju en skrotsamlare av viss rang vilket kanske har framgått. Då och då ramlar det in saker som är alldeles för spännande att kasta bort, men en utmaning i allt detta, förutom att hantera lagringsyta för alla spännande saker och att förklara för den bättre hälften i hemmet...

  • Haproxy med Let's Encrypt (2019-09-09)
    Det kan verka som voodoo att få vissa saker att fungera men genom att mecka, mecka och mecka lite till har jag fått fram en fungerande modell för hur man får Let’s Encrypt att fungera med Haproxy. Värt att notera är att jag baserar denna guide på Haproxy v2.0.5 kompilerad...

  • Sparka igång en server med Kickstart (2019-07-02)
    Jag gillar att testa nya funktioner, programvaror och annat som kräver en server för ändamålet. Då jag kör VMware:s ESXi hemma så kan jag närhelst jag vill sparka igång en ny virtuell maskin. Då jag gör detta hyfsat ofta bestämde jag mig för att automatisera det hela så långt som...

  • Logga in säkert med SSH (2018-11-19)
    Jag skriver som bekant denna blogg i Markdown, ett sätt att skriva text med exempelvis länkar, punktlistor och annat i som sedan konverteras till HTML för att webbläsare ska förstå det. När man skriver i Markdown och dessutom använder Jekyll som “bloggmotor” har man två alternativ - antingen laddar man...

  • Därför ska du äga dina data (2018-11-03)
    Flickr är en bildtjänst jag haft konto hos sedan tjänsten grundades och senare blev en del av Yahoo. Efter att ett krisande Yahoo sålde av Flickr till SmugMug i april 2018 så har världen i princip bara väntat på att förändringar ska ske. När nyheten väl slog ner så var...

  • Tack och adjö, Red Hat (2018-10-17)
    Nyheten slog bokstavligen talat ned som en bomb i IT-världen: IBM köper Red Hat. På marknadsföringsspråk heter det att “Red Hat går samman med IBM”, men låt oss inte för ett ögonblick betvivla hur saker och ting egentligen ligger till: IBM ser chansen att växa till en vansinnigt stor spelare...

  • Figlet (2018-10-17)
    När man arbetar med ett större antal servrar och sitter och loggar in via SSH så kan man i ett stressat läge inte alltid uppfatta vilken server man loggat in på. Det har hänt mig en och annan gång och efter att en av lyssnarna till min och Fredrik Björemans...


  • CC BY-NC-SA 4.0