nginx-LetsEncrypt Reverse Proxy in der Praxis

This page is also available in English

Um auf einem Server mehrere Webservices mit entsprechenden SSL-Zertifikaten zu betreiben, bietet sich der Letsencrypt-nginx-proxy-companion an. Bei dem Setup handelt es sich um einen Reverse-Proxy, welcher SSL-Offloading und die Zertifikats-Verwaltung übernimmt. Ist der Proxy einmal gestartet, kümmert sich der Companion um die Bereitstellung mehrerer Webseiten über eine gemeinsame IP und um dessen Zertifikatsverwaltung: Für das Ausstellen der Zertifikate für neue Container und das Erneuern dieser für bestehende Container: Alles im laufenden Betrieb und innerhalb weniger Sekunden.

Schematische Darstellung

Hier schematisch dargestellt, anhand der Seiten www.libe.net und www.script-example.com:

Der nginx-Reverse-Proxy horcht nach dem Starten der Container auf Port 80 und 443. Die beiden Ports müssen im Internet unter einer öffentlichen IP verfügbar sein:

Als Webserver kann ein virtueller oder Cloud- Server eines shared Hosters verwendet werden, oder der eigene PC zu Hause mit einer eingerichteten Port-Weiterleitung am Router.

D.h. wer im Besitz einer Domäne ist kann z.B. einen A-Record der Domain oder einer Subdomain auf die öffentliche IP des Servers oder PCs zeigen lassen. Alternativ können auch Dienste wie DynDNS dazu verwendet werden. Im Falle eines PCs der zu Hause steht, kann - falls es der Provider zulässt - die öffentliche IP des Providers für den DNS Eintrag verwendet und am Router ein Port-Forwarding des Ports 443 auf die IP des PCs erstellt werden, siehe: port-forwarding.

Installation - Nginx Letsencrypt Proxy

Docker Basics

Docker ermöglicht es, Applikationen per Befehl in einem sogenannten Container zu starten.
Ein Container ist eine vom Betriebssystem (OS) unabhängige isolierte Umgebung:
Das OS spielt also keine Rolle, vorausgesetzt Docker lässt sich installieren.
Beim ersten Start eines Containers, lädt Docker selbstständig alle notwendigen Quellen
aus dem Internet.
Docker kann unter Windows, macOS oder einer Linux-Distribution installiert werden,
siehe auch: Docker
Als Voraussetzung für das Setup wird natürlich Docker benötigt, siehe: Docker Installation Linux oder Docker Installation Windows.

Neben dem wahrscheinlich bekannteren Reverse Proxy "Traefik", kann auch das schlanke Setup von Evert Ramos verwendet werden. Für einen schnellen Start kann folgendes Repo geklont werden: github.com/evertramos/nginx-proxy-automation. Die aktuelle Version des Projektes ist:

SoftwareNginx-proxy-automation
GitHubhttps://github.com/evertramos/nginx-proxy-automation
aktuelle Version 0.6
gefunden 30.09.2021

Konkret werden für die Inbetriebnahme folgenden Befehle benötigt:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git 
cd /var
mkdir docker
git clone --recurse-submodules https://github.com/evertramos/nginx-proxy-automation.git webproxy 
cd webproxy/bin && ./fresh-start.sh --yes -e your_email@domain --skip-docker-image-check

Als Netzwerk für den Proxy habe ich "webproxy" im Wizard angegeben.

Nach dem Start können zusätzlich beliebig viele Webseiten gestartet werden. Der nginx-Proxy passt seine Konfiguration automatisch anhand der Eigenschaften der Container an. Damit die Webserver für dessen Domains auch ein Zertifikat bekommen, bzw. aus dem Internet erreichbar sind, reicht es als Eigenschaften für die Container folgende Werte zu hinterlegen:

  • -e VIRTUAL_HOST=xxx.domain.tld
  • -e LETSENCRYPT_HOST=xxx.domain.tld
  • -e LETSENCRYPT_EMAIL=admin@domain.tld
  • --network=webproxy

