diff --git a/caddy-bunny.md b/caddy-bunny.md new file mode 100644 index 0000000..c2f6ea1 --- /dev/null +++ b/caddy-bunny.md @@ -0,0 +1,114 @@ +# Plan: Ny Caddy-lösning med Bunny.net (Docker + dynamisk IP + cert-hantering) + +## Mål +- Klona nuvarande `caddy`-repo till ett nytt repo för den nya lösningen och fortsätta arbetet där. +- Behålla fungerande reverse proxy-installation (nuvarande Caddyfile-routing). +- Köra Caddy i Docker med en **custom build** som innehåller Bunny.net-stöd. +- Låta Caddy uppdatera DNS mot Bunny.net när publik IP ändras (dynamisk IP). +- Säkerställa att Let’s Encrypt-certifikat fortsatt hanteras/uppdateras av Caddy. +- Lägga till ett cron-script som reagerar på IP-byte (t.ex. efter router-omstart) och triggar cert-/TLS-verifieringsflöde. + +## Inventerat nuläge (från befintligt repo) +- `compose.yml` använder `caddy:2.6.4`, portar `80/443`, volymer för `/etc/caddy`, `/data`, `/config`, samt externt Docker-nätverk `proxy`. +- Aktiv `Caddyfile` har snippets `(auth)` och `(common)` och ett antal domäner, bl.a.: + - `test.gynther.se`, `nzbget.gynther.se`, `prowlarr.gynther.se`, `radarr.gynther.se`, `sonarr.gynther.se`, `jellyfin.gynther.se`, `qbittorrent.gynther.se`, `wetty.gynther.se`, `gitea.gynther.se`, `import.gynther.se`, `recept.gynther.se`. +- `recept.gynther.se` har ordningskänsliga `handle`-regler där import- och API-rutter måste ligga före catch-all. +- Nuläget saknar Bunny.net DNS-modul, dynamisk DNS-app och cron-automation för IP-byte. + +## Teknisk målarkitektur +1. **Nytt repo (arbetsrepo)** + - Klona nuvarande repo till nytt katalognamn (t.ex. `caddy-bunny`) och koppla till nytt remote-repo. + - Arbeta endast i nya repot. + +2. **Custom Caddy-image i Docker** + - Bygg Caddy med `xcaddy` och moduler: + - `github.com/caddy-dns/bunny` (DNS provider för ACME DNS-01) + - `github.com/mholt/caddy-dynamicdns` (uppdaterar A/AAAA vid IP-byte) + - Köra denna image via `compose.yml` (`build:` eller pinned custom image-tag). + +3. **Caddyfile med globala DNS-/ACME-inställningar** + - Införa global options-block med Bunny API-nyckel via env-variabel. + - Aktivera ACME DNS challenge med Bunny (`acme_dns bunny {env.BUNNY_API_KEY}`). + - Behålla befintliga site-block/routing oförändrade i funktion. + +4. **Dynamisk DNS i Caddy** + - Konfigurera `dynamic_dns` globalt för zonen (ex. `gynther.se`) och relevanta hostnames. + - Check-interval + TTL sätts konservativt för att undvika onödiga DNS-skrivningar. + - IPv4 prioriteras; IPv6 endast om verifierat fungerande i miljön. + +5. **Cron-script för IP-byte och cert/TLS-flöde** + - Script körs periodiskt (t.ex. var 5:e minut) och: + 1. Läser aktuell publik IP. + 2. Jämför mot senast känd IP (state-fil). + 3. Vid förändring: logga händelse, trigga Caddy reload/validering, och köra HTTPS-smoke-test mot definierade domäner. + - Viktigt: Certifikat är domänbundna (inte IP-bundna). Scriptet ska därför **inte** forcera ny cert-utgivning vid varje IP-byte (risk för Let’s Encrypt rate limits), utan säkerställa att DNS och TLS fungerar direkt efter ändringen. + +## Implementationssteg + +### Fas 1: Repo-etablering +- Skapa nytt repo från nuvarande kodbas: + - Lokal klon till ny katalog. + - Ny remote (Gitea) för nya caddy-repot. + - Verifiera att arbetskopian är ren och att endast nya repot används framåt. + +### Fas 2: Containerisering med custom build +- Lägg till `Dockerfile` för Caddy custom build med båda modulerna. +- Uppdatera `compose.yml`: + - Använd custom image/build. + - Behåll portar, nätverk `proxy`, data/config-volymer. + - Lägg till env-hantering för `BUNNY_API_KEY` och kontaktmail. + +### Fas 3: Caddy-konfiguration +- Uppdatera `conf/Caddyfile`: + - Lägg till globalt options-block för ACME DNS + dynamic DNS. + - Mappa zon + hostnames för dynamic DNS. + - Behåll samtliga befintliga reverse proxy-regler och ordning. +- Lägga in validering (`caddy validate` via container) som del av drift-rutin. + +### Fas 4: Cron + script +- Lägg till script (t.ex. `scripts/ddns-cert-sync.sh`) med: + - lock-fil (undvika parallellkörning), + - robust felhantering och loggning, + - IP-change detection + Caddy reload + TLS-smoke-test. +- Lägg till crontab-exempel (t.ex. `cron/caddy-ddns-cert.cron`) och installationsinstruktion. + +### Fas 5: Test och verifiering +- Funktionstesta i ordning: + 1. Container build/start. + 2. `caddy validate` + `caddy list-modules` (verifiera bunny + dynamic_dns). + 3. Simulerad IP-förändring och bekräfta DNS-record update i Bunny. + 4. HTTPS-test av representativa domäner. + 5. Verifiera att befintliga tjänster bakom reverse proxy fungerar oförändrat. + +### Fas 6: Dokumentation och överlämning +- Uppdatera `README.md` med: + - setup, env-variabler, cron-installation, + - felsökning (DNS update, ACME challenge, loggar), + - rollback-steg. + +## Konfigurationsförslag (målvärden) +- `dynamic_dns.check_interval`: 5m +- DNS TTL: 300s eller 600s +- Cron: var 5:e minut +- State-fil för senaste IP: persistent volym/sökväg på host +- Loggning: tidsstämplad, roterbar via systemets logrotate/journal + +## Risker och motåtgärder +- **Let’s Encrypt rate limits**: undvik forcerad re-issue vid IP-byte; kör verifiering istället. +- **DNS propagation delay**: script ska vänta/retrya innan TLS-smoke-test markeras failed. +- **Felaktig zon/record mapping**: explicit lista över zone + hostnames i config, samt initial torrkörning. +- **Modulkompatibilitet/versioner**: pinna Caddy- och plugin-versioner i build för reproducerbarhet. + +## Acceptanskriterier +- Nytt repo finns och används som arbetsrepo. +- Caddy kör i Docker med custom image och laddade moduler för Bunny + dynamic DNS. +- Samtliga befintliga hostnames/routingregler fungerar som idag. +- DNS A/AAAA uppdateras automatiskt när publik IP ändras. +- Cron-script upptäcker IP-byte och triggar reload + TLS-verifiering utan att orsaka onödig cert-utgivning. +- Dokumentation räcker för drift utan muntlig kunskapsöverföring. + +## Beslutspunkter före implementation +- Namn/URL för nya caddy-repot i Gitea. +- Exakt vilka hostnames som ska dynamiskt uppdateras (alla i Caddyfile eller delmängd). +- Om IPv6 ska ingå från start. +- Önskad TTL (300 eller 600 sekunder). \ No newline at end of file