Einleitung
Betreibt man einen Server mit mehreren Diensten, bietet es sich an einen Reverse-Proxy davor zuschalten. So kann man mit einer IP-Adresse viele Dienste auf dem selben Port laufen lassen. Die Unterscheidung erfolgt dann durch den FQDN. Zum Beispiel:
- www.example.com
- dokuwiki.example.com
- nextcloud.example.com
- ichhabsmirausgedacht.example.com
Der Reverse-Proxy kümmert sich dann bestenfalls auch um die TLS-Zertifikate, sodass man bei der Konfiguration der Dienste sich darum nicht mehr kümmern muss.
Die folgende Anleitung nutzt Traefik als reverse-Proxy und Let’s-Encrypt Wildcard-Zertifikate. So kann man schnell neue Services aufsetzen, ohne ein neues Zertifikat beantragen zu müssen. Zusammen mit einem Catchall-DNS Eintrag für die Domain kann man alle Einstellungen für einen neuen Service in dessen docker-compose.yml
vornehmen.
Um Wildcard-Zertifikate über LetsEncrypt zu beantragen muss man das DNS-01 Protokoll zu Verifikation nutzen. Dieses verlangt zwingend eine DNS-API mit derer man per automatisiert die DNS-Eintr?ge verwalten kann. Bietet der DNS-Server der Domain, für die das Wildcard-Zertifikat beantragt werden soll keine solche API kann mit Hilfe der CNAME-Validation auf einen zweiten DNS-Server mit DNS-API verwiesen werden.
Genau dieses Vorgehen beschreibe ich hier.
Voraussetzung
- Domain
netcuphosted.com
die auf Netcup (bietet DNS-API an) gehostet wird
- API-Zugangsdaten aus dem Customer-Controlpanel über?
Stammdaten
/?_Api
abzurufen bzw zu erzeugen:
API-Passwort
API-Key
Netcup-Kundennummer
- Praktisch w?re die TTL für die Zone
netcuphosted.com
im Customer-Controlpanel zumindest w?hrend der ersten Versuche deutlich herunterzusetzen (z.B: 120)
- DNS-Eintr?ge für?
nodnsapi.com
– Domain ohne?DNS-API
traefik.nodnsapi.com
- Entwerer als FQDN oder (besser) als Wildcard (
*.nodnsapi.com
),
- Kann ein
A-Record
oder CNAME
sein (zB: ein CNAME
auf den DynDNS)
_acme-challenge.nodnsapi.com CNAME acme.validation.netcuphosted.com
- Dieser CNAME Eintrag wird ben?tigt um die DNS-01 Validation auf den Netcup-DNS umzuleiten
Docker-Installation
Wenn Docker noch nicht installiert wurde hier eine Schnellanleitung
### Docker installieren ###
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
sudo apt update
apt-cache policy docker-ce
# > [es sollte auf das Docker-Repository zeigen]
# > ... https://download.docker.com/linux/ubuntu ...
sudo apt install docker-ce
# add user to Docker Group
sudo usermod -aG docker [myusername]
# install docker-compose
sudo apt install docker-compose
Traefik-Installation
Nun geht es an die eigentliche Installation von Traefik.
htpasswd
Zuerst braucht man htpasswd um den den PasswortHash zu erzeugen, den man sp?ter zur HTTP-AUTH-Anmeldung an dem Traefik-Dashboard ben?tigt:
# install htpasswd
sudo apt-get update
sudo apt-get install apache2-utils
# generate password
echo $(htpasswd -nb USER PASSWORD) | sed -e s/\\$/\\$\\$/g
# USER:$$apr1$$cC4LUELx$$6M4T7Y803yVXPM7lJo0Pp1
Die Ausgabe des letzten Befehls, wird sp?ter ben?tigt.
Verzeichnisse anlegen
Im Beispiel wird ein Ordner docker
im Home-Dir des Benutzers angelegt und darunter ein Order für jeden Service, den wir bereitstellen wollen. Traefik ist der erste Service:
cd ~
mkdir -p ~/docker/traefik
mkdir -p ~/docker/traefik/data
touch ~/docker/traefik/data/traefik.yml
touch ~/docker/traefik/data/dynamic_conf.yml
touch ~/docker/traefik/data/acme.json
chmod 600 ~/docker/traefik/data/acme.json
cd ~/docker/traefik
Jetzt die einzelnen Dateien editieren:
data/dynamic_conf.yml
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
http:
middlewares:
# secHeaders@file
# - Set Sameorigin
# - Set HSTS
# - enforce HTTPS
secHeaders:
headers:
browserXssFilter: true
contentTypeNosniff: true
customFrameOptionsValue: "SAMEORIGIN"
sslRedirect: true
#HSTS Configuration
#stsIncludeSubdomains: true
#stsPreload: true
#stsSeconds: 15552000
# redirect@file: Redirect HTTP -> HTTPS
redirect:
redirectScheme:
scheme: "https"
Folgendes sollte angepasst werden:
- Sie HSTS Konfiguration sollte erst ganz zum Schluss, wenn alles l?uft aktiviert werden
data/traefik.yml
log:
# DEBUG, PANIC, FATAL, ERROR, WARN, and INFO.
level: DEBUG
api:
dashboard: true
entryPoints:
http:
address: ":80"
https:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
filename: "/dynamic_conf.yml"
certificatesResolvers:
dns:
acme:
email: ############@############.##
storage: acme.json
keyType: RSA4096
# Production
# caServer: https://acme-v02.api.letsencrypt.org/directory
# Staging
caServer: https://acme-staging-v02.api.letsencrypt.org/directory
dnschallenge:
provider: netcup
delaybeforecheck: 300
resolvers:
- root-dns.netcup.net:53
- second-dns.netcup.net:53
- 8.8.8.8:53
- 1.1.1.1:53
Folgendes muss angepasst werden:
- E-Mail Adresse für die Let’s-Encrypt Beantragung
- Solange man noch experimentiert sollte der Staging-Server genutzt werden,
erst wenn alles funktioniert sollte man auf Production umstellen.
docker-compose.yml
version: '3'
services:
traefik:
image: traefik:latest
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- proxy
ports:
- 80:80
- 443:443
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme.json:/acme.json
- ./data/dynamic_conf.yml:/dynamic_conf.yml
environment:
# Wildcard-Cert for Domain without DNS-API
# - nodnsapi.com - DNS hosted by Server without DNS-API
# - netcuphosted.com - DNS hosted by Netcup-Nameserver with DNS-API
# Manual set the folowing DNS-CNAME Entry
# _acme-challenge.nodnsapi.com CNAME acme.validation.netcuphosted.com
- NETCUP_CUSTOMER_NUMBER=######
- NETCUP_API_KEY=##################################################
- NETCUP_API_PASSWORD=##################################################
- LEGO_EXPERIMENTAL_CNAME_SUPPORT=true
labels:
- "traefik.enable=true"
# --------------------------------------------------------
# INCLUDE: dynamic_conf.yml
# - redirect@file
# - secHeaders@file
- "providers.file.filename=/dynamic_conf.yml"
# --------------------------------------------------------
# Middleware: traefik-auth
# - generate Hash with: echo $(htpasswd -nb USER PASSWORD) | sed -e s/\\$/\\$\\$/g
- "traefik.http.middlewares.traefik-auth.basicauth.users=##########:$$apr1$$########$$######################"
# --------------------------------------------------------
#?Router?"traefik":?http://traefik.nodnsapi.com?->?Redirect?????
- "traefik.http.routers.traefik.entrypoints=http"
- "traefik.http.routers.traefik.rule=Host(`traefik.nodnsapi.com`)"
- "traefik.http.routers.traefik.middlewares=redirect@file"
# --------------------------------------------------------
#?Router?"traefik-secure":?https://traefik.nodnsapi.com?->?Traefik Dashboard
- "traefik.http.routers.traefik-secure.entrypoints=https"
- "traefik.http.routers.traefik-secure.rule=Host(`traefik.nodnsapi.com`)"
- "traefik.http.routers.traefik-secure.middlewares=traefik-auth,secHeaders@file"
- "traefik.http.routers.traefik-secure.tls=true"
- "traefik.http.routers.traefik-secure.service=api@internal"
# --------------------------------------------------------
#?Router?"whoami-secure":?To?get?Wildcard-Certs,?no?Service
-?"traefik.http.routers.whoami-secure.service=noop@internal"
- "traefik.http.routers.whoami-secure.tls.certResolver=dns"
- "traefik.http.routers.whoami-secure.tls.domains[0].main=*.${DOMAIN}"
# Activate this, if you also need a certificate for root Domain
# - "traefik.http.routers.whoami-secure.tls.domains[0].sans=${DOMAIN}"
# --------------------------------------------------------
networks:
proxy:
external: true
Folgendes muss angepasst werden:
NETCUP_CUSTOMER_NUMBER
NETCUP_API_KEY
NETCUP_API_PASSWORD
- Die Ausgabe von
echo $(htpasswd -nb USER PASSWORD) | sed -e s/\\$/\\$\\$/g
in traefik.http.middlewares.traefik-auth.basicauth.users
- Die Domain für den Server in
traefik.http.routers.traefik.rule=Host(`traefik.nodnsapi.com`)
traefik.http.routers.traefik-secure.rule=Host(`traefik.nodnsapi.com`)
traefik.http.routers.whoami-secure.tls.domains[0].main=*.nodnsapi.com"
- Sofern man auch die Domain nodnsapi.com nutzen m?chte die Zeile
traefik.http.routers.whoami-secure.tls.domains[0].sans=nodnsapi.com"
Docker Netzwerk anlegen
Jetzt noch das Proxy-Netzwerk anlegen
docker network create proxy
Traefik starten
Wir starten das Traefik zum ersten Mal ohne -d
, dann k?nnen wir das Log durchlaufen lassen und mit CTRL-C
beenden.
docker-compose up -d
Hinweise:
- Das Erstellung des Wildcard-Zertifikats dauert immer eine Zeit, da zuerst der DNS-Eintrag angelegt wird und dann
delaybeforecheck
Sekunden gewartet wird, dass dieser durchs Netz propagiert wurde. 5 Minuten funktionieren hier wohl sehr gut. Wenn man die TTL ge?ndert hat, geht es eventuell auch schneller.
- Beim Experimentieren sollte der Container immer mal wieder gel?scht werden
(docker-compose rm
)
- Die Zertifikate kann man sich in der Datei
data/adme.json
ansehen und ggf l?schen, falls man eine Neuerstellung antriggern will.
Test
Um zu Testen, ob alles geklappt hat, dann man sich nun mit dem Traefik-Dashboard verbinden, welches unter
https://traefik.nodnsapi.com
erreichbar sein sollte. (Username und Passwort wurden oben erzeugt)
Jetzt wird man eine Zertifikats-Fehlermeldung bekommen, da das Root-Zertifikat der Staging-CA nicht im Browser hinterlegt ist. Ich habe die CA als vertrauenswürdiges Root-Zertifikat in meinem Chrome hinterlegt. Wer das nachmacht, sollte hinterher nicht vergessen, dieses nach den Tests wieder zu entfernen.
Wechsel auf Production-CA
Sofern die Tests erfolgreich verlaufen sind, kann man das System auf die Produktive CA umstellen. Dazu:
- Container anhalten
docker-compose down
- Container l?schen
docker-compose rm
- Inhalt von
data/adme.json
l?schen
rm ~/docker/traefik/data/acme.json
touch ~/docker/traefik/data/acme.json
chmod 600 ~/docker/traefik/data/acme.json
- HSTS aktivieren (in
dynamic_conf.yml
)
- Logging auf
ERROR
stellen (in data/traefik.yml
)
- Auf die Produktive CA umstellen (in
data/traefik.yml
)
caServer: https://acme-02.api.letsencrypt.org/directory
#caServer: https://acme-staging-v02.api.letsencrypt.org/directory
- Container neu bauen und starten
docker-compose up -d
- Zertifikat der Staging-CA aus
vertrauenswürdige Root-Zertifikate
des Browsers entfernen.