Ich habe zuhause zwei Caddy-Instanzen als Reverse-Proxy laufen - einer als Proxy für Traffic von außen (via RZ), einer als Proxy für Traffic innerhalb vom Netzwerk.

Ich nutze eine interne Domain (home.local - ja, ich weiß, .internal wäre besser) für die Dienste, die nicht über das Internet aufrufbar sind. Dafür habe ich auch einen lokalen DNS-Server, der diese Zone bereitstellt.

Was noch fehlte war HTTPS für die internen Dienste, Lets Encrypt oder ähnliches ist dort nicht nutzbar.

Step-CA

Step-CA ist eine selbst betreibbare Zertifizierungsstelle, die u.a. ACME kann. ACME ist das selbe “Protokoll”, was auch Lets Encrypt zur Verifizierung von Hosts und der Ausstellung von Zertifikaten benutzt. Das ganze ist ziemlich flott eingerichtet und lässt sich dann simpel an Clients wie Certbot oder auch Caddy anbinden und damit automatisch Zertifikate ausstellen. Das einzige manuelle ist, dass man auf allen Computern (und Smartphones und co), die diese lokalen Dienste nutzen sollen, natürlich das Root-Zertifikat der Step-CA installieren muss, damit die Zertifikate auch akzeptiert werden.

Meine Docker-Compose dafür sieht sehr simpel aus:

services:
  step-ca:
    image: smallstep/step-ca
    restart: always
    ports:
      - 9443:9443
    volumes:
      - ./data:/home/step

Vor dem ersten Start muss die CA noch initialisiert werden. Dazu muss das Datenverzeichnis erstellt und die Berechtigungen angepasst werden:

mkdir data
chown -R 1000:1000 data/
docker run --rm -it -v "./data/:/home/step/" smallstep/step-ca step ca init

Der Assistent führt einen nun durch die notwendigen Schritte. Dann muss noch ein Secret angelegt werden:

echo blub | tee "data/secrets/password"
chown 1000:1000 data/secrets/password

Jetzt kann die CA schon gestartet werden und danach ACME aktiviert werden:

docker compose up -d
# kurz warten
docker compose exec step-ca step ca provisioner add acme --type ACME
docker compose restart

Das Root-CA, was auf den Clients verteilt werden muss, befindet sich unter data/certs/root_ca.crt.

Caddy

Die CA kann nun also Zertifikate ausstellen und muss nur noch an Caddy angebunden werden. Eine globale CA in der Caddyfile lässt sich dafür leider nicht nutzen, dieser Mechanismus ist laut Dokumentation von Caddy nicht für interne Domains freigegeben bzw. funktioniert damit nicht. Daher habe ich die für die lokale CA notwendige Konfiguration als Snippet angelegt:

(local-ca) {
        tls me@example.com {
                ca https://stepca.home.local:9443/acme/acme/directory
                ca_root /etc/caddy/root_ca.crt
        }
}

Das Root-CA habe ich, wie in der Config sichtbar, unter /etc/caddy/root_ca.crt abgelegt.

Nun lassen sich Reverse-Proxy-Hosts anlegen, die dieses Snippet verwenden und damit automatisch Zertifikate einrichten:

# Stirling-PDF
pdf.apps.home.local {
        import local-ca
        reverse_proxy http://192.168.104.46:8081
}

Oder im Falle von Proxmox vorerst mit Ignorieren der Korrektheit des vom PVE-Hosts genutzten Zertifikates (solange, bis ich bei PVE ACME mit der lokalen CA noch nicht eingerichtet habe):

# Proxmox
pve.apps.home.local {
        import local-ca
        reverse_proxy https://192.168.103.2:8006 {
        transport http {
                tls
                tls_insecure_skip_verify
        }
    }
}

Das sieht in Fertig im Browser dann so aus: Proxmox via lokalem Caddy mit internem Zertifikat

Windows

Damit Windows diesem Zertifikat vertraut, muss das CA noch installiert werden. Dazu reicht es, die .ca-Datei mit Doppelklick zu öffnen und zu installieren. Danach muss das Zertifikat noch als Vertrauenswürdig eingestuft werden. Dazu kann man im Startmenü nach “Zertifikat” suchen und - je nachdem, wie man es installiert hat - die Verwaltung für Benutzer- oder Computerzertifikate öffnen. Das neue Zertifikat liegt dann wahrscheinlich unter Zwischenzertifizierungsstellen/Zertifikat und muss nur noch zu Vertrauenswürdige Stammzertifizierungsstellen/Zertifikate verschoben werden. Nach einem Neustart vom Browser sollte der Aufruf lokaler Subdomains mit SSL nun fehlerfrei funktionieren.