Die Variable "VIRTUAL_HOST" gibt vor auf welchen Container der Reverse-Proxy den Traffic für diese Domäne durchstellen soll. "LETSENCRYPT_HOST" ist der DNS-Name für das Lets Encrypt-Zertifikat (sollte gleich "VIRTUAL_HOST" sein) und "LETSENCRYPT_EMAIL" die Mail-Adresse die beim Ausstellen des Zertifikats angegeben wird. Das Netzwerk "webproxy" wurde als Backend-Netzwerkname in der zuvor heruntergeladenen Docker-Compose-Konfig verwendet. Nachdem die Domains im nginx-Proxy bekannt gemacht wurden, werden die Anfragen auf den Container über das Netzwerk webproxy des Reverse-Proxy geleitet.

Beispiel: Start einer Webseite

Bevor wir die erste Webseite starten, muss ein A-Record im DNS hinterlegt werden, welcher auf die öffentliche IP-Adresse des Webservers zeigt. Im Anschluss kann ein einfacher Webserver mit folgenden Befehlen im Internet zur Verfügung gestellt werden, inkl. SSL-Zertifikat:

docker run -d -e VIRTUAL_HOST=xxx.domain.tld \
              -e LETSENCRYPT_HOST=xxx.domain.tld \
              -e LETSENCRYPT_EMAIL=admin@domain.tld \
              --network=webproxy \
              --name xxx \
              -v /var/www/xxx/httpdocs:/var/www \
              httpd:alpine

Was macht der Companion genau?

Der Letsencrypt-nginx-proxy-companion verwendet die Eigenschaften anderer Container und trägt diese als Upstream-Server ein. Er fungiert als Reverse-Proxy und leitet sämtliche Anfragen weiter. Für die Weiterleitung kann Port 80 verwendet werden, für den Zugriff auf die gehosteten Seiten 80 oder 443. Für https, Port 443 wird das SSL-Zertifikat vom Reverse-Proxy verwaltet und verlängert: SSL-Offloading. 

Zertifikat ausstellen und verlängern

Die Zertifikatsverwaltung läuft mit diesem Setup automatisch. Ein Blick in die Logs verrät, was im Hintergrund passiert: Der Container nginx-letsencrypt kontrolliert beim Start und alle 60 Minuten die Zertifikate. Sollte ein neues Zertifikat notwendig sein, wird dieses angefordert und verwendet:

nginx-letsencrypt    | /etc/nginx/certs/www.libe.net /app
nginx-letsencrypt    | Creating/renewal www.libe.net certificates... (www.libe.net)
nginx-letsencrypt    | 2021-03-14 11:09:24,871:INFO:simp_le:1414: Generating new certificate private key
nginx-web            | www.libe.net 18.196.96.172 - - [14/Mar/2021:11:09:26 +0000] "GET /.well-known/acme-challenge/xxx HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
nginx-web            | www.libe.net 3.128.26.105 - - [14/Mar/2021:11:09:26 +0000] "GET /.well-known/acme-challenge/xxx HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
nginx-web            | www.libe.net 34.211.6.84 - - [14/Mar/2021:11:09:26 +0000] "GET /.well-known/acme-challenge/xxx HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
nginx-web            | www.libe.net 66.133.109.36 - - [14/Mar/2021:11:09:26 +0000] "GET /.well-known/acme-challenge/xxx HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
nginx-letsencrypt    | 2021-03-14 11:09:29,190:INFO:simp_le:396: Saving key.pem
nginx-letsencrypt    | 2021-03-14 11:09:29,191:INFO:simp_le:396: Saving chain.pem
nginx-letsencrypt    | 2021-03-14 11:09:29,193:INFO:simp_le:396: Saving fullchain.pem
nginx-letsencrypt    | 2021-03-14 11:09:29,193:INFO:simp_le:396: Saving cert.pem

Rate-Limit: here were too many requests of a given type :: Error creating new order

