Let's Encrypt Support: DOMAIN+LETSENCRYPT_EMAIL in .env aktivieren echtes Zertifikat

- caddy/entrypoint.sh generiert Caddyfile jetzt dynamisch: sind DOMAIN und
  LETSENCRYPT_EMAIL gesetzt, holt Caddy automatisch ein Let's-Encrypt-Zertifikat;
  sonst Fallback auf das bisherige selbstsignierte 100-Jahres-Zertifikat.
- .env.example um DOMAIN/LETSENCRYPT_EMAIL ergaenzt (auskommentiert), inkl. Erklaerung.
- Caddy /data und /config (ACME-Cache) jetzt unter ./daten gebind-mounted statt
  Named Volumes, damit ein einzelner Ordner fuer Backup/Umzug reicht.
- statische Caddyfile entfernt (wird zur Laufzeit erzeugt), README entsprechend
  um beide Zertifikats-Modi erweitert.
This commit is contained in:
ARIA
2026-07-20 20:20:49 +00:00
parent 0b6acbb874
commit 4dfcc3303f
8 changed files with 140 additions and 65 deletions
+14 -2
View File
@@ -1,3 +1,15 @@
# Hostname/IP fuer das selbstsignierte 100-Jahres-Zertifikat (CN + SAN). # --- Let's Encrypt (echtes, oeffentlich vertrauenswuerdiges Zertifikat) ---
# Nach dem ersten Start nur wirksam, wenn daten/caddy_certs vorher geleert wird. # Werden BEIDE Felder ausgefuellt, fordert Caddy beim Start automatisch ein
# Let's-Encrypt-Zertifikat fuer DOMAIN an (und erneuert es danach selbst).
# Voraussetzung: DOMAIN zeigt per DNS-A/AAAA-Record auf diesen Host, Port 80
# UND 443 sind aus dem Internet erreichbar (HTTP-01 Challenge).
#
# DOMAIN=baikal.meine-domain.de
# LETSENCRYPT_EMAIL=ich@meine-domain.de
# --- Fallback: selbstsigniertes 100-Jahres-Zertifikat ---
# Wird automatisch genutzt (bzw. beim ersten Start erzeugt), wenn DOMAIN
# und/oder LETSENCRYPT_EMAIL oben LEER bleiben. Bereits vorhandenes
# Zertifikat unter daten/caddy_certs wird dabei nicht ueberschrieben.
# CADDY_CERT_CN steuert nur CN/SAN dieses selbstsignierten Zertifikats.
CADDY_CERT_CN=baikal.local CADDY_CERT_CN=baikal.local
+2
View File
@@ -2,6 +2,8 @@
daten/config/* daten/config/*
daten/data/* daten/data/*
daten/caddy_certs/* daten/caddy_certs/*
daten/caddy_data/*
daten/caddy_config/*
!daten/**/.gitkeep !daten/**/.gitkeep
.env .env
-24
View File
@@ -1,24 +0,0 @@
# Caddyfile fuer den Baikal CalDAV/CardDAV Server
#
# auto_https wird global abgeschaltet, weil wir selbst ein Zertifikat
# bereitstellen (siehe caddy/entrypoint.sh) statt Caddy per ACME/Let's
# Encrypt bzw. seiner internen CA (kurzlebige Zertifikate) machen zu lassen.
{
auto_https off
}
:443 {
tls /certs/baikal.crt /certs/baikal.key
reverse_proxy baikal:80
encode gzip
log {
output stdout
}
}
:80 {
# Reiner HTTP->HTTPS Redirect
redir https://{host}{uri} permanent
}
+42 -17
View File
@@ -16,36 +16,60 @@ Alle persistenten Daten liegen im Projektverzeichnis unter `./daten`:
daten/ daten/
config/ Baikal-Konfiguration (Setup, Admin-Login, DB-Settings) config/ Baikal-Konfiguration (Setup, Admin-Login, DB-Settings)
data/ Baikal-Nutzdaten (Kalender, Adressbuecher, SQLite-DB) data/ Baikal-Nutzdaten (Kalender, Adressbuecher, SQLite-DB)
caddy_certs/ Selbstsigniertes TLS-Zertifikat (baikal.crt / baikal.key) caddy_certs/ Selbstsigniertes TLS-Zertifikat (nur Fallback-Modus, s.u.)
caddy_data/ Let's-Encrypt-Zertifikatscache (nur Let's-Encrypt-Modus)
caddy_config/ Caddy Runtime-Config-Autosave
``` ```
`daten/` ist damit der einzige Ordner, den man fuer Backups sichern bzw. bei `daten/` ist damit der einzige Ordner, den man fuer Backups sichern bzw. bei
einem Umzug/Redeploy 1:1 mitnehmen muss. einem Umzug/Redeploy 1:1 mitnehmen muss.
## TLS-Zertifikat (100 Jahre, automatisch) ## TLS-Zertifikat (Let's Encrypt oder 100 Jahre selbstsigniert, automatisch)
Der Caddy-Container hat einen eigenen Entrypoint Der Caddy-Container hat einen eigenen Entrypoint (`caddy/entrypoint.sh`), der
(`caddy/entrypoint.sh`): Beim Start prueft er, ob unter das `Caddyfile` bei JEDEM Start dynamisch erzeugt — abhaengig davon, ob in
`daten/caddy_certs/baikal.crt` + `baikal.key` bereits ein Zertifikat liegt. `.env` eine Domain + Email fuer Let's Encrypt hinterlegt sind:
- **Nicht vorhanden** -> es wird automatisch ein neues, selbstsigniertes ### Modus 1 — Let's Encrypt (echtes Zertifikat)
Zertifikat per `openssl` erzeugt, gueltig fuer **36500 Tage (100 Jahre)**.
- **Vorhanden** -> wird unveraendert weiterverwendet (kein Ueberschreiben bei
jedem Neustart).
Caddys eingebautes automatisches HTTPS (ACME / interne CA mit kurzlebigen Werden **beide** Variablen `DOMAIN` und `LETSENCRYPT_EMAIL` in `.env`
Zertifikaten) ist im `Caddyfile` bewusst per `auto_https off` deaktiviert — ausgefuellt, fordert Caddy automatisch ein echtes, oeffentlich
stattdessen wird das selbst erzeugte Langzeit-Zertifikat direkt referenziert. vertrauenswuerdiges Let's-Encrypt-Zertifikat fuer `DOMAIN` an und erneuert es
danach von selbst (Caddys eingebautes automatisches HTTPS).
Voraussetzungen:
- `DOMAIN` zeigt per DNS (A/AAAA-Record) auf diesen Host.
- Port `80` UND `443` sind aus dem Internet erreichbar (HTTP-01 Challenge).
```bash
cp .env.example .env
# .env bearbeiten:
# DOMAIN=baikal.meine-domain.de
# LETSENCRYPT_EMAIL=ich@meine-domain.de
```
### Modus 2 — Fallback: selbstsigniertes 100-Jahres-Zertifikat
Bleibt `DOMAIN` oder `LETSENCRYPT_EMAIL` leer (Default, z.B. bei reiner
LAN/IP-Nutzung ohne oeffentliche Erreichbarkeit), nutzt der Entrypoint
automatisch ein selbstsigniertes Zertifikat:
- **Noch keins vorhanden** unter `daten/caddy_certs/baikal.crt` +
`baikal.key` -> es wird automatisch per `openssl` neu erzeugt, gueltig fuer
**36500 Tage (100 Jahre)**.
- **Bereits vorhanden** -> wird unveraendert weiterverwendet (kein
Ueberschreiben bei jedem Neustart).
Da es sich um ein selbstsigniertes Zertifikat handelt, werden CalDAV/CardDAV- Da es sich um ein selbstsigniertes Zertifikat handelt, werden CalDAV/CardDAV-
Clients (Browser, Thunderbird, DAVx5, iOS/macOS Kalender-App, ...) beim ersten Clients (Browser, Thunderbird, DAVx5, iOS/macOS Kalender-App, ...) beim ersten
Verbinden eine Zertifikatswarnung anzeigen. Das Zertifikat muss dort einmalig Verbinden eine Zertifikatswarnung anzeigen. Das Zertifikat muss dort einmalig
als vertrauenswuerdig akzeptiert bzw. importiert werden. als vertrauenswuerdig akzeptiert bzw. importiert werden. Bei Modus 1 (Let's
Encrypt) entfaellt diese Warnung, da das Zertifikat echt ist.
### Hostname/CN anpassen ### Hostname/CN des selbstsignierten Zertifikats anpassen
Der Common Name (CN) und SAN-Eintrag des Zertifikats werden ueber die Nur relevant fuer Modus 2. Der Common Name (CN) und SAN-Eintrag werden ueber
Umgebungsvariable `CADDY_CERT_CN` gesteuert (Default: `baikal.local`). die Umgebungsvariable `CADDY_CERT_CN` gesteuert (Default: `baikal.local`).
Eigene Domain/IP setzen, bevor der Container zum ersten Mal hochfaehrt (das Eigene Domain/IP setzen, bevor der Container zum ersten Mal hochfaehrt (das
Zertifikat wird nur EINMAL erzeugt — danach `daten/caddy_certs` loeschen und Zertifikat wird nur EINMAL erzeugt — danach `daten/caddy_certs` loeschen und
@@ -95,4 +119,5 @@ docker compose up -d --build
``` ```
Beim naechsten Start wird automatisch ein neues 100-Jahres-Zertifikat mit dem Beim naechsten Start wird automatisch ein neues 100-Jahres-Zertifikat mit dem
aktuellen `CADDY_CERT_CN` erzeugt. aktuellen `CADDY_CERT_CN` erzeugt (nur relevant im Fallback-Modus 2, siehe
oben — bei aktivem Let's Encrypt kuemmert sich Caddy selbst um Erneuerung).
Regular → Executable
+59 -3
View File
@@ -4,11 +4,43 @@ set -e
CERT_DIR="/certs" CERT_DIR="/certs"
CERT_FILE="$CERT_DIR/baikal.crt" CERT_FILE="$CERT_DIR/baikal.crt"
KEY_FILE="$CERT_DIR/baikal.key" KEY_FILE="$CERT_DIR/baikal.key"
CADDYFILE="/etc/caddy/Caddyfile"
DOMAIN="${DOMAIN:-}"
LETSENCRYPT_EMAIL="${LETSENCRYPT_EMAIL:-}"
CN="${CADDY_CERT_CN:-baikal.local}" CN="${CADDY_CERT_CN:-baikal.local}"
mkdir -p "$CERT_DIR" mkdir -p "$CERT_DIR"
if [ ! -f "$CERT_FILE" ] || [ ! -f "$KEY_FILE" ]; then if [ -n "$DOMAIN" ] && [ -n "$LETSENCRYPT_EMAIL" ]; then
# DOMAIN + LETSENCRYPT_EMAIL gesetzt -> echtes, oeffentlich vertrauenswuerdiges
# Zertifikat ueber Caddys eingebautes automatisches HTTPS (Let's Encrypt).
# Voraussetzung: DOMAIN zeigt per DNS auf diesen Host, Port 80+443 sind von
# aussen erreichbar (HTTP-01 Challenge).
echo "[entrypoint] DOMAIN=$DOMAIN und LETSENCRYPT_EMAIL=$LETSENCRYPT_EMAIL gesetzt - hole/verwalte Zertifikat automatisch ueber Let's Encrypt."
cat > "$CADDYFILE" <<EOF
{
email ${LETSENCRYPT_EMAIL}
}
${DOMAIN} {
reverse_proxy baikal:80
encode gzip
log {
output stdout
}
}
EOF
else
# DOMAIN/LETSENCRYPT_EMAIL nicht (vollstaendig) gesetzt -> Fallback auf
# selbstsigniertes Langzeit-Zertifikat (100 Jahre), einmalig erzeugt und
# danach unter daten/caddy_certs persistiert/weiterverwendet.
echo "[entrypoint] DOMAIN/LETSENCRYPT_EMAIL nicht gesetzt - nutze selbstsigniertes 100-Jahres-Zertifikat (CN=$CN)."
if [ ! -f "$CERT_FILE" ] || [ ! -f "$KEY_FILE" ]; then
echo "[entrypoint] Kein Zertifikat unter $CERT_DIR gefunden - erstelle neues, 100 Jahre gueltiges Zertifikat fuer CN=$CN ..." echo "[entrypoint] Kein Zertifikat unter $CERT_DIR gefunden - erstelle neues, 100 Jahre gueltiges Zertifikat fuer CN=$CN ..."
openssl req -x509 -nodes -newkey rsa:4096 -sha256 \ openssl req -x509 -nodes -newkey rsa:4096 -sha256 \
@@ -22,8 +54,32 @@ if [ ! -f "$CERT_FILE" ] || [ ! -f "$KEY_FILE" ]; then
chmod 644 "$CERT_FILE" chmod 644 "$CERT_FILE"
echo "[entrypoint] Zertifikat erstellt (gueltig fuer 36500 Tage / 100 Jahre)." echo "[entrypoint] Zertifikat erstellt (gueltig fuer 36500 Tage / 100 Jahre)."
else else
echo "[entrypoint] Bestehendes Zertifikat in $CERT_DIR gefunden, wird weiterverwendet." echo "[entrypoint] Bestehendes Zertifikat in $CERT_DIR gefunden, wird weiterverwendet."
fi
cat > "$CADDYFILE" <<EOF
{
auto_https off
}
:443 {
tls ${CERT_FILE} ${KEY_FILE}
reverse_proxy baikal:80
encode gzip
log {
output stdout
}
}
:80 {
# Reiner HTTP->HTTPS Redirect
redir https://{host}{uri} permanent
}
EOF
fi fi
exec caddy run --config /etc/caddy/Caddyfile --adapter caddyfile exec caddy run --config "$CADDYFILE" --adapter caddyfile
View File
View File
+13 -9
View File
@@ -22,17 +22,25 @@ services:
container_name: baikal_caddy container_name: baikal_caddy
restart: unless-stopped restart: unless-stopped
environment: environment:
# Hostname/CN fuer das selbstsignierte 100-Jahres-Zertifikat. # Hostname/CN fuer das selbstsignierte 100-Jahres-Zertifikat (Fallback,
# Bei Bedarf auf die tatsaechliche Domain/IP anpassen. # nur relevant wenn DOMAIN/LETSENCRYPT_EMAIL NICHT gesetzt sind).
- CADDY_CERT_CN=${CADDY_CERT_CN:-baikal.local} - CADDY_CERT_CN=${CADDY_CERT_CN:-baikal.local}
# Domain + Kontakt-Email fuer ein echtes Let's Encrypt Zertifikat.
# Sind BEIDE gesetzt, holt/verwaltet Caddy automatisch ein Let's-Encrypt-
# Zertifikat fuer DOMAIN. Ist eines von beiden leer, faellt der
# Entrypoint auf das selbstsignierte 100-Jahres-Zertifikat zurueck.
- DOMAIN=${DOMAIN:-}
- LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL:-}
ports: ports:
- "80:80" - "80:80"
- "443:443" - "443:443"
volumes: volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./daten/caddy_certs:/certs - ./daten/caddy_certs:/certs
- caddy_data:/data # /data enthaelt u.a. den Let's-Encrypt-Zertifikatscache (Modus 1),
- caddy_config:/config # /config Caddys Runtime-Config-Autosave. Beides unter ./daten, damit
# dieser eine Ordner fuer beide Zertifikats-Modi ausreicht (Backup/Umzug).
- ./daten/caddy_data:/data
- ./daten/caddy_config:/config
depends_on: depends_on:
- baikal - baikal
networks: networks:
@@ -40,7 +48,3 @@ services:
networks: networks:
baikal_net: baikal_net:
volumes:
caddy_data:
caddy_config: