Wem Traefik zu kompliziert ist, findet mit Caddy und Caddyfile eine einfachere Lösung, um Docker-Images unter einer Domain zu binden. Damit hat man eine saubere Trennung zwischen den Containern und dieser Traefik-Verwaltung.
Bei GNU/Linux.ch gibt es die Möglichkeit, Artikelvorschläge einzureichen. Vor einiger Zeit habe ich dort diesen Vorschlag gepostet:
Jetzt habe ich eine viel einfachere Methode entdeckt, um meine Docker-Images unter einer Domain oder mehreren zu binden. Da ich Traefik zu kompliziert finde, da man an jedem Docker-Image Traefik-spezifische Zeilen hinzufügen muss, was man bei Caddyfile nicht machen muss. Somit hat man eine saubere Trennung zwischen dem Container und dieser Traeffic-Verwaltung.
Nun habe ich zu meinem Artikelvorschlag selbst einen Artikel geschrieben.
Caddy image
Dieses Image managed alle TLS-Abfragen automatisch. Dabei kann man verschiedene Varianten wählen:
- Let's Encrypted (Default)
- Self-Signed-Key
- DuckDNS (Um keine Portweiterleitung von Port 80/443 haben zu müssen)
Alle, die sich das erst auf Docker Hub anschauen möchten: Hub-Docker.
Vollständige Ordnerstrucktur
Daraus resultiert folgende Ordnerstruktur (in alter Manier: tree-output):
/ Domainname
├ docker-compose.yml
├ Caddyfile
├ / caddy_data
│ └ ...
└ / caddy_config
└ ...
Hier noch einige One-Liner zur Erstellung der Ordnerstruktur und der zwei Dateien:
# Ordner kurze Schreibweise (Flavor 01)
mkdir -p domainname/{caddy_data,caddy_config}
# Ordner lange Schreibweise (Flavor 02)
mkdir -p domainname/caddy_data domainname/caddy_config
# Dateien
touch domainname/docker-compose.yml domainname/Caddyfile
Konfigurationsdatei Caddyfile
Die Struktur ist sehr einfach gehalten.
# domain.de abändern in die gewünschte Adresse
domain.de {
# Zugriff beschränken
@allowed_ip {
# Ganze lokales Netzwerk zugriff geben
remote_ip 192.168.0.0/24
# Einzelne IP zugriff gewähren
remote_ip 192.168.0.1
# Oder falls es eine öffentliche IP sein soll
# dann diese eintragen. Ist es eine wechselnde öffentliche IP,
# dann immer vorher anpassen, bevor der Container gestartet wird!
}
# Richtige IP klopft an, dann weiter reichen an Webserver - Docker Container
handle @allow_ip {
reverse_proxy dockerName:dockerPort {
# Wenn man verschleiern möchte, dass man einen alten
# apache2 oder nginx Webserver nutzt.
header_down -Server
}
}
# Alle anderen IP's die nicht in der Liste stehen, landen hier:
handle {
respond "Access denied! (Forbidden - 403)" 403
}
# Falls der Service nicht läuft kann man eine eindeutige Nachricht geben:
handle_errors {
@unavailable expression `{err.status_code} >= 500`
respond @unavailable "Sorry, the website is currently unavailable due to maintenance. Please try again later." 503
}
# komprimierter Aufruf
encode gzip
# Fake Webserver Informationen zeigen
header {
-Server
Server "Web-Server-Name Versionsnummer"
Strict-Transport-Security "max-age=31536000;"
}
}
Dies wäre eine mögliche Konfiguration für eine Let's Encrypted Variante.
Konfigurationsdatei Docker-compose Yaml
caddy:
image: caddy:latest
restart: always
ports:
# HOST_PORT:DOCKER_PORT
# Sollten Ports schon verwendet werden, dann 80 in 8080
# das selbe mit dem SSL-Port 443 in 8443
#- "80:80"
- "8080:80"
#- "443:443"
- "8443:443"
volumes:
# Caddyfile neben der docker-compose.yml Datei
- ./Caddyfile:/etc/caddy/Caddyfile
# Einen Ordner 'caddy_data' neben der docker-compse.yml Datei
- ./caddy_data:/data
# Einen weiteren Ordner 'caddy_config' neben der docker-compose.yml Datei
- ./caddy_config:/config
networks:
- caddy_net
# Achtung: Sicherheitsrisiko! Steht nur hier als Vervollständigung
#extra_hosts:
# Ermöglicht Zugriff auf lokale Netzgeräte vom Container aus
# - "host.docker.internal:host-gateway"
networks:
caddy_net:
driver: bridge
Möchte man hingegen einen Self-Sign-Key verwenden
Dann muss im Caddyfile ganz oben stehen mit folgenden Parametern. (Es gibt noch andere Parameter, die man definieren kann. Diese können von folgender Webseite Caddyserver.com/docs/... geholt werden).:
{
# TLS options
#auto_https off|disable_redirects|ignore_loaded_certs|disable_certs
#email example@mydomain.de
local_certs
tls internal
#key_type ed25519|p256|p384|rsa2048|rsa4096
# Neu erzeugen nach 90 Tagen sind 129600 Minuten ( 60 Minuten * 24 Stunden * 90 Tage )
#renew_interval 129600m
}
Möchte man DuckDNS verwenden, benötigt man ein Konto bei DuckDNS
Folgendes Docker-Image ist nötig caddy-dns/duckdns und in der Caddyfile Datei muss folgendes stehen im globalen Bereich tls { dns duckdns DEIN_DUCKDNS_TOKEN } und folgender Eintrag darf in der docker-compose.yml auch nicht fehlen:
caddy:
# Wichtig, da ansonsten das Plugin fehlt, was gebraucht wird für DuckDNS
image: caddy-dns/duckdns
...
environment:
- DUCKDNS_TOKEN=DEIN_DUCKDNS_TOKEN
...
Dieses DuckDNS kann man nutzen, wenn man HTTPS verwenden möchte, ohne den NAG-Screen "Sicherheitsrisiko - Diese Webseite nutzt ein selbst erstelltes Zertifikat... Vertrauen?"
Dann noch ein Eintrag in die /etc/hosts Datei, um deine Domain bekannt zu machen.
# Wenn es nur lokal auf deinem Rechner laufen soll
127.0.0.1 domainname.de subdomain.domainname.de andererdomainname.de
# Ansonsten deine Netzwerk IP-Adresse nutzen
192.168.0.1 domainname.de subdomain.domainname.de andererdomainname.de
Hinweis für die Nutzung von Docker und podman
Bei Docker kann man die Namensgebung von der docker-compose.yml Datei als Hostnamen verwenden. Mit podyman als Docker-Image-Starter muss man die IP-Adresse verwenden, ganz wichtig, weil podyman keinen internen DNS-Handler besitzt, um die Namensauflösung zu steuern. Außerdem sei zu podyman zu sagen, dass es rootless (ohne Administratoren-Rechte) arbeitet, also muss man darauf achten, dass man die richtigen Docker-Images (rootless unterstützen) auswählt. Ansonsten wundert man sich über Fehlermeldungen, die man hätte im Vorfeld vermeiden können.
Weiterer Hinweis für das Anschauen der Logs innerhalb von containern
Mit folgendem Befehl kann man sich die Log-History ansehen, ob fehlerhafte Einträge in der Konfiguration sind oder andere nützliche Hinweise, die man vorher nicht gesehen hat.
# Neuste Docker Version
docker compose logs dockername
# Ältere Docker Version müssen folgendes eingeben:
docker-compose logs dockername
Fazit
Meiner Meinung nach ist Caddy ein viel einfacheres Tool als Traefik, da man nur einmal konfigurieren muss. Bei Traefik muss man bei jedem einzelnen Container immer 3-5 Zeilen extra hinzufügen, damit Traefik weiss, wie es damit umzugehen hat.
Titelbild: https://cdn.hackersandslackers.com/2019/03/caddy.jpg
Quellen:
[1] https://hub.docker.com/_/caddy - Docker Image
[2] https://caddyserver.com/docs/caddyfile/options - Caddyfile TLS Optionen Erklärungen
[3] https://caddyserver.com/docs/caddyfile - Allgemeine Konfigurationen