Sollte zum Beispiel der DNS noch nicht auf die öffentliche IP-Adresse zeigen und der Container dennoch bereits laufen, ist etwas Geduld gefragt. Ich hatte an dieser Stelle nicht so viel Geduld und den Letsencrypt-nginx-proxy-companion mehrfach neugestartet, woraufhin dieser bei jedem Start um ein Zertifkat angefragt hat, welches aufgrund des DNS-Eintrags aber nicht ausgestellt werden konnte. An dieser Stelle habe ich gelernt, dass pro Stunde nur 5 Anfragen für ein neues Zertifikat erlaubt sind, in den Logs spiegelt sich das wie folgt wieder:

Attaching to nginx-letsencrypt, nginx-gen, nginx-web
...
nginx-gen            | 2021/03/14 10:09:12 Generated '/etc/nginx/conf.d/default.conf' from 12 containers
...
nginx-gen            | 2021/03/14 10:09:12 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification ''
...
nginx-letsencrypt    | Creating/renewal www.script-example.com certificates... (www.script-example.com)
nginx-letsencrypt    | 2021-03-14 10:09:19,372:INFO:simp_le:1546: Certificates already exist and renewal is not necessary, exiting with status code 1.
...
nginx-letsencrypt    | Creating/renewal www.libe.net certificates... (www.libe.net)
nginx-letsencrypt    | 2021-03-14 10:09:17,961:INFO:simp_le:1414: Generating new certificate private key
nginx-letsencrypt    | ACME server returned an error: urn:ietf:params:acme:error:rateLimited :: There were too many requests of a given type :: Error creating new order :: too many failed authorizations recently: see https://letsencrypt.org/docs/rate-limits/
...
nginx-letsencrypt    | Sleep for 3600s

Die Lösung: eine Stunde warten. Der Letsencrypt-nginx-proxy-companion versucht es in der nächsten Stunde wieder und wenn der DNS dann passt, wird auch ein Zertifikat ausgestellt und verwendet. 

mehrere Subdomains (SAN)

Let's Encrypt-Zertifikate können auf mehrere Subdomains ausgestellt werden, ein einfaches gängiges Beispiel wäre die Root-Domäne und die Subdomain mit einem www-Prefix: https://libe.net und https://www.libe.net. Als Beispiel können mit folgendem Docker-Aufruf Zertifikate für beide URLs angefordert werden:

docker run -d -e VIRTUAL_HOST=www.libe.net,libe.net \
              -e LETSENCRYPT_HOST=www.libe.net,libe.net \
              -e LETSENCRYPT_EMAIL=admin@domain.tld \
              --network=webproxy \
              --name xxx \
              -v /var/www/xxx/httpdocs:/var/www \
              httpd:alpine

Als Voraussetzung müssen natürlich alle DNS-Einträge der Subdomains vorhanden sein und auf den Server zeigen.

In den Eigenschaften des Zertifikats spiegeln sich zusätzliche Subdomains als "Alternativer Antragstellername"  (SAN: Subject Alternative Name) wieder:

Mit diesem Setup sollte die Webseite auf allen Domains erreichbar sein, meist soll der Internetauftritt aber primär eine URL verwenden: z.B. "www.libe.net". Der Aufruf über "libe.net" sollte dann auf "www.libe.net" umgeleitet werden:

URLs umleiten: Nicht-www auf www

Wer mehrere Subdomains beim Starten des Containers angegeben hat (SAN), kann für bestimmte Subdomains eine 301 Umleitung auf eine andere Subdomain erstellen.

Damit jetzt die domain.tld auf www.domain.tld umgeleitet wird, kann unter /data/vhost.d eine Datei mit dem exakten Namen der Domain (domain.tld) angelegt und innerhalb der Datei die Umleitung platziert werden:

if ($request_uri !~ "^/.well-known/acme-challenge")
{
  return 301 https://www.domain.tld$request_uri;
}

Reload nginx

