From b6c9184a7b173287de9567723a715a0da6409b2d Mon Sep 17 00:00:00 2001 From: dtoro Date: Sun, 28 Jun 2026 22:32:59 +0200 Subject: [PATCH] decommission: destroy plato (LXC 126) LXC 126 stopped and destroyed on hubris. Remove all live references: inventory, container doc, host file, README, containers index, auto-deploy pipeline, DNS entry, SSH access table, nfs-export mount list. Co-Authored-By: Claude Sonnet 4.6 --- README.md | 1 - containers/102-nfs-export.md | 2 +- containers/126-plato.md | 108 ---------------------------------- containers/index.md | 2 +- hosts/plato.yaml | 28 --------- infrastructure/auto-deploy.md | 14 ++--- infrastructure/dns.md | 4 +- infrastructure/ssh-access.md | 1 - inventory.yaml | 15 +---- 9 files changed, 12 insertions(+), 163 deletions(-) delete mode 100644 containers/126-plato.md delete mode 100644 hosts/plato.yaml diff --git a/README.md b/README.md index 05ce373..90020ea 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ See the full table in [`containers/index.md`](containers/index.md). Quick links: | 121 | [caddy](containers/121-caddy.md) | 192.168.8.175 | Reverse proxy | | 122 | [arriman](containers/122-arriman.md) | 192.168.8.132 | Docker host (\*arr stack) | | 124 | [authentik](containers/124-authentik.md) | 192.168.8.180 | SSO + split-horizon DNS | -| 126 | [plato](containers/126-plato.md) | 192.168.8.190 | Plato (notes/discovery workspace) | ### Cross-cutting infrastructure - [DNS — split-horizon](infrastructure/dns.md) diff --git a/containers/102-nfs-export.md b/containers/102-nfs-export.md index 7ec89a9..c8efe5a 100644 --- a/containers/102-nfs-export.md +++ b/containers/102-nfs-export.md @@ -8,7 +8,7 @@ Dedicated, single-purpose LXC that re-exports `/mnt/library` over NFSv4 to clien - **LAN DNS:** `nfs-export.hubris.network` → `192.168.8.200` (direct, no Caddy) - **Privilege:** privileged (`unprivileged: 0`) + `lxc.apparmor.profile: unconfined` — required for `nfs-kernel-server` - **Resources:** 1 core / 512 MiB RAM / 2 GiB rootfs / 256 MiB swap -- **Mounts:** host `/mnt/library` ↔ container `/mnt/library` (same path on both sides — matches the bind-mount convention used by jellyfin, paperless, arriman, nextcloud, mule-images, plato, apps) +- **Mounts:** host `/mnt/library` ↔ container `/mnt/library` (same path on both sides — matches the bind-mount convention used by jellyfin, paperless, arriman, nextcloud, mule-images, apps) ## What it does diff --git a/containers/126-plato.md b/containers/126-plato.md deleted file mode 100644 index d2a38cc..0000000 --- a/containers/126-plato.md +++ /dev/null @@ -1,108 +0,0 @@ -# 126 — `plato` - -Docker host for [Plato](https://git.hubris.network/dtoro/Plato) — a cross-linked notes workspace (SvelteKit SPA embedded into a Go HTTP server, SQLite-backed). LAN+mesh only, no public ingress. - -## At a glance -- **Hostname:** `plato` -- **IP:** `192.168.8.190` -- **Privilege:** privileged -- **Resources:** 2 cores / 2 GiB RAM / 8 GiB rootfs / 1 GiB swap -- **Mounts:** host `/mnt/library/documents/plato` ↔ container `/opt/plato/data` -- **Public hostname:** [`plato.hubris.network`](../infrastructure/dns.md) → [caddy (121)](121-caddy.md) → `192.168.8.190:8080` - -## Stack - -Single-container deploy. The repo's `Dockerfile` is a three-stage build (Node → Go → distroless/static-debian12:nonroot, ~23 MiB final image). The container exposes `:8080` and writes its SQLite db to `/data`. - -- **Checkout:** `/opt/plato/app` (clone of `http://192.168.8.121:3000/dtoro/Plato.git`, using the cached gitea PAT in `/root/.git-credentials` — same pattern as [caddy (121)](121-caddy.md)). -- **Data:** host `/mnt/library/documents/plato` (owned `65532:65532` to match the distroless nonroot UID) bind-mounted into the LXC at `/opt/plato/data`, then bound into the container at `/data` via a `docker-compose.override.yml`: - ```yaml - services: - plato: - volumes: !override - - /opt/plato/data:/data - restart: unless-stopped - ``` -- **`.env`** at `/opt/plato/app/.env` (optional, untracked) — LLM provider keys (`OPENROUTER_API_KEY`, `ANTHROPIC_API_KEY`, etc.) and `PLANTUML_BASE_URL` override. Absent by default; LLM features stay greyed out, PlantUML defaults to the public service. -- **Run / update:** push to `dtoro/Plato` (auto-deploys, see below) or `cd /opt/plato/app && git pull && docker compose up -d --build` for a manual rebuild. - -## Auto-deploy - -Push to `dtoro/Plato` `main` triggers a rebuild — same Shape B pattern as [Artifacto / mule-image](../infrastructure/auto-deploy.md). Webhook receiver at `/opt/plato-deploy/`, systemd unit `plato-deploy-webhook.service`, port `9799`, gitea hook id 8. - -- Receiver: `http://192.168.8.190:9799/deploy`, signed payload (HMAC-SHA256, secret in `/etc/plato-deploy/secret`). -- Logs: `journalctl -u plato-deploy-webhook -f`. -- Health: `curl http://127.0.0.1:9799/health`. -- Manual deploy: `/opt/plato-deploy/deploy.sh`. -- Gitea's `app.ini` `ALLOWED_HOST_LIST` was extended with `192.168.8.190` to allow this delivery. - -## Fresh-DB bootstrap workaround - -The `schema` constant in `backend/internal/views/store.go` (as of commit `e0542c0`) creates the `views` table without `project_id`, then immediately runs `CREATE UNIQUE INDEX … ON views(project_id, lower(title))`. On a fresh DB this fails (no such column) and Plato crash-loops with `open views store: SQL logic error: no such column: project_id`. `ensureProjectIDColumn()` adds the column on subsequent migrations, but the schema apply happens first. - -Until the upstream fix lands, pre-seed the DB before first start: - -``` -docker compose stop -rm -f /opt/plato/data/plato.db -python3 - <<'PY' -import sqlite3 -c = sqlite3.connect('/opt/plato/data/plato.db') -c.executescript(""" -CREATE TABLE views ( - id TEXT PRIMARY KEY, - type TEXT NOT NULL DEFAULT 'document', - title TEXT NOT NULL, - aliases TEXT NOT NULL DEFAULT '[]', - content TEXT NOT NULL DEFAULT '', - created_at TEXT NOT NULL, - updated_at TEXT NOT NULL, - project_id TEXT NOT NULL DEFAULT '' -); -CREATE UNIQUE INDEX views_project_title_lower ON views(project_id, lower(title)); -CREATE INDEX views_project_id ON views(project_id); -""") -c.commit() -PY -chown 65532:65532 /opt/plato/data/plato.db -docker compose up -d -``` - -Once the column exists, every subsequent boot's `IF NOT EXISTS` clauses no-op. Once Plato is fixed upstream (remove the `CREATE UNIQUE INDEX` line from the boot `schema` constant — `ensureTitleIndexPerProject()` already re-creates it after the migration), this preseed becomes unnecessary. - -## Why privileged - -Matches the docker-host convention used by [120 mule-images](120-mule-images.md) and [122 arriman](122-arriman.md). Distroless nonroot's UID `65532` on the host bind mount maps directly through; unprivileged would shift the UID by the idmap offset and the container couldn't write `/data` without extra plumbing. - -## Caddy - -``` -plato.hubris.network { - tls { - dns ionos {env.IONOS_AUTH_API_TOKEN} - } - reverse_proxy 192.168.8.190:8080 -} -``` - -No Authentik forward-auth — Plato has no auth model yet; access control is "be on the LAN or the mesh". - -## DNS - -dnsmasq entry on [124-authentik](124-authentik.md): -``` -address=/plato.hubris.network/192.168.8.175 -``` - -## Related -- [Caddy (121)](121-caddy.md) -- [DNS (split-horizon)](../infrastructure/dns.md) -- [Media permissions](../infrastructure/media-permissions.md) - -## Changelog - -### 2026-05-13 — auto-deploy wired -Shape B pipeline added (`/opt/plato-deploy/`, port `9799`, gitea hook id 8). `ALLOWED_HOST_LIST` in gitea `app.ini` extended with `192.168.8.190`. See [auto-deploy](../infrastructure/auto-deploy.md#plato). - -### 2026-05-13 — container created, Plato deployed -LXC 126 stood up on Debian 12 standard, privileged, docker-ce installed. Plato cloned from `dtoro/Plato`, built and started. Caddy site and dnsmasq split-horizon entry added. Recycled the IP/ID slot freed earlier the same day by the [decommissioned Seafile experiment (LXC 125)](index.md#recently-destroyed-kept-for-archaeology). Hit the [fresh-DB bootstrap bug](#fresh-db-bootstrap-workaround) on first boot; worked around by pre-seeding the SQLite schema. diff --git a/containers/index.md b/containers/index.md index 2b7055e..b77177c 100644 --- a/containers/index.md +++ b/containers/index.md @@ -15,7 +15,6 @@ All containers live on [`hubris`](../hosts/hubris.md). Each row links to the per | 121 | [caddy](121-caddy.md) | 192.168.8.175 | unpriv | 1 | 512 MiB | 6 GiB | — | (terminates all `*.hubris.network`) | running | | 122 | [arriman](122-arriman.md) | 192.168.8.132 | priv | 4 | 8 GiB | 24 GiB | `/mnt/library` | `jellyseerr` / `qbit` / `sab` | running | | 124 | [authentik](124-authentik.md) | 192.168.8.180 | priv | 2 | 4 GiB | 20 GiB | — | `auth.hubris.network` | running | -| 126 | [plato](126-plato.md) | 192.168.8.190 | priv | 2 | 2 GiB | 8 GiB | `/mnt/library/documents/plato` | `plato.hubris.network` | running | | 128 | [trmnl](128-trmnl.md) | 192.168.8.211 | unpriv | 1 | 768 MiB | 8 GiB | — | `trmnl.hubris.network` | running | | 129 | [house](129-house.md) | 192.168.8.212 | unpriv | 1 | 1344 MiB | 8 GiB | — | `house.hubris.network` | running | @@ -27,6 +26,7 @@ All containers live on [`hubris`](../hosts/hubris.md). Each row links to the per | 100 | arr (yunohost) | ~2026-04-28 | Migrated to docker stack on [arriman](122-arriman.md); planned retention window expired | | 106 | flaresolverr | ~2026-04-28 | Folded into the arriman docker compose | | 116 | heaper | 2026-05-14 | Decommissioned by user; data subtree at `/mnt/library/heaper` (224 MiB) retained | +| 126 | plato | 2026-06-28 | Notes/discovery workspace decommissioned; data at `/mnt/library/documents/plato` retained for archaeology | | 123 | claudio-bot | 2026-06-04 | Replaced by Hermes Agent on mac-mini; monitoring migrated to `homelab-health-watchdog` cron. See [deprecation plan](../plans/2026-06-04_130000-deprecate-claudio-bot.md) | | 109 | syncthing | 2026-05-14 | Decommissioned by user; `/mnt/library/syncthing` was already empty | | 125 | seafile | 2026-05-13 | Seafile Pro evaluation, user disliked the product; teardown also removed `files.hubris.network` from caddy + dnsmasq | diff --git a/hosts/plato.yaml b/hosts/plato.yaml deleted file mode 100644 index e391ff2..0000000 --- a/hosts/plato.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by mcp/build_host_files.py from inventory.yaml. -# Do NOT edit by hand — your changes will be overwritten. -# Source of truth: ../inventory.yaml -name: plato -kind: lxc -os: linux -role: app -host: hubris -pve_id: 126 -lan_ip: 192.168.8.190 -mesh_globals: - primary: netbird - accepted: - - netbird - - tailscale -mounts: -- /mnt/library/documents/plato -public_host: plato.hubris.network -runs: -- plato -services_hosted: -- name: plato - url: https://plato.hubris.network - backend: plato -see_also: -- containers/126-plato.md -mcp_endpoint: https://mcp.hubris.network/mcp -secrets_issuance_endpoint: https://secrets.hubris.network/issue diff --git a/infrastructure/auto-deploy.md b/infrastructure/auto-deploy.md index 9c8d65f..fbe87c4 100644 --- a/infrastructure/auto-deploy.md +++ b/infrastructure/auto-deploy.md @@ -23,7 +23,7 @@ The app repo at `/opt/` is the working tree, but the deploy tooling (`web - ~~`192.168.8.230` (claudio-bot — destroyed 2026-06-04)~~ - `192.168.8.136` ([mule-images (120)](../containers/120-mule-images.md)) - `192.168.8.77` ([hubris host](../hosts/hubris.md) — backup-library) - - `192.168.8.190` ([plato (126)](../containers/126-plato.md)) + - ~~`192.168.8.190` ([plato (126)](../containers/126-plato.md))~~ (destroyed 2026-06-28) - `192.168.8.211` ([trmnl (128)](../containers/128-trmnl.md) — terminalito) **Don't strip these when editing app.ini.** @@ -38,7 +38,7 @@ The app repo at `/opt/` is the working tree, but the deploy tooling (`web | `dtoro/gitea-customizations` | [gitea (104)](../containers/104-gitea.md) `/var/lib/gitea/custom/` | A | `http://127.0.0.1:9797/deploy` (loopback) | (orig) | `systemctl restart gitea` if templates changed | | `dtoro/mule-image` | [mule-images (120)](../containers/120-mule-images.md) `/opt/mule-image/` | B | `http://192.168.8.136:9797/deploy` | 6 | `docker compose up -d --build` | | `dtoro/Artifacto` | [apps (105)](../containers/105-apps.md) `/opt/artifacto/` | B | `http://192.168.8.205:9798/deploy` | 7 | `docker compose up -d --build` | -| `dtoro/Plato` | [plato (126)](../containers/126-plato.md) `/opt/plato/app/` | B | `http://192.168.8.190:9799/deploy` | 8 | `docker compose up -d --build` | +| ~~`dtoro/Plato`~~ | ~~[plato (126)](../containers/126-plato.md) `/opt/plato/app/`~~ (destroyed 2026-06-28) | ⊘ | `http://192.168.8.190:9799/deploy` (dead) | 8 (removed) | Repo archived — LXC destroyed | | `dtoro/claudio-bot` | ~~[claudio-bot (123)](../containers/123-claudio-bot.md)~~ (destroyed 2026-06-04) | ⊘ | `http://192.168.8.230:9797/deploy` (dead) | (archived) | Repo archived — LXC destroyed | | `dtoro/backup-library` | [hubris host](../hosts/hubris.md) `/opt/backup-library/` | A | `http://192.168.8.77:9798/deploy` | (orig) | runs `deploy.sh` (preserves admin-edited `/etc/restic/include-*.list`) | | `dtoro/Homelab-Docs` → homelab-mcp | [apps (105)](../containers/105-apps.md) `/opt/homelab-mcp/` | B | `http://192.168.8.205:9811/deploy` | 10 | reinstalls `homelab-mcp.service` + restart | @@ -59,7 +59,7 @@ Always commit + push. Local-only edits drift. Common ones: - `/var/lib/gitea/custom/` ↔ `dtoro/gitea-customizations` (auto-deploys) - `/opt/artifacto/` ↔ `dtoro/Artifacto` (auto-deploys) - `/opt/mule-image/` ↔ `dtoro/mule-image` (auto-deploys) -- `/opt/plato/app/` ↔ `dtoro/Plato` (auto-deploys) +- ~~`/opt/plato/app/` ↔ `dtoro/Plato`~~ (destroyed 2026-06-28) - ~~`/opt/claudio-bot/` ↔ `dtoro/claudio-bot`~~ (destroyed 2026-06-04) - `/opt/backup-library/` ↔ `dtoro/backup-library` (auto-deploys) - `/opt/homelab-mcp/` + `/opt/secrets-issuance/` ↔ `dtoro/Homelab-Docs` (auto-deploys both, see [homelab-context](homelab-context.md)) @@ -74,11 +74,6 @@ Always commit + push. Local-only edits drift. Common ones: - Receiver is on **loopback** (`127.0.0.1:9797`), not the LXC IP. - Online3DViewer binary assets are NOT tracked; `deploy.sh` fetches them on first run. -### Plato -- Shape B (`/opt/plato-deploy/{webhook.py,deploy.sh}`, port `9799`). -- The in-LXC checkout's `origin` is `http://192.168.8.121:3000/dtoro/Plato.git` (internal gitea), and git creds are at `/root/.git-credentials` rather than the `/etc/plato-deploy/git-credentials` pattern — the unit doesn't set `ProtectHome` so root's home is reachable. -- `/data` is a host bind (`/mnt/library/documents/plato`), so `docker compose up -d --build` rebuilds the image + restarts the container without touching the SQLite db. The [fresh-DB bootstrap workaround](../containers/126-plato.md#fresh-db-bootstrap-workaround) only matters if you blow `plato.db` away. - ### mule-image / Artifacto - Async deploy (returns 202) — gitea would otherwise time out the request. Logs: `pct exec -- journalctl -u -deploy-webhook -f`. - **Cloning from inside the LXC must use the internal gitea IP** (`http://192.168.8.121:3000/...`). `https://git.hubris.network` hits a connection reset from inside [apps (105)](../containers/105-apps.md) (Caddy routing / TLS hairpin not configured for this LXC). Configured `origin` on the in-LXC checkout is the internal URL. @@ -125,6 +120,9 @@ If you're not sure what's already lurking, run `homelab apt-audit --fleet` and l ## Changelog +### 2026-06-28 — Plato pipeline decommissioned +LXC 126 destroyed, webhook id 8 on `dtoro/Plato` removed. `192.168.8.190` removed from gitea `app.ini` `ALLOWED_HOST_LIST`. + ### 2026-06-24 — terminalito pipeline added Webhook id 12 on `dtoro/terminalito` → `http://192.168.8.211:9797/deploy` on [trmnl (128)](../containers/128-trmnl.md). Shape B (`server/deploy/webhook.py` receiver, in-repo `server/deploy/deploy.sh`; secret `/etc/terminalito-deploy/secret`). `app.ini` `ALLOWED_HOST_LIST` extended with `192.168.8.211`. Verified end-to-end with a push. Repo-local `credential.helper` in `/opt/terminalito/.git/config` (the unit can't read root's global git config). diff --git a/infrastructure/dns.md b/infrastructure/dns.md index 218c0d3..011f7ee 100644 --- a/infrastructure/dns.md +++ b/infrastructure/dns.md @@ -32,7 +32,6 @@ address=/blog.hubris.network/192.168.8.175 address=/photos.hubris.network/192.168.8.175 address=/photos-new.hubris.network/192.168.8.175 address=/artifacto.hubris.network/192.168.8.175 -address=/plato.hubris.network/192.168.8.175 address=/zimaos.hubris.network/192.168.8.175 address=/nfs-export.hubris.network/192.168.8.200 ``` @@ -76,6 +75,9 @@ Either: ## Changelog +### 2026-06-28 — `plato.hubris.network` removed +Plato (LXC 126) decommissioned. Technitium entry deleted; dns-sync cron reaped the NetBird managed zone record. + ### 2026-06-17 — Fritz!Box DNSv4 server set to Technitium; old limitation resolved Household LAN clients (192.168.178.x) now resolve `*.hubris.network` to LAN IPs — the limitation noted below is resolved. Configured at Fritz!Box Internet → Filter → DNS Server → DNSv4 Server = `192.168.8.2` (User-defined). Authentik LXC 124 (192.168.8.180) destroyed — Authentik runs on VPS, DNS on Technitium (107). diff --git a/infrastructure/ssh-access.md b/infrastructure/ssh-access.md index b33f39c..3b80d08 100644 --- a/infrastructure/ssh-access.md +++ b/infrastructure/ssh-access.md @@ -131,7 +131,6 @@ are managed by `ssh/deploy-keys.sh`. SSH user is `root`. | 120 | mule-images | `192.168.8.136` | photo-management | | 121 | caddy | `192.168.8.175` | reverse-proxy | | 122 | arriman | `192.168.8.132` | arr-stack | -| 126 | plato | `192.168.8.190` | app | ### Workstations diff --git a/inventory.yaml b/inventory.yaml index a36c556..6f9fb82 100644 --- a/inventory.yaml +++ b/inventory.yaml @@ -69,9 +69,6 @@ services: photos: url: https://photos.hubris.network backend: mule-images - plato: - url: https://plato.hubris.network - backend: plato arr_stack: backend: arriman note: jellyseerr / qbit / sab on docker compose @@ -317,17 +314,7 @@ hosts: - /mnt/library age_pubkey: '' # 123 (claudio-bot) — destroyed 2026-06-04, replaced by Hermes Agent - plato: - kind: lxc - pve_id: 126 - host: hubris - os: linux - role: app - lan_ip: 192.168.8.190 - public_host: plato.hubris.network - mounts: - - /mnt/library/documents/plato - age_pubkey: '' + # 126 (plato) — destroyed 2026-06-28, notes workspace decommissioned zimaos: kind: vm pve_id: 100