# Deployment mit Podman ## Bauen ```sh podman build -t kver . ``` Multi-Stage-Build (`Containerfile`): statisches Go-Binary (CGO aus, modernc- SQLite ist pures Go), Laufzeit-Image ist Alpine mit unprivilegiertem Nutzer. ## Starten ```sh podman run -d --name kver \ -p 127.0.0.1:8080:8080 \ -v kver-data:/app/data \ -v kver-media:/app/static/media \ kver ``` - `kver-data` hält die SQLite-DB (`/app/data/kver.db`), `kver-media` die hochgeladenen Bilder. Beides Named Volumes -> überleben Image-Updates. - Port nur an localhost binden; nach außen geht es über den Reverse-Proxy. Konfiguration über Umgebungsvariablen: | Variable | Default | Bedeutung | |-------------|---------------------|----------------------| | `KVER_ADDR` | `:8080` | Listen-Adresse | | `KVER_DB` | `/app/data/kver.db` | Pfad zur SQLite-Datei | ## Bestehende Daten übernehmen DB und Medien einmalig in die Volumes kopieren (Container muss dafür kurz gelaufen sein bzw. die Volumes existieren): ```sh podman volume create kver-data podman volume create kver-media podman cp kver.db kver:/app/data/kver.db # bei laufendem Container, oder: cp kver.db "$(podman volume inspect kver-data -f '{{.Mountpoint}}')/" cp static/media/* "$(podman volume inspect kver-media -f '{{.Mountpoint}}')/" ``` Danach Container neu starten. (Rootless: `podman unshare cp ...`, damit die UID-Zuordnung ins User-Namespace-Mapping passt.) ## Reverse-Proxy (TLS) Der Container spricht nur HTTP. Davor gehört ein TLS-terminierender Proxy (Caddy/nginx), der `X-Forwarded-Proto: https` setzt — daran erkennt die App HTTPS und setzt das `Secure`-Flag auf den Session-Cookie (siehe `isHTTPS`). nginx-Beispiel: ```nginx location / { proxy_pass http://127.0.0.1:8080; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $remote_addr; client_max_body_size 20m; # Uploads bis 17 MB durchlassen } ``` `client_max_body_size` muss über dem App-Limit (17 MB, `maxUploadBytes`) liegen, sonst kappt nginx vor der App. Hinweis Rate-Limiting: `httprate.LimitByIP` auf den Auth-Routen sieht hinter einem Proxy die Proxy-IP. Entweder den Proxy die echte Client-IP als `X-Real-IP`/`X-Forwarded-For` setzen lassen und chi's `middleware.RealIP` vorschalten — oder damit leben, dass das Limit global statt pro IP wirkt. ## Autostart mit systemd (Quadlet) `~/.config/containers/systemd/kver.container` (rootless): ```ini [Unit] Description=kver (Kontrollverlust) [Container] Image=localhost/kver:latest PublishPort=127.0.0.1:8080:8080 Volume=kver-data:/app/data Volume=kver-media:/app/static/media [Service] Restart=on-failure [Install] WantedBy=default.target ``` Aktivieren: ```sh systemctl --user daemon-reload systemctl --user start kver loginctl enable-linger "$USER" # damit der Dienst ohne Login läuft ``` ## Update einspielen ```sh podman build -t kver . systemctl --user restart kver # bzw. podman stop kver && podman run ... ``` Die App fährt bei SIGTERM sauber herunter (laufende Requests werden zu Ende bedient, WAL-Checkpoint beim DB-Close).