Files
oikos/hosts/strong.md
dtoro fd35b48c8d Phase 1-4: full doc reorg
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)
2026-07-06 00:46:27 +02:00

11 KiB

strong — Proxmox host

Second node in the Homelab cluster, alongside hubris. Formerly a Linux dev workstation nicknamed "ludo" (or "ludo-mini") — reformatted to 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) — hosts 7 LXCs 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 ludo-mini, but that was renamed so the hostname bootstrap needs (hosts/$(hostname).yaml) would just resolve. "Ludo"/"ludo-mini" remains the machine's everyday nickname; some older docs (investigations, the library-SSD migration plan) still refer to it that way — that's fine, those are historical.
  • Hardware: AMD Ryzen 7 PRO 6850U, 16 threads, 28 GiB RAM.
    • nvme0n1 — MasonSemi MC3100 1TB (boot/OS): pve-root 96G, pve-data (thinpool) 815G, 8G swap.
    • nvme1n1 — WD_BLACK SN7100 2TB, added 2026-07-01. Arrived with an existing APFS partition (previously used in a Mac) — wiped via pvesh set nodes/strong/disks/wipedisk --disk /dev/nvme1n1, then turned into its own LVM-thin pool via pvesh create nodes/strong/disks/lvmthin (handles pvcreate/vgcreate/lvcreate + storage.cfg registration in one step). Registered as Proxmox storage ludo-lvm (VG ludo-lvm, thinpool ludo-lvm, ~1.8 TiB usable — kept the ludo-lvm name since that's what was actually created live; not worth renaming), restricted nodes strong in /etc/pve/storage.cfg — same pattern as hubris's library pool. Empty so far; this is separate from the library-SSD migration plan's planned drive move from hubris (that hasn't happened) — this is general-purpose VM/CT capacity.
  • Network: vmbr0 is bridged straight onto the household LAN — 192.168.178.181/24, gateway 192.168.178.1. Unlike hubris, there is no internal/uplink bridge split yet — vmbr0 here plays the role hubris's vmbr1 plays there. Reachable from the homelab subnet (192.168.8.0/24) via the existing Fritz!Box static route through hubris; no new cabling or routing was needed to join the cluster.
  • Storage: local + local-lvm (cluster-wide default names, shared with hubris by convention, actually separate per-node volumes). Hubris's library lvmthin pool is restricted to nodes hubris in /etc/pve/storage.cfg and does not exist here.
  • Mesh: Netbird not installed — fresh OS wiped whatever the old workstation had. Reachable today only via LAN routing (confirmed DNS for *.hubris.network already resolves correctly here via 192.168.8.2). Add to Netbird if off-LAN access to this host itself (distinct from any future guests) is needed.
  • Homelab-context client enrollment: done 2026-07-01 via bootstrap.sh --no-secrets (reused the operator's existing Gitea PAT for the initial clone). /opt/homelab-context, the homelab CLI, and the 5-min sync timer are live; homelab whoami resolves correctly. See agent-enrollment.md.
  • Age key / secrets: issued the same day over plain LAN (no Netbird needed — see the --no-mesh bootstrap.sh fix below). Key lives at /etc/age/key.txt; pubkey age1rtwvdct6avjkr3cyxv3vue3vqx4d524fjfr3vk7xrnvyrylnry5sm54sn4 recorded in inventory.yaml. Not yet a recipient on any actual secret (hello.yaml, gitea-pat.yaml, etc.) — that's a separate grant, see "Granting a secret to a new client".

Cluster membership

Joined hubris's single-node cluster (Homelab) via pvecm add on 2026-07-01. See hosts/hubris.md#cluster for the full cluster picture, node IDs, and the quorum tradeoff (2 nodes, no QDevice — either node going down freezes management on the survivor).

SSH

Root login via the same key set trusted on hubris (root@hubris, d.toro.v@pm.me) — installed 2026-07-01 by appending to /root/.ssh/authorized_keys (now symlinked to /etc/pve/priv/authorized_keys post cluster-join, so it's cluster-synced same as hubris). No password auth needed going forward.

Changelog

2026-07-05 — Phase 2d: grimmory (130) migrated to strong

Migrated book library from hubris (192.168.8.213) to strong (192.168.8.247). Rsync'd /books (2.6G) from hubris library SSD to ludo-lvm/media. Container mounts /mnt/media_local → /mnt/library locally. Caddy backend for books.hubris.network updated.

2026-07-05 — Phase 2: arriman (122) + jellyfin (101) migrated; library on ludo-lvm

Migrated arriman (→ 192.168.8.245) and jellyfin (→ 192.168.8.246) to strong. Created 1.5T thin volume on ludo-lvm for media library (/mnt/media_local). Rsync'd 363G of media data (movies, tv, anime, downloads, music) from hubris library SSD to ludo-lvm. Both containers now mount /mnt/media_local directly as local ext4 — no NFS cross-node dependency. Jellyfin gets Radeon 680M iGPU (for VAAPI) + RX 7600 dGPU passthrough via dev0/dev1. Caddy backends updated for media, jellyseerr, qbit, sab. Hubris freed 16 GiB RAM (8+8). Dhcp scope narrowed to 192.168.8.100-239.

2026-07-05 — house (LXC 129) migrated to strong; DHCP scope narrowed

Migrated Yuvomi family planner from hubris (192.168.8.212) to strong (192.168.8.244). Followed same restore pattern as elementsynapse (Phase 1b). Discovered IP conflict: teddycloud (LXC 131) had 192.168.8.243 via DHCP (scope was 192.168.8.241-254). Narrowed DHCP scope to 192.168.8.100-239, gave teddycloud static IP 192.168.8.150. Caddy updated: house.hubris.network → 192.168.8.244:3000, teddy.hubris.network → 192.168.8.150:8443.

2026-07-05 — elementsynapse (LXC 118) migrated to strong

Migrated Matrix/Synapse + Element client from hubris (192.168.8.239) to a new LXC on strong (192.168.8.242). Added vmbr1 on strong at 192.168.8.241/28 (portless internal bridge) for strong-hosted guests. Enabled IP forwarding, proxy ARP on hubris vmbr0, and specific /32 routes for strong's guest subnet. Caddy updated: element.hubris.network → 192.168.8.242:8080. VPS traefik updated: matrix.hubris.network backend → 192.168.8.242:8008. This is Phase 1a of the strong migration plan — see .hermes/plans/2026-07-05_strong-migration-assessment.md.

2026-07-01 — age key issued over LAN; 3 bugs found/fixed in bootstrap.sh

Re-ran bootstrap without --no-secrets to get a real age key. Hit three real bugs live, fixed all three in bootstrap.sh and re-ran clean:

  1. The mcp-CLI pipx-install step and the (unused, --with-hermes-only) Goose installer both called sudo -u <user> unconditionally — fails with "sudo: command not found" on a minimal root-only image with no sudo binary at all. Added a run_as() helper that only shells out to sudo when there's a real distinct invoking user.
  2. sops isn't an apt/dnf package (matches what agent-enrollment.md's manual-install recipe already does) — the auto-installer tried apt-get install sops and failed outright. Added install_sops_binary(), fetching the GitHub release binary directly on both dnf and apt paths.
  3. Bigger one: running without --no-secrets unconditionally tries to install + interactively connect Netbird (device-code SSO), even though the very next check already knows how to accept plain LAN reachability instead. Over SSH with nobody watching, this hangs forever — had to manually kill a stuck netbird up process. Added --no-mesh, which skips the Netbird install/connect step but keeps the LAN-fallback path for secrets issuance. This run used bootstrap.sh --no-mesh and completed cleanly: mesh: lan, age key installed, mcp CLI installed via pipx (proving fix #1 too).

Result: age key at /etc/age/key.txt, pubkey recorded in inventory.yaml. Not yet granted access to any actual secret file — see the note above.

2026-07-01 — enrolled as a homelab-context client

Ran bootstrap.sh --no-secrets (reused the operator's existing personal Gitea PAT for the initial clone rather than minting a fresh read-only one). Installed git, cloned /opt/homelab-context, installed the 5-min systemd sync timer, symlinked homelab CLI and AGENTS.md. Skipped age-key/secrets issuance and Netbird per operator choice — but bootstrap's own connectivity check reported mesh: lan, i.e. the secrets-issuance endpoint is already reachable over plain LAN, so re-running without --no-secrets later wouldn't require a Netbird join. Known gap: the mcp pipx CLI install step silently failed (sudo: command not found — bootstrap.sh's pipx step assumes a sudo binary even when already root; harmless, only affects the homelab mcp <tool> shell subcommand).

2026-07-01 — inventory identity renamed ludo-mini → strong

Discovered while starting client enrollment: bootstrap.sh looks up hosts/$(hostname).yaml, and the OS hostname here is strong, not ludo-mini. Renaming the OS hostname was ruled out (already a cluster member — Proxmox doesn't support in-place node rename, only leave+rejoin). Renamed the wiki/inventory side instead: inventory.yaml key, this page (hosts/ludo-mini.mdhosts/strong.md), README, ssh-access.md all now say strong. "Ludo"/"ludo-mini" is still fine as a spoken nickname.

2026-07-01 — 2nd NVMe added; new LVM-thin pool ludo-lvm

User added a WD_BLACK SN7100 2TB (nvme1n1), previously used in a Mac (arrived with an EFI + APFS partition table — confirmed disposable, wiped). Used Proxmox's own disk-management API rather than raw LVM commands: pvesh set nodes/strong/disks/wipedisk --disk /dev/nvme1n1 to clear the old partition table/signatures, then pvesh create nodes/strong/disks/lvmthin --name ludo-lvm --device /dev/disk/by-id/nvme-WD_BLACK_SN7100_2TB_251663803202 --add_storage 1 to create the PV/VG/thinpool and register it as Proxmox storage in one step. Result: storage ID ludo-lvm, ~1.8 TiB, content rootdir,images, nodes strong (mirrors hubris's library node-restriction pattern — this pool only physically exists here). Empty — no VM/CT disks placed on it yet.

2026-07-01 — Proxmox install; joined Homelab cluster

Reformatted from Linux workstation to Proxmox VE 9.2.3. SSH keys seeded from hubris's trusted set (root password used once, then discarded). Joined the existing Homelab cluster via pvecm add 192.168.8.77 --use_ssh 1 from this node's side, using key-based SSH pre-authorized in both directions — no interactive password prompt needed for the join itself. Cluster now 2 nodes (hubris, strong), quorate, no QDevice. Decided to leave hostname as strong and skip a QDevice for now — both revisitable later.