Docker-containers met automatische certificaten
Docker-containers automatisch van certificaten voorzien
Zelfs complexe toepassingen kunnen in een handomdraai op internet als daar een Docker-container voor is. Let's-Encrypt-certificaten zijn daarbij volautomatisch te genereren – en niet alleen voor web-, maar ook voor mailservers.
Veel complexe toepassingen die uit veel afzonderlijke delen bestaan, zoals de GitHub-kloon GitLab, zijn er als Docker-images. Om dergelijke diensten zonder risico's productief te kunnen gebruiken, zijn goede certificaten belangrijk. Die kun je er bij dergelijke toepassingen aan toevoegen of deze taak delegeren aan twee andere Docker-images die zich daarin gespecialiseerd hebben. De Docker-image jwilder/nginx-proxy verzamelt toegang tot de belangrijke poorten 80 en 443 als reverse-proxy en stuurt die door naar de desbetreffende containers. Welke container dat is, wordt van de naam afgeleid. De Docker-image JrCs/ docker-letsencrypt-nginx-proxy-companion maakt een certificaat voor die naam en stelt dat beschikbaar aan de reverseproxy. Aan de containers met de webapplicaties hoef je zelf dus niets te doen.
Omgevingsvariabelen, die je vooraf opgeeft bij het starten van een webapplicatie of ook andere toepassingen uit Docker-images, zorgen ervoor dat de helpers met elkaar verbonden kunnen worden. De reverse-proxy en zijn helpers luisteren naar de Docker-socket, krijgen te horen wanneer een container start en lezen dan zijn omgevingsvariabelen uit. Daaruit halen ze de host- en domeinnamen en andere benodigde gegevens voor het aanmaken van een Let's-Encrypt-certificaat.
Deze manier van werken heeft dan het charmante voordeel dat op een host in een Docker-container meerdere webapplicaties dezelfde poort kunnen gebruiken. De proxy maakt die dan bereikbaar als virtuele hosts onder verschillende namen op de standaardpoort. De webapplicaties hoeven vaak niet eens overgezet te worden naar SSL. De ACMEcommunicatie regelt de reverse-proxy transparant voor je.
Voorwaarde voor dat alles is wel dat de host met de containers via internet bereikbaar is en de name-resolving van de containers onderling werkt. Dat is bij een gemeenschappelijk User Defined Network gegarandeerd – het default netwerk van een Docker-host biedt geen name-resolving. Om ervoor te zorgen dat de data van de reverse-proxy en zijn begeleiders updates overleven, moeten ze op aparte volumes staan.
Starthulp
Het volgende yaml-bestand voor dockercompose stelt de beide hulpcontainers goed in:
ersion:‘2' networks:
ext: volumes: certs: vhosts: html: services:
nginxproxy:
image: jwilder/nginx-proxy container_name: nginxproxy hostname: nginxproxy restart:
unless-stopped networks:
- ext volumes: - certs:/etc/nginx/certs:ro - vhosts:/etc/nginx/vhost.d - html:/usr/share/nginx/html - /var/run/docker.sock:: ./tmp/docker.sock:ro ports:
- 80:80
- 443:443 labels:
- com.github.jrcs.letsencrypt: ._nginx_proxy_companion.nginx_proxy nginxproxy_comp:
image: jrcs/letsencrypt-: .nginx-proxy-companion container_name: nginxproxy_comp hostname: nginxproxy_comp restart:
unless-stopped depends_on:
- nginxproxy networks:
- ext volumes:
- certs:/etc/nginx/certs - /var/run/docker.sock:: ./var/run/docker.sock:ro volumes_from:
- nginxproxy
Het prox.yaml-bestand staat bij de link onderaan dit artikel. Het bevat ook wat begeleidend commentaar bij hier niet genoemde opties. Zet het bestand in een directory met de naam le en start met docker-compose -f ./prox.yaml up -d de beide containers. Dan wordt een User Defined Network gemaakt en komen er volumes met de prefix le_. De containers luisteren dan zowel naar poort 80 als naar poort 443 van je host.
Nu kun je een webapplicatie via een container-image starten die automatisch certificaten krijgt. Stel dat de naam www. example.com naar je Docker-host verwijst, dan start je met het volgende commando een Apache-webserver met SSLcertificaat:
docker run -d --name www
--network=le_ext -e "LETSENCRYPT_ .HOST=www.example.com" -e "LETS .ENCRYPT_EMAIL=my@example.com" -e
"VIRTUAL_HOST=www.example.com" httpd Met docker logs -f nginxproxy_comp kun je het krijgen van het certificaat volgen. De containernaam en het hostnaamaandeel in de omgevingsvariabele VIRTUAL_HOST zijn daarbij identiek, namelijk www – dat zorgt ervoor dat de nginxreverse-proxy de requests naar de juiste containers kan doorsturen. Met ExposedPort wordt ingesteld welke poort daarbij gebruikt wordt.
Tips & Trucs
Voor speciale gevallen moet je dan nog wat meer weten. Sommige webapplicaties moet je even melden dat ze achter een reverse-proxy werken. GitLab downloadt anders bijvoorbeeld geen door SSL/TLS-beveiligde content en verklaart de gehele website onveilig. Je hoeft maar een ding in het configuratiebestand gitlab.rb te veranderen om dat uit te zetten (Proxied SSL, zie de link onderaan).
Webapplicaties staan vaak grote uploads toe. Daar moet je de reverse-proxy even mee helpen. Daar kun je de client_ max_body_size-optie in de configuratie van de nginx-proxy voor gebruiken. Die kan in het globale configuratiebestand of in het vhost-specieke staan – in het bovenstaande voorbeeld is dat /etc/nginx/ vhost.d/www.example.com (zonder .conf erachter).
Let's-Encrypt-certificaten die door nginxproxy_comp verkregen zijn, kun je vanuit andere containers gebruiken of meteen inzetten voor diensten in een container. Dat kan door het volume van de nginxproxy_comp-container toegankelijk te maken voor lezen, bijvoorbeeld met -v nginxproxy_certs:/etc/nginx/certs:ro bij een docker run-aanroep.
Op die manier profiteert ook een container die voor het ontvangen en versturen verantwoordelijk is, redelijk makkelijk van Let's-Encrypt-certificaten. Die is net als elke webapplicatie met de juiste omgevingsvariabelen te starten:
docker run -d --name mail
--network=le_ext -e "LETSENCRYPT_ .HOST=mail.example.com" -e "LETS .ENCRYPT_EMAIL=my@example.com" -e "VIRTUAL_HOST=mail.example.com" -v le_nginxproxy_certs: ./etc/nginx/certs:ro -p 25:25 -p 587 .:587 -e maildomain=mail.example.com -e smtp_user=joe:pass12 catatnight/postfix
Dat daar helemaal geen webserver in draait stoort verder niet omdat de reverse-proxy en zijn compagnon gezamenlijk de onderhandeling met Let's Encrypt afhandelen voor het certificaat. Via de als read-only-volume meegegeven directory met de certificaten is dan de e-mailserver in de container te configureren. Omdat de reverse-proxy bij toegang hier niet als tussenpersoon kan fungeren (hij kent de e-mailprotocollen niet), moet de container de voor e-mail verantwoordelijke poorten naar buiten vrijgeven (met de optie -e).
Volg dit voorbeeld trouwens niet één op één na, er ontbreekt namelijk nog van alles waar je voor productief gebruik wel op moet letten: de configuratiebestanden van de container moeten op een apart volume komen, omdat ze volumeupdates moeten overleven. Een in eigen beheer draaiende mailserver wordt snel een doelwit van meelifters die hem voor het versturen van spam gaan gebruiken. Om dat risico te verkleinen, moet je alleen berichten voor bekende adressen accepteren en alleen na authenticatie te verzenden e-mail accepteren.
Voor het toevoegen van de Let'sEncrypt-certificaten aan de mailserver of een andere via SSL/TLS te beveiligen dienst, zoals LDAP, staan voor het bovenstaande voorbeeld in de map /etc/ nginx/certs/mail.example.com meerdere bestanden om uit te kiezen: voor een e-mailserver adviseren we altijd key. pem en fullchain.pem. Voor de bovenstaande mailserver is het dan voldoende om in het bestand /etc/postfix/main.cf de items smtpd_tls_cert_file en smtpd_ tls_key_file te laten verwijzen naar de genoemde certificaatbestanden fullchain.pem en key.pem. Na een herstart van Postfix, in de container uitgevoerd met supervisorctl restart postfix, gebruikt de mailserver dan de certificaten van Let's Encrypt.
De combinatie met reverse-proxycontainer kan niet aan alle wensen voldoen. De geopende en gesloten tickets op GitHub zeggen daar genoeg over. Verschillende gebruikers hebben patches voorgesteld om het gebruik van een container als subdirectory van een vhost mogelijk te maken (bijvoorbeeld example. com/mail) – maar tot nu toe is er nog geen in de nginxproxy-image terechtgekomen. Sommige gebruikers gaan daarom aan de slag met alternatieven als Traefik – maar die bieden in de regel geen integratie met Let's Encrypt. (nkr)