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:
+14
-2
@@ -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,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
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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
+69
-13
@@ -4,26 +4,82 @@ 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
|
||||||
echo "[entrypoint] Kein Zertifikat unter $CERT_DIR gefunden - erstelle neues, 100 Jahre gueltiges Zertifikat fuer CN=$CN ..."
|
# 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."
|
||||||
|
|
||||||
openssl req -x509 -nodes -newkey rsa:4096 -sha256 \
|
cat > "$CADDYFILE" <<EOF
|
||||||
-days 36500 \
|
{
|
||||||
-keyout "$KEY_FILE" \
|
email ${LETSENCRYPT_EMAIL}
|
||||||
-out "$CERT_FILE" \
|
}
|
||||||
-subj "/C=DE/ST=Niedersachsen/L=Oldenburg/O=HackerSoft/CN=${CN}" \
|
|
||||||
-addext "subjectAltName=DNS:${CN},DNS:localhost,IP:127.0.0.1"
|
|
||||||
|
|
||||||
chmod 600 "$KEY_FILE"
|
${DOMAIN} {
|
||||||
chmod 644 "$CERT_FILE"
|
reverse_proxy baikal:80
|
||||||
|
|
||||||
|
encode gzip
|
||||||
|
log {
|
||||||
|
output stdout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
echo "[entrypoint] Zertifikat erstellt (gueltig fuer 36500 Tage / 100 Jahre)."
|
|
||||||
else
|
else
|
||||||
echo "[entrypoint] Bestehendes Zertifikat in $CERT_DIR gefunden, wird weiterverwendet."
|
# 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 ..."
|
||||||
|
|
||||||
|
openssl req -x509 -nodes -newkey rsa:4096 -sha256 \
|
||||||
|
-days 36500 \
|
||||||
|
-keyout "$KEY_FILE" \
|
||||||
|
-out "$CERT_FILE" \
|
||||||
|
-subj "/C=DE/ST=Niedersachsen/L=Oldenburg/O=HackerSoft/CN=${CN}" \
|
||||||
|
-addext "subjectAltName=DNS:${CN},DNS:localhost,IP:127.0.0.1"
|
||||||
|
|
||||||
|
chmod 600 "$KEY_FILE"
|
||||||
|
chmod 644 "$CERT_FILE"
|
||||||
|
|
||||||
|
echo "[entrypoint] Zertifikat erstellt (gueltig fuer 36500 Tage / 100 Jahre)."
|
||||||
|
else
|
||||||
|
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
|
||||||
|
|||||||
+13
-9
@@ -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:
|
|
||||||
|
|||||||
Reference in New Issue
Block a user