App hinzufügen¶
Zuerst DNS und Token-Policy, dann der Stack
Roll den DNS-Eintrag und die Zeile _acme-challenge.<subdomain> in der Token-Policy in einem eigenen Commit aus, bevor du die Stack-Datei anlegst (Schritte 2 bis 4).
Fehlt die Zeile in der Token-Policy, wenn die App zum ersten Mal ausgerollt wird, bekommt sie kein Zertifikat, und Caddy versucht es auch nach dem Nachtragen erst nach langer Zeit erneut.
Ziel¶
Eine neue App läuft auf einem Host unter ihrer eigenen Adresse mit gültigem Zertifikat, wird gesichert, überwacht und ist, wo nötig, an Authentik angebunden.
Voraussetzungen¶
- du kannst eine Änderung ausrollen (Änderung ausrollen), auch für DNS
- gelesen: Eine Stack-Datei lesen, syslet in diesem Repo, Caddy, DNS und Backup
- geklärt, auf welchem Host die App laufen soll: auf werner, wenn sie aus dem Internet erreichbar sein soll, auf containerhost, wenn sie nur vor Ort gebraucht wird (siehe Architektur)
Diese Anleitung ist eine Checkliste: Jeder Schritt sagt, was dazugehört, und verlinkt für die Einzelheiten auf die passende Anleitung.
Schritte¶
1. Name und Hostnamen festlegen¶
Leg fest:
- den Namen der App, klein und ohne Leerzeichen, etwa
beispiel; danach heißen Stack-Datei, Container, Volumes und Secrets - den Hostnamen: auf werner
<subdomain>.garage-lab.de, auf containerhost<subdomain>.garage-lab.net
Prüf in der Zonendatei, dass es die Subdomain noch nicht gibt:
| Bash | |
|---|---|
Erwartet: keine Ausgabe.
2. DNS-Eintrag anlegen¶
Nur für eine App auf werner.
Trag in desec/desec_garage_lab_de.cue bei den anderen Apps einen A- und einen AAAA-Eintrag auf werner ein, wie bei md:
| Text Only | |
|---|---|
Für eine App auf containerhost kommt kein Eintrag nach deSEC; den Namen löst der DNS-Server auf dem Gateway auf, der nicht im Repo steht (siehe Netzwerk). Bitte in Signal jemanden mit Zugang zum Gateway, den Namen dort einzutragen.
3. Token-Policy ergänzen¶
Trag am Ende derselben Zonendatei in der Token-Policy des Caddy auf dem Ziel-Host eine Zeile für die Subdomain ein, alphabetisch einsortiert:
| Host | Datei | Block |
|---|---|---|
| werner | desec/desec_garage_lab_de.cue |
desec: tokenPolicies: "2262403e-…" |
| containerhost | desec/desec_garage_lab_net.cue |
desec: tokenPolicies: "2f198c18-…" |
| Text Only | |
|---|---|
Auf containerhost steht garage-lab.net statt garage-lab.de.
4. DNS ausrollen, committen und pushen¶
Wie in Änderung ausrollen, im Ordner desec/.
plan zeigt dabei für werner etwa:
Für containerhost nur die Zeile + create policy.
Commit und Push gehören zu diesem Schritt; die Stack-Datei kommt in einen eigenen Commit.
Prüfen (nur werner):
| Bash | |
|---|---|
Erwartet: die IPv4-Adresse von werner.
5. Stack-Datei anlegen¶
Kopier die Stack-Datei einer ähnlichen App und pass sie an:
- eine App mit Postgres-Datenbank:
syslet/werner/stack-hedgedoc.cue, Block für Block erklärt in Eine Stack-Datei lesen - eine App mit nur einem Container:
syslet/werner/stack-vaultwarden.cue
| Bash | |
|---|---|
Geh die neue Datei von oben nach unten durch und ersetze überall den Namen der alten App durch den neuen. Achte dabei auf:
- Image: Tag oben in der Datei, nach den Release Notes der App gewählt (siehe Image-Version anheben)
- Netzwerke: ein eigenes internes Netzwerk für die App; auf werner zusätzlich
caddyfür den Container, der von außen erreichbar sein soll (siehe syslet in diesem Repo) - Volumes:
:Z, wenn nur dieser Container das Volume nutzt,:z, wenn es auch gesichert wird oder ein anderer Container es nutzt (siehe SELinux) - Labels: auf werner
#LabelsmitpartOfgleich dem Namen der App (siehe syslet in diesem Repo) - Ingress: Hostname aus Schritt 1, Port, auf dem die App im Container lauscht
- Locks: jedes Volume mit Daten, die Container und das Netzwerk der App im Block
tools.#SysdefLock - Secrets: Passwörter und Tokens nicht unter
Environment:, sondern nach Secret anlegen oder ändern
Trag außerdem für jeden Container ein Speicherlimit in syslet/<host>/host.cue ein, wie für die anderen Container dort.
6. Backup einbinden¶
Nur für Apps auf werner, die Daten haben, die wir nicht verlieren wollen.
In der Stack-Datei:
backup: <app>:mit den Volumes und Pfaden, die gesichert werden sollen, wie am Ende vonstack-hedgedoc.cue- bei einer Postgres-Datenbank beim Datenbank-Container
configFiles: [restic.scripts.postgresBackup, restic.scripts.postgresRestore]und das Volume<app>-postgres-backups
In rootfs/werner/usr/bin/system-backup eine Zeile, die den Dump schreibt, wie bei HedgeDoc:
| Bash | |
|---|---|
und in rootfs/werner/etc/systemd/system/system-backup.service eine Zeile Requires=beispiel-postgres.service.
Diese beiden Dateien kopierst du erst in Schritt 9 auf den Host.
7. Anmeldung über Authentik¶
Nur wenn sich die Leute in der App anmelden sollen.
Leg die App in Authentik an, wie in App per OIDC anbinden, und trag Client-ID und Client-Secret nach Secret anlegen oder ändern als oidcclientid und oidcclientsecret in creds-<app>-server.enc.yaml ein.
8. Monitoring¶
- Hat die App eine Postgres-Datenbank, bekommt sie einen eigenen Container
<app>-postgres-exporter, wie instack-hedgedoc.cue, mit dem nächsten freien Port unterPublishPort(die belegten zeigtgrep -n PublishPort syslet/werner/*.cue). Dazu kommt ein Eintrag unterscrape_configsinsyslet/containerhost/stack-prom.cue, wie beihedgedoc-postgres. - Ist die App öffentlich erreichbar, trägt jemand mit Zugang ihre Adresse in der Web-Oberfläche von Uptime Kuma ein (siehe Uptime-Monitoring).
9. Ausrollen¶
Wie in Änderung ausrollen, im Ordner des Hosts; für einen neuen Exporter danach auch in syslet/containerhost.
Erwartet bei plan: unter Images to pull: die Images der App, unter Unit file changes: neue Units für Container, Volumes und Netzwerk der App, bei Secrets Secret changes:, und in der Zusammenfassung jede Unit der App mit created.
Dazu caddy.container mit config updated, reloaded, weil das Caddyfile den neuen Hostnamen bekommt, und mit Backup-Block restic.container mit unit updated, restarted.
Hast du in Schritt 6 die Backup-Dateien geändert, kopier sie nach dem apply auf werner und lass systemd sie neu einlesen:
| Bash | |
|---|---|
Erwartet: keine Ausgabe außer dem Fortschritt von scp.
Hat die App auf werner ein eigenes internes Netzwerk, trag dessen Subnetz nach dem ersten apply in firewalld ein, wie in Podman-Netzwerke reparieren; sonst erreichen sich ihre Container nicht.
Committe Stack-Datei, host.cue, Secrets und rootfs/-Dateien zusammen und push sofort.
10. App-Seite schreiben¶
Leg unter docs/explanation/selfhosting/apps/<app>.md eine Seite nach der Vorlage .work/docs/app-template.md an, trag sie in der Tabelle des Hosts in docs/explanation/general/apps.md und in nav in zensical.toml ein und prüf mit make docs.
Prüfen¶
cue cmd ingressim Ordner des Hosts listet den neuen Hostnamen.curl -sI https://beispiel.garage-lab.deantwortet ohne Zertifikatsfehler; das erste Zertifikat kann wegen der DNS-Challenge ein paar Minuten dauern.- Die Anmeldung über Authentik klappt, falls angebunden.
- Am Morgen nach dem ersten Backup zeigt
cue cmd -t unit=system-backup.service statusinsyslet/wernerstatus=0/SUCCESS. cue cmd planzeigt in jedem Ordner, in dem du ausgerollt hast, „No changes“.
Wenn etwas schiefgeht¶
- Kein Zertifikat, in den Logs von Caddy Fehler mit
_acme-challenge: Die Zeile in der Token-Policy fehlt oder hat einen Tippfehler; nachtragen, ausrollen und Caddy neu starten (Gecrashten Dienst neu starten). - Die App startet nicht: Container-Status und Logs ansehen
- Zugriff auf ein Volume verweigert (
Permission denied): SELinux: Permission denied - Container erreichen sich gegenseitig nicht: Podman-Netzwerke reparieren
- Allgemeines: Add ingress with Caddy und Manage volumes in der syslet-Doku