From fd35b48c8d7ff8b3dd4919568e4df5d552ae32c4 Mon Sep 17 00:00:00 2001 From: dtoro Date: Mon, 6 Jul 2026 00:45:28 +0200 Subject: [PATCH] Phase 1-4: full doc reorg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 — fix stale state after strong migration (Phase 1+2, 2026-07-05) - README: corrected IPs (jellyfin 206→246, arriman 132→245, etc.), added missing containers (128 trmnl, 129 house, 133 seanime, 134 romm, 124 authentik), updated last-refreshed date, added strong host context - containers/101-jellyfin.md: IP 206→246, host hubris→strong, mount /mnt/library→/mnt/media_local, GPU 760M→680M+RX7600, privilege→priv - containers/118-elementsynapse.md: IP 239→242, added Host: strong - containers/122-arriman.md: IP 132→245, mount→/mnt/media_local, added Host - containers/129-house.md: IP 212→244, added Host: strong - containers/130-grimmory.md: IP 213→247, mount→/mnt/media_local, added Host - containers/121-caddy.md: fixed site list (books→grimmory, removed auth→VPS, added house, roms, teddy, trmnl) - hosts/strong.md: updated At-a-glance to reflect 7 LXCs hosted - containers/123-claudio-bot.md, 127-mule-photos-new.md: archived to containers/archive/ (were destroyed LXCs with living pages) - inventory.yaml: verified correct — no changes needed Phase 2 — structural cleanup - infrastructure/index.md: one-page overview of all cross-cutting systems - runbooks/: moved runbook-budget-from-csv.md and runbook-dpkg-interrupted.md from operations/ with YAML frontmatter added - plans/done/: moved 4 completed plans out of active view; updated index - vms/index.md: added VM index page Phase 3 — navigation & discoverability - GLOSSARY.md: term definitions (Authentik, Caddy, LXC, VAAPI, etc.) - README: added table of contents, links to glossary + infrastructure index - investigations/: archived 2 resolved cases (crash-loop, authentik-migration) to investigations/archive/; updated index with active vs archived sections Phase 4 — ongoing discipline - CONTRIBUTING.md: documented same-session update rule with explicit checklist - README: replaced full LXC table with summary + link to containers/index.md (single source of truth; de-duplication) --- .gitignore | 4 +- CONTRIBUTING.md | 24 +++++++ GLOSSARY.md | 33 ++++++++++ README.md | 53 ++++++++------- containers/101-jellyfin.md | 27 +++++--- containers/118-elementsynapse.md | 3 +- containers/121-caddy.md | 9 ++- containers/122-arriman.md | 5 +- containers/129-house.md | 3 +- containers/130-grimmory.md | 11 ++-- containers/{ => archive}/123-claudio-bot.md | 0 .../{ => archive}/127-mule-photos-new.md | 0 containers/index.md | 2 +- hosts/strong.md | 2 +- infrastructure/index.md | 66 +++++++++++++++++++ .../2026-04-21-hubris-crash-loop.md | 0 .../2026-05-31-authentik-vps-migration.md | 0 investigations/index.md | 18 +++-- ...2026-06-01-slate-ax-to-sodola-migration.md | 0 ...2026-06-04_130000-deprecate-claudio-bot.md | 0 .../2026-06-25-yuvomi-deployment.md | 0 .../2026-06-29-grimmory-migration.md | 0 plans/index.md | 26 +++++--- .../runbook-budget-from-csv.md | 7 ++ .../runbook-dpkg-interrupted.md | 6 ++ vms/index.md | 14 ++++ 26 files changed, 255 insertions(+), 58 deletions(-) create mode 100644 GLOSSARY.md rename containers/{ => archive}/123-claudio-bot.md (100%) rename containers/{ => archive}/127-mule-photos-new.md (100%) create mode 100644 infrastructure/index.md rename investigations/{ => archive}/2026-04-21-hubris-crash-loop.md (100%) rename investigations/{ => archive}/2026-05-31-authentik-vps-migration.md (100%) rename plans/{ => done}/2026-06-01-slate-ax-to-sodola-migration.md (100%) rename plans/{ => done}/2026-06-04_130000-deprecate-claudio-bot.md (100%) rename plans/{ => done}/2026-06-25-yuvomi-deployment.md (100%) rename plans/{ => done}/2026-06-29-grimmory-migration.md (100%) rename {operations => runbooks}/runbook-budget-from-csv.md (98%) rename {operations => runbooks}/runbook-dpkg-interrupted.md (96%) create mode 100644 vms/index.md diff --git a/.gitignore b/.gitignore index 4d348ed..b23dac9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ __pycache__/ # Regenerated every scheduler run (every 10 min); no audit value in the # diff. Signals (signals/*.jsonl) ARE tracked — this is just the ephemeral # health-probe cache. See oikos/scheduler.py. -oikos/state.json \ No newline at end of file +oikos/state.json + +.worktrees/ \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1cfd2d7..7706538 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -121,3 +121,27 @@ Changelog entries to write, index status to update. - One entry per discrete change, even if you make several in one day. - If a change spans nodes, repeat the entry on each affected page (different perspective is fine). - Don't rewrite history — entries are append-only. Mistakes get a follow-up entry that supersedes them. + +## Same-session update rule + +When you make a change to a node — migrate an LXC, update an IP, change a +mount, deploy a new service — **update every relevant doc page in the same +session.** A change that touches a container page must also update: + +- The `containers/index.md` table (IPs, host, mounts, status) +- The `README.md` table (if the change affects listed columns) +- The Caddy page site list (if the change affects `*.hubris.network` routing) +- The DNS / ingress infrastructure pages (if the change affects routing) +- The `hosts/{hubris,strong}.md` host page (if container count changes) +- The `inventory.yaml` host entry (source of truth for the `hosts/*.yaml` generation) +- The `infrastructure/topology.md` (generated from inventory, but regen if needed) + +The pattern of updating only one page and leaving stale references on others +is a bug. If you're doing a multi-step migration, document the intermediate +state with a changelog entry that says "pending — will finalize after Phase +N." + +This rule is why Phase 2 of the strong migration (2026-07-05) caused +widespread stale data: individual container pages were updated in the +changelog but never had their At-a-glance sections, IPs, mount paths, or +host attribution updated. Don't repeat that. diff --git a/GLOSSARY.md b/GLOSSARY.md new file mode 100644 index 0000000..624b77f --- /dev/null +++ b/GLOSSARY.md @@ -0,0 +1,33 @@ +# Glossary + +Terms and abbreviations used throughout the homelab wiki. + +| Term | Meaning | +|------|---------| +| **Authentik** | SSO/identity provider. Core runs on the VPS; forward-auth outpost at LXC 106 on hubris | +| **Caddy** | Reverse proxy (LXC 121). Terminates TLS for every `*.hubris.network` hostname | +| **Caveman** | Terse communication standard for agent responses — no filler, keep substance | +| **Forward-auth** | Caddy snippet that delegates authentication to an Authentik outpost. Protects web UIs like qBit, SABnzbd | +| **Gitea** | Git server at `git.hubris.network`. Hosts all tracked config repos | +| **Gluetun** | WireGuard VPN sidecar on arriman. All \*arr traffic routes through it | +| **HAOS** | Home Assistant Operating System. VM 108 on hubris | +| **Hubris** | Primary Proxmox VE node (GMKtec NucBox M6 Ultra). PVE hostname, cluster member 1 | +| **LXC** | Linux Container (Proxmox). VM-like isolation without a full OS kernel | +| **LVM-thin** | Thin-provisioned logical volume manager. Used for all container/VM storage | +| **MCP** | Model Context Protocol (MCP server at `mcp.hubris.network`). Structured tools for agents to query homelab state | +| **Mesh** | Overlay VPN for off-LAN connectivity. Netbird is current; Tailscale is legacy | +| **Netbird** | Preferred mesh VPN. VPS hosts the management plane; all homelab nodes are members | +| **OIDC** | OpenID Connect. Protocol used by Authentik for SSO login flows | +| **Oikos** | Agent operating model (OIKOS.md). OODA loop, risk classes, policy, ontology | +| **PVE** | Proxmox Virtual Environment — the hypervisor on both hubris and strong | +| **SOPS** | `sops` — Mozilla SOPS. Encrypts secrets with age keys so they live in the git repo | +| **Strong** | Secondary Proxmox VE node. Cluster member 2 (hostname `strong`, nickname ludo/ludo-mini) | +| **Traefik** | Reverse proxy on IONOS VPS. Serves `*.hubris.network` to the public internet | +| **VAAPI** | Video Acceleration API. Intel/AMD GPU-based hardware transcode for Jellyfin | +| **VPS** | Virtual Private Server at IONOS (`82.165.190.79`). Runs Authentik core + Netbird management | +| **\\*arr** | Media automation suite: Sonarr (TV), Radarr (movies), Lidarr (music), Prowlarr (indexer), Bazarr (subtitles), Readarr (books — not in use) | + +## See also + +- [Infrastructure index](infrastructure/index.md) — cross-cutting systems each with their own doc page +- [OIKOS operating model](OIKOS.md) — agent policy, risk classes, lifecycle \ No newline at end of file diff --git a/README.md b/README.md index 388b506..2c0ab21 100644 --- a/README.md +++ b/README.md @@ -2,39 +2,47 @@ Living documentation for the **hubris** Proxmox homelab. Every node, every cross-cutting system, and every meaningful incident is its own page; pages are linked so you can start anywhere and walk the graph. -> Last refreshed against live state: **2026-04-28**. +> Last refreshed against live state: **2026-07-06**. + +## Quick navigation + +- [Proxmox hosts](#proxmox-hosts) — hubris (primary) + strong (cluster member) +- [VMs](#vms) — ZimaOS, Home Assistant +- [LXC containers](#lxc-containers) — service fleet (17 containers) +- [Cross-cutting infrastructure](#cross-cutting-infrastructure) — DNS, ingress, mesh, storage, auth +- [Investigations](#investigations) — incident timelines +- [Operations](#operations) — cheatsheet, enrollment, runbooks +- [Glossary](GLOSSARY.md) — term definitions +- [Conventions](#conventions) — wiki style, changelog hygiene, same-session update rule ## Map -### Hosts -- [`hubris`](hosts/hubris.md) — Proxmox VE node, GMKtec NucBox M6 Ultra, `192.168.8.77` — runs everything today -- [`strong`](hosts/strong.md) — Proxmox VE node (cluster hostname `strong`), `192.168.178.181` — 2nd member of the `Homelab` cluster as of 2026-07-01, hosts no guests yet +### Proxmox hosts +- [`hubris`](hosts/hubris.md) — PVE node, GMKtec NucBox M6 Ultra, `192.168.8.77` — primary host, runs [8 LXCs](containers/index.md) + 2 VMs +- [`strong`](hosts/strong.md) — PVE node (cluster hostname `strong`), `192.168.178.181` — 2nd member of `Homelab` cluster. Hosts [7 LXCs](containers/index.md) migrated from hubris (Phase 1+2, 2026-07-05) ### VMs - [100 — `zimaos`](vms/100-zimaos.md) — ZimaOS 1.6.1, NAS frontend (evaluation) - [108 — `haos-16.3`](vms/108-haos.md) — Home Assistant OS +- See [vms/index.md](vms/index.md) for the full table ### LXC containers -See the full table in [`containers/index.md`](containers/index.md). Quick links: +See the full table with IPs, hosts, mounts, and status in +[`containers/index.md`](containers/index.md). Quick summary: -| ID | Name | IP | Role | -| --- | ---------------- | --------------- | --------------------------------------------- | -| 101 | [jellyfin](containers/101-jellyfin.md) | 192.168.8.206 | Media server | -| 102 | [nfs-export](containers/102-nfs-export.md) | 192.168.8.200 | NFSv4 re-export of /mnt/library for ZimaOS | -| 103 | [paperless](containers/103-paperless.md) | 192.168.8.130 | Document mgmt | -| 104 | [gitea](containers/104-gitea.md) | 192.168.8.121 | Git server | -| 105 | [apps](containers/105-apps.md) | 192.168.8.205 | Docker host (Artifacto / PlantUML / Portainer / WriteFreely) | -| 114 | [nextcloud](containers/114-nextcloud.md) | 192.168.8.224 | Personal cloud | -| 118 | [elementsynapse](containers/118-elementsynapse.md) | 192.168.8.239 | Matrix Synapse | -| 119 | [sophia](containers/119-sophia.md) | 192.168.8.157 | Sophia | -| 120 | [mule-images](containers/120-mule-images.md) | 192.168.8.136 | Mule-image / mulita photos | -| 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 | -| 130 | [grimmory](containers/130-grimmory.md) | 192.168.8.213 | Digital library (Grimmory — fork of Booklore) | -| 132 | [rclone](containers/132-rclone.md) | 192.168.8.214 | Off-host backup → Proton Drive (rclone + Web GUI) | +- **hubris** (10 active): 102 nfs-export, 103 paperless, 104 gitea, 105 apps, + 114 nextcloud, 119 sophia, 120 mule-images, 121 caddy, 124 authentik (outpost), + 128 trmnl, 132 rclone +- **strong** (7 active): 101 jellyfin, 118 elementsynapse, 122 arriman, + 129 house, 130 grimmory, 133 seanime, 134 romm +- **Destroyed (archaeology)**: 100 arr, 106 flaresolverr, 107 marimo, + 109 syncthing, 110 photoprism, 111 karakeep, 112 immich, 115 reticulum, + 123 claudio-bot, 125 seafile, 126 plato, 127 mule-photos-new — see + [containers/index.md](containers/index.md#recently-destroyed-kept-for-archaeology) ### Cross-cutting infrastructure +- [Infrastructure index](infrastructure/index.md) — map of every cross-cutting system +- [Glossary](GLOSSARY.md) — term definitions - [DNS — split-horizon](infrastructure/dns.md) - [Ingress — Caddy + VPS traefik](infrastructure/ingress.md) - [Mesh — Tailscale → Netbird migration](infrastructure/mesh.md) @@ -47,7 +55,8 @@ See the full table in [`containers/index.md`](containers/index.md). Quick links: - [Homelab context distribution](infrastructure/homelab-context.md) — cross-client `/opt/homelab-context` + MCP + secrets-issuance ### Investigations -Time-stamped incident notes / experiments in [`investigations/`](investigations/index.md). +Time-stamped incident notes / experiments in [`investigations/index.md`](investigations/index.md). +Resolved cases move to [`investigations/archive/`](investigations/archive/). ### Operations - [Command cheatsheet](operations/commands.md) diff --git a/containers/101-jellyfin.md b/containers/101-jellyfin.md index 7386985..597e231 100644 --- a/containers/101-jellyfin.md +++ b/containers/101-jellyfin.md @@ -1,14 +1,14 @@ # 101 — `jellyfin` -Media server: serves the movies / TV / anime / music libraries from `/mnt/library` to LAN clients. Hardware transcoding via AMD Radeon 760M VAAPI. Authentik SSO via OIDC. +Media server: serves the movies / TV / anime / music libraries from `/mnt/media_local` to LAN clients. Hardware transcoding via AMD Radeon 680M + RX 7600 VAAPI. Authentik SSO via OIDC. ## At a glance -- **Hostname:** `jellyfin` -- **IP:** `192.168.8.206` -- **Privilege:** **unprivileged** + idmap (so it can write to the `media` group on `/mnt/library`) +- **Host:** **strong** (migrated from hubris 2026-07-05) +- **IP:** `192.168.8.246` +- **Privilege:** privileged (recreated on strong as priv) - **Resources:** 4 cores / 8 GiB RAM / 1 GiB swap / 16 GiB rootfs -- **GPU:** `/dev/dri/renderD128` (AMD Radeon 760M, RDNA 3) passed via `dev0` in LXC config -- **Mounts:** `/mnt/library` ↔ `/mnt/library` +- **GPU:** `/dev/dri/renderD128` + `/dev/dri/card0` (AMD Radeon 680M iGPU + RX 7600 dGPU) passed via `dev0` / `dev1` in LXC config +- **Mounts:** `/mnt/media_local` ↔ `/mnt/library` - **Public hostname:** [`media.hubris.network`](../infrastructure/dns.md) → [caddy](121-caddy.md) → `:8096` - **Version:** Jellyfin 10.11.11 (apt package, Ubuntu 24.04 noble repo) - **FFmpeg:** jellyfin-ffmpeg7 7.1.4 @@ -21,10 +21,16 @@ Media server: serves the movies / TV / anime / music libraries from `/mnt/librar ## Hardware acceleration (VAAPI) -GPU is passed through to the LXC via `dev0: /dev/dri/renderD128,gid=993` in -`/etc/pve/lxc/101.conf`. The `jellyfin` user is in the `render` (GID 993) and +GPU is passed through to the LXC via `dev0: /dev/dri/renderD128,gid=993` and +`dev1: /dev/dri/card0,gid=44` in +`/etc/pve/lxc/101.conf` (strong). The `jellyfin` user is in the `render` (GID 993) and `video` groups inside the container. +| GPU | Model | Role | +|-----|-------|------| +| Radeon 680M | iGPU (AMD Ryzen 7 PRO 6850U) | Primary VAAPI encoder/decoder | +| RX 7600 | dGPU (add-in) | Secondary transcode, HEVC/AV1 encoding | + Encoding settings (`/etc/jellyfin/encoding.xml`): - `HardwareAccelerationType`: `vaapi` - `VaapiDevice`: `/dev/dri/renderD128` @@ -120,7 +126,7 @@ User → media.hubris.network → Caddy (TLS, no forward-auth) → Jellyfin :809 ``` ## Permissions -Member of the [media GID 10000](../infrastructure/media-permissions.md) standard. Service user `jellyfin` is in the `media` group inside the container; idmap block in `/etc/pve/lxc/101.conf` maps in-container GID 10000 to host GID 10000. +Member of the [media GID 10000](../infrastructure/media-permissions.md) standard. Service user `jellyfin` is in the `media` group inside the container; `/mnt/media_local` on strong's ludo-lvm is owned `root:media` with mode `2775`. ## Related - [Caddy reverse proxy](121-caddy.md) @@ -131,6 +137,9 @@ Member of the [media GID 10000](../infrastructure/media-permissions.md) standard ## Changelog +### 2026-07-06 — wiki: IP, host, GPU, mount path updated for strong migration +Updated At-a-glance: IP 206→246, host hubris→strong, mount /mnt/library→/mnt/media_local, GPU Radeon 760M→680M+RX7600, privilege unpriv→priv. Permissions section updated. Changelog entry in 122-arriman.md updated similarly. + ### 2026-07-04 — VAAPI hardware acceleration + Authentik SSO + resource bump - Upgraded Jellyfin 10.11.8 → 10.11.11 (purge + reinstall to fix DB migration bug) - Enabled VAAPI hardware acceleration (Radeon 760M): h264/hevc/vc1/vp9/av1 decode + encode diff --git a/containers/118-elementsynapse.md b/containers/118-elementsynapse.md index c40be73..e552a08 100644 --- a/containers/118-elementsynapse.md +++ b/containers/118-elementsynapse.md @@ -4,7 +4,8 @@ Matrix homeserver (Synapse). Backs `@dtoro:avispero`. ## At a glance - **Hostname:** `elementsynapse` -- **IP:** `192.168.8.239` +- **IP:** `192.168.8.242` +- **Host:** **strong** (migrated from hubris 2026-07-05) - **Privilege:** **unprivileged** - **Resources:** 1 core / 2 GiB RAM / **16 GiB rootfs** (grown from 8 GiB on 2026-05-15 after disk-full incident) - **Mounts:** none from `/mnt/library` diff --git a/containers/121-caddy.md b/containers/121-caddy.md index 0f316e1..3e7ff19 100644 --- a/containers/121-caddy.md +++ b/containers/121-caddy.md @@ -11,16 +11,16 @@ The reverse proxy. Terminates TLS for every `*.hubris.network` hostname on the L - **Config:** `/etc/caddy/Caddyfile` is a [git checkout of `dtoro/caddy-conf`](#auto-deploy) - **Cert source:** Let's Encrypt **DNS-01** via IONOS API (`IONOS_AUTH_API_TOKEN`). -## Sites currently served (live as of 2026-04-28) +## Sites currently served (live as of 2026-07-06) - `artifacto.hubris.network` → [apps (105)](105-apps.md) `:3100` -- `auth.hubris.network` → [authentik (124)](124-authentik.md) `:9000` - `blog.hubris.network` → [apps (105)](105-apps.md) `:8080` -- `books.hubris.network` → [apps (105)](105-apps.md) `:6060` +- `books.hubris.network` → [grimmory (130)](130-grimmory.md) `:6060` - `cloud.hubris.network` → [nextcloud (114)](114-nextcloud.md) `:443` - `docker.hubris.network` → [apps (105)](105-apps.md) `:9443` - `git.hubris.network` → [gitea (104)](104-gitea.md) `:3000` (+ `handle_path /_plantuml/*` → apps `:8079`) - `home.hubris.network` → [haos VM (108)](../vms/108-haos.md) `192.168.8.101:8123` +- `house.hubris.network` → [house (129)](129-house.md) `:3000` - `jellyseerr.hubris.network` → [arriman (122)](122-arriman.md) `:5056` - `matrix.hubris.network` → [elementsynapse (118)](118-elementsynapse.md) `:8008` - `media.hubris.network` → [jellyfin (101)](101-jellyfin.md) `:8096` @@ -28,7 +28,10 @@ The reverse proxy. Terminates TLS for every `*.hubris.network` hostname on the L - `photos.hubris.network` → [mule-images (120)](120-mule-images.md) `:3000` - `proxmox.hubris.network` → [hubris host](../hosts/hubris.md) `:8006` - `qbit.hubris.network` → [arriman (122)](122-arriman.md) `:8080` +- `roms.hubris.network` → [romm (134)](134-romm.md) `:80` - `sab.hubris.network` → [arriman (122)](122-arriman.md) `:8082` (Authentik forward-auth) +- `teddy.hubris.network` → LXC 131 `192.168.8.150:8443` +- `trmnl.hubris.network` → [trmnl (128)](128-trmnl.md) `:9851` > **Reminder:** Caddy alone isn't enough to make a new subdomain reachable on the LAN. Each one needs an entry in [DNS split-horizon](../infrastructure/dns.md) too. diff --git a/containers/122-arriman.md b/containers/122-arriman.md index daeea14..1e5a0d4 100644 --- a/containers/122-arriman.md +++ b/containers/122-arriman.md @@ -4,10 +4,11 @@ Docker host running the \*arr stack via [`ezarr`](https://github.com/ezarr/ezarr ## At a glance - **Hostname:** `arriman` -- **IP:** `192.168.8.132` +- **IP:** `192.168.8.245` +- **Host:** **strong** (migrated from hubris 2026-07-05) - **Privilege:** privileged - **Resources:** 4 cores / 8 GiB RAM / 24 GiB rootfs -- **Mounts:** `/mnt/library` ↔ `/mnt/library` +- **Mounts:** `/mnt/media_local` ↔ `/mnt/library` - **Public hostnames:** `jellyseerr` / `qbit` / `sab` (see below) ## Compose diff --git a/containers/129-house.md b/containers/129-house.md index a998c6f..333fabb 100644 --- a/containers/129-house.md +++ b/containers/129-house.md @@ -5,7 +5,8 @@ Yuvomi family planner (formerly Oikos). Self-hosted family planner with 14 modul ## At a glance - **Hostname:** `house` -- **IP:** `192.168.8.212` (static) +- **IP:** `192.168.8.244` +- **Host:** **strong** (migrated from hubris 2026-07-05) - **Privilege:** unprivileged - **Resources:** 1 core / 1344 MiB RAM / 8 GiB rootfs (Debian 13) - **Mounts:** none diff --git a/containers/130-grimmory.md b/containers/130-grimmory.md index ff27789..8800200 100644 --- a/containers/130-grimmory.md +++ b/containers/130-grimmory.md @@ -5,17 +5,18 @@ Self-hosted digital library (eBooks, comics, audiobooks). Community fork/success ## At a glance - **Hostname:** `grimmory` -- **IP:** `192.168.8.213` (static, set in PVE `net0` config — same pattern as all other LXCs) +- **IP:** `192.168.8.247` +- **Host:** **strong** (migrated from hubris 2026-07-05) - **Privilege:** privileged (UID = host UID for `/mnt/library` media GID) - **Resources:** 1 core / 2 GiB RAM / 16 GiB rootfs (Debian 13) -- **Mounts:** `/mnt/library` +- **Mounts:** `/mnt/media_local` ↔ `/mnt/library` - **Public hostname:** `books.hubris.network` ## Service / port map | Service | Listen | Notes | |---------|--------|-------| -| Grimmory | `192.168.8.213:6060` | Docker Compose at `/opt/grimmory/` | +| Grimmory | `192.168.8.247:6060` | Docker Compose at `/opt/grimmory/` | | MariaDB | internal only | Sidecar in the same compose stack | ## Compose @@ -43,7 +44,7 @@ Uses Confidential client (client secret stored in Grimmory's DB — migrated fro - **Client type:** Confidential (client secret in `oidc_provider_details` in MariaDB `app_settings`) - **Redirect URI:** `https://books.hubris.network/oauth2-callback` - **Scopes:** openid, profile, email, offline_access -- **Back-channel logout:** `http://192.168.8.213:6060/api/v1/auth/oidc/backchannel-logout` +- **Back-channel logout:** `http://192.168.8.247:6060/api/v1/auth/oidc/backchannel-logout` - **Application slug:** `booklore` → Issuer URI: `https://auth.hubris.network/application/o/booklore/` ## Media permissions @@ -53,7 +54,7 @@ LXC is privileged → in-container UID = host UID. Docker container gets media G ## Related - [apps (105)](105-apps.md) — previous host (Booklore) -- [Caddy (121)](121-caddy.md) — `books.hubris.network → 192.168.8.213:6060` +- [Caddy (121)](121-caddy.md) — `books.hubris.network → 192.168.8.247:6060` - [Authentik (124)](124-authentik.md) — OIDC provider `Grimmory` - [DNS (107)](107-dns.md) — `books.hubris.network → 192.168.8.175` (unchanged from Booklore) - [Media permissions](../infrastructure/media-permissions.md) diff --git a/containers/123-claudio-bot.md b/containers/archive/123-claudio-bot.md similarity index 100% rename from containers/123-claudio-bot.md rename to containers/archive/123-claudio-bot.md diff --git a/containers/127-mule-photos-new.md b/containers/archive/127-mule-photos-new.md similarity index 100% rename from containers/127-mule-photos-new.md rename to containers/archive/127-mule-photos-new.md diff --git a/containers/index.md b/containers/index.md index c7a804b..9c6668a 100644 --- a/containers/index.md +++ b/containers/index.md @@ -31,7 +31,7 @@ Most containers live on [`hubris`](../hosts/hubris.md). Some have been | 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) | +| 123 | claudio-bot (destroyed — see [archive](archive/123-claudio-bot.md)) | 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 | | 107 | marimo | between 2026-04-21 and 2026-04-28 | Decommissioned | diff --git a/hosts/strong.md b/hosts/strong.md index 597e27c..1778a4b 100644 --- a/hosts/strong.md +++ b/hosts/strong.md @@ -6,7 +6,7 @@ Proxmox VE on 2026-07-01. No LXCs/VMs deployed on it yet. ## At a glance -- **Role:** Proxmox VE 9.2.3 cluster member (kernel `7.0.12-1-pve`) +- **Role:** Proxmox VE 9.2.3 cluster member (kernel `7.0.12-1-pve`) — hosts [7 LXCs](../containers/index.md) migrated from hubris (Phase 1+2, 2026-07-05) - **Naming:** the OS/cluster hostname is `strong` (leftover from install, kept as-is). This wiki page and `inventory.yaml` also use `strong` as of 2026-07-01 — earlier the same day the inventory entry was briefly named diff --git a/infrastructure/index.md b/infrastructure/index.md new file mode 100644 index 0000000..3b86737 --- /dev/null +++ b/infrastructure/index.md @@ -0,0 +1,66 @@ +# Infrastructure — cross-cutting systems + +The homelab's shared infrastructure: systems that span multiple nodes and +are documented in their own pages. Each system below links to its full doc. + +## Network + +- **[Network](network.md)** — physical topology, subnets, routing, DHCP. + Homelab `192.168.8.0/24` isolated from household `192.168.178.0/24`. + Proxmox hubris acts as subnet router. +- **[DNS — split-horizon](dns.md)** — Technitium DNS on LXC 107, + `192.168.8.2:53`. `*.hubris.network` resolves to LAN IPs on the homelab + network and to mesh addresses off-LAN. + +## Connectivity / mesh + +- **[Mesh — Tailscale → Netbird migration](mesh.md)** — overlay networking. + Netbird is the preferred path; Tailscale is legacy. +- **[SSH access](ssh-access.md)** — dual-server SSH (OpenSSH + Netbird SSH) + on hubris, key distribution. + +## Public ingress + +- **[Public ingress — VPS traefik + cert mirror](ingress.md)** — how home + services reach the open internet. Two-stage: VPS traefik (IONOS) terminates + TLS, proxies over Netbird to home Caddy. +- **[Caddy reverse proxy](../containers/121-caddy.md)** — LAN endpoint. + Terminates TLS for every `*.hubris.network` hostname, forwards to backends. + +## Storage + +- **[Media permissions — GID 10000 standard](media-permissions.md)** — shared + group permission model across all LXCs that read/write the media library. +- **[Backups — rclone → Proton Drive](backups.md)** — off-host backup strategy. + LXC 132 handles rclone to Proton Drive; restic-on-USB deprecated. + +## Identity & access + +- **[Authentik SSO](../containers/124-authentik.md)** — identity provider. + Core server runs on the VPS; LAN forward-auth outpost at LXC 106. + OIDC providers configured for Jellyfin, Jellyseerr, Sabnzbd, qBittorrent, + Yuvomi, and more. + +## Management & automation + +- **[Homelab context distribution](homelab-context.md)** — `/opt/homelab-context` + clone, MCP server, secrets issuance, cross-client sync. +- **[Auto-deploy — gitea-webhook pipelines](auto-deploy.md)** — push-to-deploy + for Caddy config, mule-image, and other tracked repos. +- **[Monitoring](monitoring.md)** — health checks, watchdogs, alerting + (migrated from claudio-bot to Hermes cron). +- **[VPS hardening](vps-hardening.md)** — IONOS netbird VPS: fail2ban, + nftables, OIDC SSH, security posture. + +## Topology + +- **[Topology diagram (generated)](topology.md)** — Mermaid graph of compute, + ingress routing, and storage mounts. Auto-generated from `inventory.yaml` + by `oikos/gen-topology.py`. + +## Related + +- [README](../README.md) — entry point +- [Containers index](../containers/index.md) +- [Operations cheatsheet](../operations/commands.md) +- [OIKOS operating model](../OIKOS.md) \ No newline at end of file diff --git a/investigations/2026-04-21-hubris-crash-loop.md b/investigations/archive/2026-04-21-hubris-crash-loop.md similarity index 100% rename from investigations/2026-04-21-hubris-crash-loop.md rename to investigations/archive/2026-04-21-hubris-crash-loop.md diff --git a/investigations/2026-05-31-authentik-vps-migration.md b/investigations/archive/2026-05-31-authentik-vps-migration.md similarity index 100% rename from investigations/2026-05-31-authentik-vps-migration.md rename to investigations/archive/2026-05-31-authentik-vps-migration.md diff --git a/investigations/index.md b/investigations/index.md index 377fc10..6ea255e 100644 --- a/investigations/index.md +++ b/investigations/index.md @@ -2,14 +2,23 @@ Time-stamped incident reports and experiments. One entry per incident; the entry is the canonical source. Per-node changelog entries link back here. -## Index +## Active / recent | Date | Title | Status | | ------------ | ------------------------------------------------------------------ | ------------- | -|| 2026-06-06 | [Frequent Authentik login prompts — session lifetime fix](2026-06-06-authentik-session-lifetime.md) | Resolved — `session_duration=days=30`, `SESSION_COOKIE_AGE=30d` | -|| 2026-05-31 | [Authentik migrated from LXC 124 to the VPS](2026-05-31-authentik-vps-migration.md) | Resolved; LXC 124 Authentik in ~2-week dual-run before decommission | +| 2026-06-06 | [Caddyfile truncation incident](2026-06-06-caddyfile-truncation.md) | Resolved — permanent safeguards deployed (site-count guard, auto-stash, auto-backup) | +| 2026-06-06 | [Frequent Authentik login prompts — session lifetime fix](2026-06-06-authentik-session-lifetime.md) | Resolved — `session_duration=days=30`, `SESSION_COOKIE_AGE=30d` | | 2026-06-03 | [Moonlight/Sunshine streaming — WiFi jitter](2026-06-03-moonlight-sunshine-wifi-jitter.md) | Mitigations applied; definitive fix requires wiring mac-mini via Ethernet | -| 2026-04-21 | [Hubris crash loop — thermal + USB drive](2026-04-21-hubris-crash-loop.md) | Drive removal A/B test passing as of 2026-04-28 (3+ days uptime) | +| 2026-06-01 | [Mac-mini onboarding](2026-06-01-mac-mini-onboarding.md) | Onboarded | + +## Resolved (archived) + +See [`archive/`](archive/): + +| Date | Title | +| ------------ | ------------------------------------------------------------------ | +| 2026-04-21 | [Hubris crash loop — thermal + USB drive](archive/2026-04-21-hubris-crash-loop.md) | +| 2026-05-31 | [Authentik migrated from LXC 124 to the VPS](archive/2026-05-31-authentik-vps-migration.md) | ## Conventions @@ -17,3 +26,4 @@ Time-stamped incident reports and experiments. One entry per incident; the entry - Mandatory sections: Summary, Timeline, Root cause, Mitigations applied, Open questions. - Update the entry as the situation evolves; never rewrite history. Add new dated sections at the bottom. - Link back from every node's changelog that's affected. +- Move to `archive/` when the incident is fully resolved and no longer actively referenced. \ No newline at end of file diff --git a/plans/2026-06-01-slate-ax-to-sodola-migration.md b/plans/done/2026-06-01-slate-ax-to-sodola-migration.md similarity index 100% rename from plans/2026-06-01-slate-ax-to-sodola-migration.md rename to plans/done/2026-06-01-slate-ax-to-sodola-migration.md diff --git a/plans/2026-06-04_130000-deprecate-claudio-bot.md b/plans/done/2026-06-04_130000-deprecate-claudio-bot.md similarity index 100% rename from plans/2026-06-04_130000-deprecate-claudio-bot.md rename to plans/done/2026-06-04_130000-deprecate-claudio-bot.md diff --git a/plans/2026-06-25-yuvomi-deployment.md b/plans/done/2026-06-25-yuvomi-deployment.md similarity index 100% rename from plans/2026-06-25-yuvomi-deployment.md rename to plans/done/2026-06-25-yuvomi-deployment.md diff --git a/plans/2026-06-29-grimmory-migration.md b/plans/done/2026-06-29-grimmory-migration.md similarity index 100% rename from plans/2026-06-29-grimmory-migration.md rename to plans/done/2026-06-29-grimmory-migration.md diff --git a/plans/index.md b/plans/index.md index a202ce0..09798ba 100644 --- a/plans/index.md +++ b/plans/index.md @@ -1,19 +1,29 @@ # Plans -Pre-flight runbooks for planned changes that haven't happened yet. Once executed, move the outcome to `investigations/` (if anything interesting happened) or just a changelog entry on the affected node pages. +Pre-flight runbooks for planned changes. When a plan is executed, move it to +[`done/`](done/) and add changelog entries on affected node pages. If things +went sideways, open an investigation. -## Index +## Active | Date | Title | Status | | ---- | ----- | ------ | | 2026-06-24 | [TRMNL plugins LXC (128) + middleware deploy pipeline](2026-06-24-trmnl-plugins-lxc.md) | In Progress | -| 2026-06-25 | [Yuvomi deployment — house.hubris.network](2026-06-25-yuvomi-deployment.md) | Done | -| 2026-06-24 | [TRMNL plugins LXC (128) + middleware deploy pipeline](2026-06-24-trmnl-plugins-lxc.md) | In Progress | -| 2026-06-01 | [Slate AX → SODOLA managed switch migration](2026-06-01-slate-ax-to-sodola-migration.md) | Done | + +## Done + +See [`done/`](done/) for executed plans: + +| Date | Title | +| ---- | ----- | +| 2026-06-01 | [Slate AX → SODOLA managed switch migration](done/2026-06-01-slate-ax-to-sodola-migration.md) | +| 2026-06-04 | [Deprecate claudio-bot](done/2026-06-04_130000-deprecate-claudio-bot.md) | +| 2026-06-25 | [Yuvomi deployment — house.hubris.network](done/2026-06-25-yuvomi-deployment.md) | +| 2026-06-29 | [Grimmory migration — Booklore → dedicated LXC](done/2026-06-29-grimmory-migration.md) | ## Conventions - File name: `YYYY-MM-DD-.md`. Use the *target* date if known, otherwise the planning date. -- Status: `Planned` → `In Progress` → `Done` (update index entry as it moves). -- When done: add a changelog entry on every affected node page, then update status to `Done` here. If things went sideways, open an investigation. -- Plans are append-only once execution starts — don't rewrite pre-flight intent after the fact. +- Status: `Planned` → `In Progress` → `Done` (move to `done/` on completion). +- When done: add a changelog entry on every affected node page, then move the file to `done/`. +- Plans are append-only once execution starts — don't rewrite pre-flight intent after the fact. \ No newline at end of file diff --git a/operations/runbook-budget-from-csv.md b/runbooks/runbook-budget-from-csv.md similarity index 98% rename from operations/runbook-budget-from-csv.md rename to runbooks/runbook-budget-from-csv.md index 61e4e0e..c0ccf8d 100644 --- a/operations/runbook-budget-from-csv.md +++ b/runbooks/runbook-budget-from-csv.md @@ -1,3 +1,10 @@ +--- +name: budget-import-from-csv +risk_class: config_mutation +inputs: [csv_file] +references: [containers/129-house.md] +--- + # Runbook: Budget import from N26 CSV → Yuvomi Distil a bank-export CSV into Yuvomi's Budget and Subscriptions modules using diff --git a/operations/runbook-dpkg-interrupted.md b/runbooks/runbook-dpkg-interrupted.md similarity index 96% rename from operations/runbook-dpkg-interrupted.md rename to runbooks/runbook-dpkg-interrupted.md index 5b1ff8a..3e71f15 100644 --- a/operations/runbook-dpkg-interrupted.md +++ b/runbooks/runbook-dpkg-interrupted.md @@ -1,3 +1,9 @@ +--- +name: recover-dpkg-interrupted +risk_class: reversible_low +verification: "dpkg --audit (should be clean); apt-get check" +--- + # Runbook — recover from dpkg-interrupted state You're here because an apt run got killed mid-transaction and the target now diff --git a/vms/index.md b/vms/index.md new file mode 100644 index 0000000..ad649c1 --- /dev/null +++ b/vms/index.md @@ -0,0 +1,14 @@ +# VMs — index + +Two QEMU VMs running on [hubris](../hosts/hubris.md): + +| ID | Name | Role | IP | Public hostname | +|----|------|------|----|-----------------| +| 100 | [zimaos](100-zimaos.md) | NAS frontend eval (ZimaOS) | `192.168.8.195` | [`zimaos.hubris.network`](../infrastructure/dns.md) | +| 108 | [haos-16.3](108-haos.md) | Home automation (HAOS) | `192.168.8.101` | [`home.hubris.network`](../infrastructure/dns.md) | + +## Related + +- [Hubris host](../hosts/hubris.md) — both VMs run here +- [Containers index](../containers/index.md) — LXCs on both nodes +- [README](../README.md) \ No newline at end of file