Mit folgendem Befehl kann die nginx-Konfiguration neu geladen werden:

docker exec -it proxy-web-auto nginx -s reload

Logs

Details zum Ausstellen und Verlängern der Zertifikate können über folgendes Log angezeigt werden:

docker logs -f letsencrypt-auto

Update von Version 0.4

Ich setzte den Letsencrypt-nginx-proxy-companion bereits seit Version 0.4 ein, siehe github.com/evertramos/nginx-proxy-automation/tree/v0.4. Da sich mit Version 0.5 an den Skripts einiges geändert hat, muss das Update laut Anleitung durchgeführt werden, zum Beispiel auf die Version 0.6:  github.com/evertramos/nginx-proxy-automation/blob/master/docs/upgrade-guide.md. Bei dem Update ist etwas Geduld gefragt, da die Zertifikate dabei neu erstellt werden, was je nach Anzahl der Webservices die ein oder andere Minute dauern kann.

413 Request Entity too Large

Wer beim Setup die Option "Use NGINX Conf Files" nicht ausgewählt hat, kann dies wie folgt nachholen:

Dazu muss in der Datei ".env" das Verarbeiten der Conf-Files folgende Zeile hinzugefügt werden:

USE_NGINX_CONF_FILES=true

Im Anschluss können im Ordner data/conf.d/ zusätzliche Konfigurations-Files hinterlegt werden, als Beispiel das Anpassen der "client_max_body_size" um die Uploadgrößen zu erhöhen und somit den Fehler 413 Request Entity too Large zu umgehen:

Datei: /data/conf.d/uploadsize.conf

client_max_body_size 100m;

Webservices

Die beschriebene Lösung kann dann zum Beispiel für den Betrieb anderer Websevices verwendet werden:

positive Bewertung({{pro_count}})
Beitrag bewerten:
{{percentage}} % positiv
negative Bewertung({{con_count}})

DANKE für deine Bewertung!


Top-Artikel in diesem Bereich

Preview ioBroker installieren - Docker

ioBroker installieren - Docker

geändert: 12.11.2020 von Bernhard (Erstveröffentlichung: 06.11.2020)

Mit ioBroker können verschiedene Automatisierungslösungen oder Geräte in einem System zusammengefasst werden. Um bestimmte Gateways oder Geräte ansprechen zu können, werden in ioBroker verschiedene Adapter verwendet.  ... weiterlesen

Preview Home-Assistant Docker Conbee 2 und Zigbee2MQTT / deCONZ

Home-Assistant Docker Conbee 2 und Zigbee2MQTT / deCONZ

geändert: 09.03.2022 von Bernhard (Erstveröffentlichung: 06.11.2020)

Dank zahlreicher Integrationsmöglichkeiten ist Home-Assistant eine einfache Plattform für das Steuern verschiedenster Smart-Home Geräte. Im Vergleich zu ioBroker ist mir der Start mit Home Assistant wesentlich einfacher gefallen. Während ich für ioBroker noch am Suchen war, welches Frontend ich für meine Dashboards verwenden könnte, hatte ich mit Home-Assistant Out of the box ein fertig eingerichtetes System. Die Lovelance Dashboards von Home Assistant können einfach in der GUI zusammengeklickt... ... weiterlesen

Bitwarden in Docker betreiben - Setup Schritt für Schritt

Bitwarden in Docker betreiben - Setup Schritt für Schritt

erstellt: 28.02.2022 von Bernhard

Bitwarden ist ein webbasierter Passwort-Manager, ähnlich LastPass, aber Open Source und der Möglichkeit diesen selbst zu betreiben (hosten). Wie sich Bitwarden im Vergleich zu anderen Passwortmanagern einordnet, habe ich auf folgender Seite überlegt: Passwortmanager sicher? KeePass vs. LastPass vs. Bitwarden. ... weiterlesen


Fragen / Kommentare


Durch die weitere Nutzung der Seite stimmst du der Verwendung von Cookies zu Mehr Details