From 6dfb58d3f187461eb8a64754ec4189d1599dd452 Mon Sep 17 00:00:00 2001 From: Phil Date: Sat, 31 Oct 2026 11:51:48 -0600 Subject: [PATCH] Retire Gondulf and move StarPunk to v2.0.0 with Pocket ID login StarPunk 2.0.0 logs in with Pocket ID and issues its own Micropub tokens (ADR-064 in the StarPunk repo), so the Gondulf IndieAuth server is no longer used. Removes its task, templates, Caddy route, subdomain and service entry, and moves its DNS record to removed_records. The StarPunk template was still on v1.6.0-rc.2 with Gondulf hairpin hosts; deploying it would have broken login. It now matches production: v2.0.0, Pocket ID hairpin, OIDC client from vault_starpunk.pocketid and the admin sub in starpunk_admin_sub. Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 10 +++--- README.md | 3 +- dns.yml | 4 +-- group_vars/all/domains.yml | 1 - group_vars/docker/services.yml | 5 ++- roles/docker/README.md | 9 +++-- roles/docker/tasks/infrastructure/gondulf.yml | 28 --------------- roles/docker/tasks/infrastructure/main.yml | 4 --- roles/docker/templates/Caddyfile.j2 | 4 --- roles/docker/templates/gondulf-compose.yml.j2 | 34 ------------------- roles/docker/templates/gondulf-env.j2 | 9 ----- .../docker/templates/starpunk-compose.yml.j2 | 13 +++++-- todo.md | 2 +- 13 files changed, 27 insertions(+), 99 deletions(-) delete mode 100644 roles/docker/tasks/infrastructure/gondulf.yml delete mode 100644 roles/docker/templates/gondulf-compose.yml.j2 delete mode 100644 roles/docker/templates/gondulf-env.j2 diff --git a/CLAUDE.md b/CLAUDE.md index 96bd452..7d400ba 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -81,7 +81,7 @@ subdomain. and the Warhammer RSS feed (09:10). ### Docker role categories (`roles/docker/tasks//`) -- **infrastructure/**: Caddy, Pocket ID, Gondulf (IndieAuth), Dockge +- **infrastructure/**: Caddy, Pocket ID, Dockge - **development/**: Gitea (+ act_runner), ByteStash - **media/**: Audiobookshelf, Kavita, Karakeep (files named `hoarder`), Manyfold - **productivity/**: Paperless-ngx, Baikal, Syncthing, HeyForm, Dawarich, Obsidian LiveSync, Gokapi @@ -127,11 +127,11 @@ user (`vault_aws_dns`). It also deletes the records listed under ### SSO (Pocket ID) Pocket ID (`id.thesatelliteoflove.com`) replaced Authentik on 2026-10-31. Apps that log in with it: Gitea, ByteStash, Audiobookshelf, Kavita, Karakeep, -Manyfold, Paperless-ngx, Gokapi, GoToSocial. Some read the client from env +Manyfold, Paperless-ngx, Gokapi, GoToSocial, StarPunk. Some read the client from env vars; Gitea, Audiobookshelf and Kavita store it in their own database (set in their admin UI). OIDC clients are created in Pocket ID's UI and their ID and -secret go in the vault as `vault_.pocketid`. StarPunk logs in with -IndieAuth through Gondulf instead. +secret go in the vault as `vault_.pocketid`. StarPunk (v2.0.0+) also +runs its own IndieAuth server so Micropub apps can post; Gondulf was retired. ### Shared Docker Network (`lava`) Created by the docker role as `{{ docker.subnet }}` with `ip_range: {{ docker.ip_range }}`. Docker only hands out dynamic addresses from that range, so `172.20.0.x` is reserved for fixed IPs: Caddy (`docker.hairpin_ip`, .5) and Gitea (`docker.gitea_ip`, .6). Both need fixed IPs because ufw-docker firewall rules point at container IPs. A network without the range (the 2024 original) is migrated once with `migrate-lava-network.yml`. @@ -146,7 +146,7 @@ extra_hosts: ``` Most often needed for `subdomains.pocketid` (OIDC); also `subdomains.git` -(Gitea itself), `subdomains.gondulf` and `primary_domain` (StarPunk). +(Gitea itself) and `primary_domain` (StarPunk). ### Template pattern ```yaml diff --git a/README.md b/README.md index b683a5f..e7d0682 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,6 @@ takes ports 80/443 and passes each subdomain to the right container. |---|---|---|---| | Infrastructure | Caddy (reverse proxy, static sites) | — | — | | | Pocket ID (passkey OIDC provider) | id.thesatelliteoflove.com | passkeys | -| | Gondulf (IndieAuth for the main site) | gondulf.thesatelliteoflove.com | email code | | | Dockge (compose stack manager) | port 5001, no public route | local | | Development | Gitea + Actions runner | git.thesatelliteoflove.com (SSH on port 222) | Pocket ID | | | ByteStash (code snippets) | snippets.thesatelliteoflove.com | Pocket ID | @@ -40,7 +39,7 @@ takes ports 80/443 and passes each subdomain to the right container. | | Gokapi (file sharing) | gokapi.thesatelliteoflove.com | Pocket ID | | Communication | GoToSocial (fediverse) | social.thesatelliteoflove.com | Pocket ID | | | Listmonk (mailing lists) | listmonk.nerder.land | local | -| | StarPunk (Micropub for the main site) | starpunk.thesatelliteoflove.com | IndieAuth | +| | StarPunk (Micropub for the main site) | starpunk.thesatelliteoflove.com | Pocket ID | | Monitoring | Changedetection | watcher.thesatelliteoflove.com | local | | | Apprise API (notifications) | Tailscale only, port 8000 | — | | | Gotify + iGotify assistant | gotify.thesatelliteoflove.com, gotify-assistant.thesatelliteoflove.com | local | diff --git a/dns.yml b/dns.yml index 4d594ae..5867bbe 100644 --- a/dns.yml +++ b/dns.yml @@ -17,8 +17,6 @@ domains: - name: thesatelliteoflove.com dns_records: - - name: "gondulf" - ip: "{{ network.netcup_ip }}" - name: "starpunk" ip: "{{ network.netcup_ip }}" - name: "git" @@ -88,6 +86,8 @@ ip: "{{ network.netcup_ip }}" - name: "auth" # Authentik, replaced by Pocket ID ip: "{{ network.netcup_ip }}" + - name: "gondulf" # IndieAuth, replaced by StarPunk v2 + Pocket ID + ip: "{{ network.netcup_ip }}" - name: "files" ip: "{{ network.netcup_ip }}" - name: "kanboard" diff --git a/group_vars/all/domains.yml b/group_vars/all/domains.yml index 8e8f912..2ec2072 100644 --- a/group_vars/all/domains.yml +++ b/group_vars/all/domains.yml @@ -26,7 +26,6 @@ subdomains: listmonk: "listmonk.{{ secondary_domain }}" # Listmonk mailing list gokapi: "gokapi.{{ primary_domain }}" # Gokapi file sharing pocketid: "id.{{ primary_domain }}" # Pocket ID passkey OIDC - gondulf: "gondulf.{{ primary_domain }}" # IndieAuth for the main site starpunk: "starpunk.{{ primary_domain }}" # Micropub for the main site # Email domains for notifications diff --git a/group_vars/docker/services.yml b/group_vars/docker/services.yml index df8f717..f0b002c 100644 --- a/group_vars/docker/services.yml +++ b/group_vars/docker/services.yml @@ -2,7 +2,7 @@ # Service categories for organization service_categories: - infrastructure: ["caddy", "dockge", "gondulf"] + infrastructure: ["caddy", "dockge"] development: ["gitea", "bytestash"] media: ["audiobookshelf", "kavita", "hoarder", "manyfold"] productivity: ["paperlessngx", "baikal", "syncthing", "heyform", "dawarich", "obsidian-livesync", "gokapi"] @@ -19,5 +19,8 @@ services: dawarich: db_name: "dawarich" db_user: "dawarich" +# StarPunk admin: Pocket ID user ID (sub) of phil +starpunk_admin_sub: "5754855f-0a30-4755-9609-7294209e40f4" + # Gokapi super admin: must match the Pocket ID account email gokapi_admin_email: "phil@{{ primary_domain }}" diff --git a/roles/docker/README.md b/roles/docker/README.md index ef06ded..0b2fe01 100644 --- a/roles/docker/README.md +++ b/roles/docker/README.md @@ -26,7 +26,6 @@ Tags: each category file has a category tag, each service its own tag. |---|---|---| | `caddy` | Caddy | Fixed IP 172.20.0.5. Ports 80/443 (+443/udp). `Caddyfile.j2` changes restart it via a handler; the stack itself is deployed with `recreate: never`. Static sites are served from `/opt/stacks/caddy/site/`. | | `pocketid` | Pocket ID v2 | Passkey OIDC provider at `id.`. OIDC clients are created in its web UI; their IDs and secrets go in the vault. | -| `gondulf` | Gondulf | IndieAuth server for the main site (own image from Gitea). Sends login codes by email through Resend. | | `dockge` | Dockge | Compose UI on port 5001, managing `/opt/stacks`. | ### Development (`development`) @@ -59,7 +58,7 @@ Tags: each category file has a category tag, each service its own tag. |---|---|---| | `gotosocial` | GoToSocial | Pocket ID through env vars. Account domain is the apex; Caddy serves WebFinger there. Daily S3 backup of its volume. | | `listmonk` | Listmonk | Postgres 17. On `listmonk.nerder.land`. | -| `starpunk` | StarPunk | Micropub server for the main site (own image from Gitea). Logs in through Gondulf. | +| `starpunk` | StarPunk | Micropub server for the main site (own image from Gitea). Admin login via Pocket ID; issues its own Micropub tokens. | ### Monitoring (`monitoring`) | Tag | Service | Notes | @@ -97,9 +96,9 @@ in from the internet; the Caddy and Gitea task files add those rules. Containers labelled `mag37.dockcheck.update: true` are updated automatically each morning by dockcheck (set up in the cron role). Containers without the -label (Gondulf, StarPunk, Listmonk, HeyForm, Dockge and most databases) only +label (StarPunk, Listmonk, HeyForm, Dockge and most databases) only get a Gotify notice. Dawarich's database and Redis are skipped entirely. -Gondulf and StarPunk use pinned version tags. +StarPunk uses a pinned version tag. ## Adding a service @@ -121,7 +120,7 @@ roles/docker/ ├── tasks/ │ ├── main.yml # System setup, network, category imports │ ├── shell.yml # zsh, Atuin, bat -│ ├── infrastructure/ # caddy, pocketid, gondulf (+ dockge in main.yml) +│ ├── infrastructure/ # caddy, pocketid (+ dockge in main.yml) │ ├── development/ # gitea, bytestash │ ├── media/ # audiobookshelf, kavita, hoarder (Karakeep), manyfold │ ├── productivity/ # paperlessngx, baikal, syncthing, heyform, dawarich, obsidian-livesync, gokapi diff --git a/roles/docker/tasks/infrastructure/gondulf.yml b/roles/docker/tasks/infrastructure/gondulf.yml deleted file mode 100644 index 380e45a..0000000 --- a/roles/docker/tasks/infrastructure/gondulf.yml +++ /dev/null @@ -1,28 +0,0 @@ -- name: make gondulf directories - ansible.builtin.file: - path: "{{ item }}" - state: directory - loop: - - /opt/stacks/gondulf - -- name: Template out the gondulf compose file - ansible.builtin.template: - src: gondulf-compose.yml.j2 - dest: /opt/stacks/gondulf/compose.yml - owner: root - mode: '0644' - -- name: Template out the gondulf .env file - ansible.builtin.template: - src: gondulf-env.j2 - dest: /opt/stacks/gondulf/.env - owner: root - mode: '0640' - group: docker - diff: false # contains the secret key and SMTP password - -- name: deploy gondulf stack - community.docker.docker_compose_v2: - project_src: /opt/stacks/gondulf - files: - - compose.yml diff --git a/roles/docker/tasks/infrastructure/main.yml b/roles/docker/tasks/infrastructure/main.yml index e911b8d..55597dc 100644 --- a/roles/docker/tasks/infrastructure/main.yml +++ b/roles/docker/tasks/infrastructure/main.yml @@ -9,10 +9,6 @@ import_tasks: pocketid.yml tags: pocketid -- name: Install gondulf - import_tasks: gondulf.yml - tags: gondulf - - name: Template out the dockge compose file ansible.builtin.template: src: dockge-compose.yml.j2 diff --git a/roles/docker/templates/Caddyfile.j2 b/roles/docker/templates/Caddyfile.j2 index 13e5af0..4d71562 100644 --- a/roles/docker/templates/Caddyfile.j2 +++ b/roles/docker/templates/Caddyfile.j2 @@ -88,10 +88,6 @@ pdg.thesatelliteoflove.com { } } -gondulf.thesatelliteoflove.com { - reverse_proxy gondulf:8000 - } - starpunk.thesatelliteoflove.com { reverse_proxy starpunk:8000 } diff --git a/roles/docker/templates/gondulf-compose.yml.j2 b/roles/docker/templates/gondulf-compose.yml.j2 deleted file mode 100644 index d6efeb2..0000000 --- a/roles/docker/templates/gondulf-compose.yml.j2 +++ /dev/null @@ -1,34 +0,0 @@ -services: - gondulf: - image: git.thesatelliteoflove.com/phil/gondulf:1.0.1 - container_name: gondulf - restart: unless-stopped - extra_hosts: - - '{{ primary_domain }}:{{ docker.hairpin_ip }}' - volumes: - - gondulf_data:/data - env_file: - - .env - environment: - - GONDULF_HTTPS_REDIRECT=true - - GONDULF_SECURE_COOKIES=true - - GONDULF_TRUST_PROXY=true - - GONDULF_TOKEN_EXPIRY=3600 - - GONDULF_CODE_EXPIRY=600 - - GONDULF_TOKEN_CLEANUP_ENABLED=false - - GONDULF_TOKEN_CLEANUP_INTERVAL=3600 - - GONDULF_LOG_LEVEL=INFO - - GONDULF_DEBUG=false - healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8000/health"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 10s -volumes: - # Existing volume (gondulf_gondulf_data) holds the SQLite database - gondulf_data: -networks: - default: - external: true - name: {{ docker.network_name }} diff --git a/roles/docker/templates/gondulf-env.j2 b/roles/docker/templates/gondulf-env.j2 deleted file mode 100644 index 8534e45..0000000 --- a/roles/docker/templates/gondulf-env.j2 +++ /dev/null @@ -1,9 +0,0 @@ -GONDULF_SECRET_KEY={{ vault_gondulf.secret_key }} -GONDULF_BASE_URL=https://{{ subdomains.gondulf }} -GONDULF_DATABASE_URL=sqlite:////data/gondulf.db -GONDULF_SMTP_HOST={{ smtp.host }} -GONDULF_SMTP_PORT=587 -GONDULF_SMTP_USERNAME={{ smtp.username }} -GONDULF_SMTP_PASSWORD={{ vault_smtp.password }} -GONDULF_SMTP_FROM=gondulf@{{ smtp.from_domain }} -GONDULF_SMTP_USE_TLS=true diff --git a/roles/docker/templates/starpunk-compose.yml.j2 b/roles/docker/templates/starpunk-compose.yml.j2 index 3f35828..4a62d50 100644 --- a/roles/docker/templates/starpunk-compose.yml.j2 +++ b/roles/docker/templates/starpunk-compose.yml.j2 @@ -1,10 +1,10 @@ services: starpunk: - image: git.thesatelliteoflove.com/phil/starpunk:v1.6.0-rc.2 + image: git.thesatelliteoflove.com/phil/starpunk:v2.0.0 container_name: starpunk restart: unless-stopped extra_hosts: - - '{{ subdomains.gondulf }}:{{ docker.hairpin_ip }}' + - '{{ subdomains.pocketid }}:{{ docker.hairpin_ip }}' - '{{ primary_domain }}:{{ docker.hairpin_ip }}' volumes: - starpunk-data:/data @@ -14,9 +14,16 @@ services: SITE_NAME: StarPunk SITE_AUTHOR: Mr Whiskers SITE_DESCRIPTION: Starpunk instance - # Authentication + # Site owner identity (h-card source, Micropub "me") ADMIN_ME: https://{{ primary_domain }} SESSION_SECRET: {{ vault_starpunk.session_secret }} + # Admin login via Pocket ID (client "StarPunk"); only this user may log in. + # StarPunk issues Micropub tokens itself (ADR-064). + OIDC_ISSUER: https://{{ subdomains.pocketid }} + OIDC_CLIENT_ID: {{ vault_starpunk.pocketid.client_id }} + OIDC_CLIENT_SECRET: {{ vault_starpunk.pocketid.client_secret }} + OIDC_ADMIN_SUB: {{ starpunk_admin_sub }} + OIDC_PROVIDER_NAME: Pocket ID # Production settings FLASK_ENV: production FLASK_DEBUG: 0 diff --git a/todo.md b/todo.md index 3b6ef7a..d321128 100644 --- a/todo.md +++ b/todo.md @@ -21,7 +21,7 @@ Many compose templates repeat the same network, restart and label blocks. Pull the shared parts into includes or macros. ### Health checks -Only Pocket ID, Gondulf, Dawarich, Listmonk and Syncthing define health checks +Only Pocket ID, Dawarich, Listmonk and Syncthing define health checks in their templates. Add them to the rest where the image supports it. ### Backups