Let’s Encrypt en Nginx combineren

Noud van Kruysbergen
0

Inhoudsopgave

    Je kunt je server snel nieuwe mogelijkheden geven met docker­containers. Maar als je niet alle diensten wilt dockeren, kun je een kant-en-klare container­image gebruiken voor een Nginx-reverse-proxy en het automatisch verkrijgen van certificaten bij Let’s Encrypt. We laten zien hoe je die twee dingen zo instelt dat je er amper nog werk aan hebt.

    Docker is leuk. De containerimages nemen je best wat werk uit handen en maken het mogelijk om veel sneller nieuwe webdiensten uit te proberen – en die ook net zo snel en zonder achterblijvende restanten weer te verwijderen. Als je tegenwoordig een root- of een V-server hebt, wil je eigenlijk niet zonder. Maar vaak draaien op die server nog talrijke andere diensten uit een tijd van voor docker. Die zijn toen zorgvuldig handmatig geconfigureerd en jarenlang onderhouden. Al die diensten zijn in een container te zetten, maar daar moet je dan eigen images voor maken. Dat kan voor een enkele dienst al meerdere uren werk gaan betekenen.

    Je eigen server kun je meestal dan ook niet in een slag dockeren, zelfs niet als je daar het hele weekend voor inruimt. Docker is echter snel geïnstalleerd en de eerste container draait al na een paar minuten. Die container komt echter niet aan poort 80 of 443 omdat die twee nog door een web­server gebruikt worden, bijvoorbeeld Nginx. Nginx levert nog andere diensten die niet in een container draaien. De bestaande container met Nginx-proxy en Let’s-Encrypt-automatisering kan de handmatig geïnstalleerde Nginx niet vervangen omdat dat alle diensten buiten de containers zou deactiveren. Je kunt dan Nginx als reverse-proxy gaan gebruiken en een ACME-client voor Let’s Encrypt installeren. De reverse-proxy neemt alle requests van buitenaf voor zijn rekening en verdeelt die over de andere web- of CGI-servers.

    Let's Encrypt en Nginx combineren certificaat reverse proxy Nginx

    Veilig met Nginx

    Een webserver moet tegenwoordig met iedere websitebezoeker een TLS-verbinding onderhandelen. Als er op dezelfde server echter verschillende webdiensten draaien, is het niet nodig dat die diensten versleuteld met de proxy communiceren. Het volstaat daarom dat een als reverse-proxy geconfigureerde Nginx alle SSL-verbindingen ontvangt en onversleuteld doorstuurt naar de gewenste diensten. Hij is de centrale plek voor certificaten en kan zich bezig houden met de requests waarmee Let’s Encrypt de domeinen valideert.

    Elke dienst gebruikt meestal een eigen domeinnaam of subdomein op de server. Bij Nginx configureer je de virtuele hosts (VHost) met server{}-blokken die requests met server_name subdomein.mijn-domein.nl; de juiste configuratie toekennen. In de server{}-blokken definiëren location{}-blokken wat er met de opgevraagde URL moet gebeuren: uit welke directory de bestanden rechtstreeks geleverd moeten worden, of de request naar een CPI- of een WSGI-server doorgestuurd moet worden en of via proxy-pass een andere server zich om de request moet bekommeren.

    De requests waarmee Let’s Encrypt met een HTTP-challenge de domeinen valideert, roepen een erg cryptisch genoemd bestand met een token op dat in het pad /.wellknown/acme-challenge/ staat. Ngnix moet dergelijke requests niet doorsturen, maar meteen het door de ACME-client geleverde bestand terugsturen. Zoek daarom een plek op de server (bijvoorbeeld /var/www/letsencrypt-challenges/) waar de ACME-client het bestand neer mag zetten en schrijf daar een location{}-blok voor:

    location /.well-known/acme-challenge {
    root /var/www/letsencrypt-challenges;
    }

    Omdat dit blok voor alle VHosts hetzelfde is, scheelt het aardig wat typewerk als je die drie regels in een nieuw bestand met de naam /etc/nginx/letsencrypt-webroot zet. Dat kun je daarna namelijk makkelijk met de volgende regel aan alle server{}-blokken koppelen:

    include letsencrypt-webroot;

    Als je location{}-blokken gebruikt die met regex matchen (~ of ~* achter location), kijkt Nginx daar eerst naar, ook als ze in de configuratie helemaal onderaan staan. Bij die blokken moet je er dus op letten dat je niet naar het tokenbestand in het url-pad /.wellknown/acme-challenge/ matcht (bijvoorbeeld niet location ~ (.*) {} gebruiken). In geval van twijfel bouw je het blok met location ~ \/.well-known\/acme-challenge\/(.*) { zelf om naar een regex.

    Voor het valideren van een domein speelt het verder geen rol of dat via HTTP of HTTPS gebeurt. Het heeft dan ook geen nut om include letsencrypt-webroot; zowel in het server{}-blok te zetten voor HTTP (listen 80; listen [::]:80;) als in dat voor HTTPS (listen 443 ssl; listen [::]:443 ssl;).

    Certificaten met acme.sh

    De op die manier uitgebreide configuratie volstaat om de validatierequests van Let’s Encrypt te beantwoorden. Daarom kan de ACME-client nu certificaten bij Let’s Encrypt gaan aanvragen. Uit meerdere geschikte ACME-clients viel onze keuze op acme.sh, dat als shell-script op alle Linux-servers draait en alles kan wat ACME ondersteunt.

    Lees meer over Acme.sh en Let's Encrypt in c't apr/2018

    Het script acme.sh ondersteunt zowel ACME 1.0 als de nieuwe versie 2.0, en haalt indien gewenst signatures op voor zelf gemaakte CSR’s (Certificate Signing Request). Het vraagt zelfs wildcard-certificaten aan, als je via DNS kunt valideren. Ons voorbeeld gebruikt met de geïntegreerde cron-job en eenvoudige domeinvalidering via HTTP-challenge alleen de basis-features.

    Je installeert acme.sh makkelijk met git clone in de home-directory:

    git clone https://github.com/Neilpang/acme.sh.git
    cd ./acme.sh
    sudo ./acme.sh –install

    Het commando met –install verandert niets aan het shell-script. Dat heeft git al kant-en-klaar gedownload. Het stelt echter een cron-job in die automatisch al na twee maanden de opgevraagde certificaten verlengt – certificaten van Let’s Encrypt zijn maar drie maanden geldig. De accountsleutel en de lijst van aangevraagde certificaten belanden beide in ~/.acme.sh/.

    Het aanvragen van certificaten gaat daarna heel eenvoudig met ./acme.sh –issue. Achter de optie -d geef je een domeinnaam op. De eerste dient als naam voor het certificaat. Als je de optie -d meerdere keren met verschillende domeinnamen gebruikt, valideert Let’s Encrypt ze allemaal en worden ze in Subject­AlternativeName in het certificaat geschreven. Het certificaat geldt dan voor alle opgegeven domeinen.

    Als je wilt, kun je de standaard sleutellengte van 2048 nog verhogen met de optie –keylength 4096. Dat levert voor de server iets meer rekenbelasting op bij het opbouwen van een verbinding, maar veel beveiligingsexperts adviseren om RSA-sleutels van slechts 2048 bit niet te gebruiken.

    Belangrijk is de optie -w, die de web­root-directory voor het token-bestand aangeeft. Dat is door de Nginx-configuratie ingesteld op /var/www/lets encrypt-challenges/. Het script acme.sh zet de tokens dan in die directory en Nginx levert ze aan de valideringsserver van Let’s Encrypt.

    Daarnaast heeft acme.sh nog wat handige functies die het omgaan met certificaten bijzonder eenvoudig maken. Met de opties –key-file, –cert-file en –fullchain-file kopieert acme.sh de aangemaakte certificaten naar de opgegeven paden. We hebben bijvoorbeeld voor elke VHost een subdirectory in /etc/certs/ aangemaakt en de .pem-bestanden met deze drie opties daar vervolgens rechtstreeks naartoe gekopieerd.

    Om ervoor te zorgen dat Nginx bij een certificaatwisseling ook meteen de nieuwe certificaten levert, voeg je telkens de optie –reloadcmd “systemctl reload nginx.service” toe. Dat zorgt niet alleen voor een reload van de webserver na het aanvragen van een nieuw certificaat, maar voert de reload ook uit bij een certificaatswisseling door de cron-job. Omdat acme.sh met root-rechten draait, kan het script ook de webserver herladen.

    Doorlezen is gratis, maar eerst even dit:

    Dit artikel is met grote zorg samengesteld door de redactie van c’t magazine – het meest toonaangevende computertijdschrift van Nederland en België. Met zeer uitgebreide tests en praktische workshops biedt c’t de diepgang die je nergens online vindt.

    Bekijk de abonnementen   Lees eerst verder

    Certificaten installeren

    Het aanvragen van een certificaat voor het domein titans-rollenspel.nl ziet er dan bijvoorbeeld zo uit:

    sudo ./acme.sh –issue
    -d titans-rollenspel.nl
    -d www.titans-rollenspel.nl
    –keylength 4096
    -w /var/www/letsencrypt-challenges/
    –key-file /etc/certs/titans-rollenspel.nl/key.pem
    –cert-file /etc/certs/titans-rollenspel.nl/cert.pem
    –fullchain-file /etc/certs/titans-rollenspel.nl/fullchain.pem
    –reloadcmd “systemctl reload
    nginx.service”

    Als je een certificaat liever eerst ophaalt (met verificatie) en daarna installeert, kun je hetzelfde ook met twee commando’s doen:

    sudo ./acme.sh –issue
    -d titans-rollenspel.nl
    -d www.titans-rollenspel.nl
    –keylength 4096
    -w /var/www/letsencrypt-challenges/sudo ./acme.sh
    –install-cert -d
    titans-rollenspel.nl
    –key-file /etc/certs/titans-rollenspel.nl/key.pem
    –cert-file /etc/certs/titans-rollenspel.nl/cert.pem
    –fullchain-file /etc/certs/titans-rollenspel.nl/fullchain.pem
    –reloadcmd “systemctl reload
    nginx.service”

    Sleuteloverdracht

    Om ervoor te zorgen dat Nginx de nieuw verkregen certificaten van Let’s Encrypt ook gebruikt, geef je dat aan in het desbetreffende server{}-blok voor HTTPS (de VHost-­configuratie voor poort 443):

    ssl_certificate /etc/certs/titans-rollenspel.nl/fullchain.pem;
    ssl_certificate_key /etc/certs/titans-rollenspel.nl/key.pem;

    Als je wilt, meld je gebruikers ook meteen nog via HSTS dat je website de komende zes maanden via HTTPS bereikbaar zal zijn:

    add_header Strict-Transport-Security
    max-age=15768000;

    De rest van de configuratie komt overeen met een verder normale Nginx-configuratie voor een webserver met SSL. Geef in elk geval in je configuratie aan met ssl_prefer_server_ciphers on; dat versleutelings- en sleutelonderhandelings­algoritmes (ciphers) op de server voorrang hebben boven die van de clients en kijk regelmatig naar de lijst van algoritmes om afscheid te nemen van onveilige methoden.

    Met de hier voorgestelde combinatie van Nginx en acme.sh kun je al met al dus vrij makkelijk certificaten ophalen voor je diensten, of die nu in dockercontainers draaien of rechtstreeks op de server. De door acme.sh automatisch ingestelde cron-job zorgt ervoor dat je aflopende certificaten niet handmatig hoeft te vernieuwen.

    Als je het jammer vindt dat je bij deze set-up handmatig wat meer moet doen dan bij een pure dockerset-up, dan kun je alle diensten een voor een in alle rust ombouwen en vervolgens overgaan op containers. Er is echter niets op tegen om de reverse-proxy gewoon te blijven gebruiken.

    (Pina Merkert, c’t magazine)

    Meer over Docker en Linux lees je in c't. Nieuwste uitgave: c't 05/2024

    Deel dit artikel

    Noud van Kruysbergen
    Noud van KruysbergenNoud heeft de 'American Dream' doorlopen van jongste bediende tot hoofdredacteur van c't, waar hij zo veel mogelijk de diepgang, betrouwbaarheid en diversiteit wil bewaken.

    Lees ook

    Chat GPT 4 gebruiken: dit is het verschil tussen GPT-3 & GPT-4

    De lancering van GPT-4 heeft de intelligentie van ChatGPT naar een hoger niveau gebracht maar hoe kun je effectief de nieuwe Chat GPT gebruiken en wat...

    Raspberry Pi als NAS-systeem gebruiken? Dit moet je weten!

    Wist je dat je een Raspberry Pi als Network Attached Storage (NAS) kunt gebruiken? Zo voldoet de Raspberry Pi 4 aan de belangrijkste eisen om dit te k...

    0 Praat mee
    avatar
      Abonneer  
    Laat het mij weten wanneer er