Add the foundation for distributing homelab context to every client (LXCs, VMs, workstations including republic-laptop, mac-mini, ludo-mini) with a single source of truth, structured query layer (MCP), and per-client age-key issuance for secrets: - inventory.yaml — canonical topology (hosts, services, mesh addresses) - hosts/*.yaml — per-host identity files generated from inventory by mcp/build_host_files.py; do not edit by hand - AGENTS.md — orientation doc symlinked to /root/AGENTS.md on every client - bootstrap.sh — one-shot enroll (Linux + macOS), clones repo, fetches age key from issuance, installs sync timer/launchd job, drops the homelab CLI - bin/homelab — single-binary Python CLI: whoami, list, ssh, pct, logs, restart, open, status, secret, sync, mcp, client add/remove, nuke - mcp/server.py — FastMCP server: context tools + read-only management tools (no mutations exposed); shell-outs use mcp-reader restricted ssh key - mcp/deploy/ — claudio-monitor-style gitea webhook deploy scaffold for the MCP service on LXC 105 (ports 9810 mcp, 9811 webhook) - secrets-issuance/ — per-client age key auto-provisioning over the mesh; source-IP gated against inventory, with denylist for revoked clients (ports 9820 issue, 9821 webhook) - secrets/, .sops.yaml — SOPS recipient scaffolding; the operator fills in age public keys after Phase 3a generates them - scripts/sync/ — systemd timer (Linux) + launchd plist (macOS) pulling /opt/homelab-context every 5 min Mesh: both Netbird (preferred, 100.122.0.0/16) and Tailscale accepted during the in-flight migration; no client is gated on completing the move. Plan reference: /root/.claude/plans/lets-make-a-plan-fluttering-trinket.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
366 lines
8.9 KiB
YAML
366 lines
8.9 KiB
YAML
# Homelab inventory — canonical structured topology
|
|
#
|
|
# This file is the single source of truth for hosts, services, and mesh
|
|
# addresses. Everything in hosts/*.yaml is generated from this file by
|
|
# mcp/build_host_files.py — do not edit hosts/*.yaml by hand.
|
|
#
|
|
# Conventions:
|
|
# - hostname keys here MUST match the actual `hostname` of the machine
|
|
# (or, on macOS, `scutil --get LocalHostName` if set).
|
|
# - `os:` one of: linux, macos
|
|
# - `kind:` one of: proxmox-host, lxc, vm, workstation
|
|
# - `mesh:` lists addresses the host is reachable at. Both `netbird` and
|
|
# `tailscale` are accepted during the in-flight migration
|
|
# (see infrastructure/mesh.md). Prefer netbird FQDNs over raw IPs.
|
|
# - `age_pubkey:` is provisioned by the secrets-issuance service on first
|
|
# bootstrap and committed back here. New entries leave it empty.
|
|
# - When a service moves hosts, update only the `services:` section here;
|
|
# never duplicate the address elsewhere.
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Static config (mesh + service endpoints)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
mesh:
|
|
primary: netbird # preferred for new clients
|
|
accepted: [netbird, tailscale]
|
|
netbird_subnet: 100.122.0.0/16
|
|
netbird_domain: netbird.selfhosted
|
|
|
|
# Top-level service registry. Each entry resolves to a host above plus a URL.
|
|
services:
|
|
proxmox_ui:
|
|
url: https://proxmox.hubris.network
|
|
backend: hubris
|
|
port: 8006
|
|
|
|
gitea:
|
|
url: https://git.hubris.network
|
|
backend: gitea
|
|
backend_url: http://192.168.8.121:3000
|
|
|
|
caddy:
|
|
backend: caddy
|
|
role: reverse-proxy
|
|
note: terminates all *.hubris.network
|
|
|
|
authentik:
|
|
url: https://auth.hubris.network
|
|
backend: authentik
|
|
|
|
dnsmasq:
|
|
backend: authentik
|
|
note: split-horizon DNS, /etc/dnsmasq.d/hubris-split.conf
|
|
|
|
jellyfin:
|
|
url: https://media.hubris.network
|
|
backend: jellyfin
|
|
|
|
nextcloud:
|
|
url: https://cloud.hubris.network
|
|
backend: nextcloud
|
|
|
|
paperless:
|
|
url: https://paperless.hubris.network
|
|
backend: paperless
|
|
|
|
matrix:
|
|
url: https://matrix.hubris.network
|
|
backend: elementsynapse
|
|
|
|
photos:
|
|
url: https://photos.hubris.network
|
|
backend: mule-images
|
|
|
|
photos_new:
|
|
url: https://photos-new.hubris.network
|
|
backend: mule-photos-new
|
|
|
|
plato:
|
|
url: https://plato.hubris.network
|
|
backend: plato
|
|
|
|
arr_stack:
|
|
backend: arriman
|
|
note: jellyseerr / qbit / sab on docker compose
|
|
|
|
artifacto:
|
|
backend: apps
|
|
url: https://artifacto.hubris.network
|
|
|
|
zimaos:
|
|
url: https://zimaos.hubris.network
|
|
backend: zimaos
|
|
|
|
haos:
|
|
backend: haos
|
|
|
|
# New services introduced by this plan.
|
|
homelab_mcp:
|
|
backend: apps
|
|
port: 9810
|
|
netbird_host: apps.netbird.selfhosted
|
|
endpoint: http://apps.netbird.selfhosted:9810/sse
|
|
note: MCP server. Read-only context + management. Mesh-only.
|
|
|
|
secrets_issuance:
|
|
backend: apps
|
|
port: 9820
|
|
netbird_host: apps.netbird.selfhosted
|
|
endpoint: http://apps.netbird.selfhosted:9820/issue
|
|
note: Issues per-client age private keys. Mesh-only.
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Hosts (Proxmox host + LXCs + VMs + workstations)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
hosts:
|
|
|
|
# ----- The hypervisor -----
|
|
hubris:
|
|
kind: proxmox-host
|
|
os: linux
|
|
role: hypervisor
|
|
lan_ip: 192.168.8.77
|
|
mesh:
|
|
netbird:
|
|
ip: 100.122.38.109
|
|
fqdn: proxmox-server.netbird.selfhosted
|
|
ssh:
|
|
port: 22 # OpenSSH
|
|
netbird_port: 22022 # see infrastructure/ssh-access.md
|
|
mounts:
|
|
- /mnt/library # shared lvmthin
|
|
age_pubkey: "" # filled by issuance on first bootstrap
|
|
|
|
# ----- LXC containers (all on hubris) -----
|
|
jellyfin:
|
|
kind: lxc
|
|
pve_id: 101
|
|
host: hubris
|
|
os: linux
|
|
role: media-server
|
|
lan_ip: 192.168.8.206
|
|
public_host: media.hubris.network
|
|
mesh: {netbird: {fqdn: jellyfin.netbird.selfhosted}}
|
|
mounts: [/mnt/library]
|
|
age_pubkey: ""
|
|
|
|
nfs-export:
|
|
kind: lxc
|
|
pve_id: 102
|
|
host: hubris
|
|
os: linux
|
|
role: storage-export
|
|
lan_ip: 192.168.8.200
|
|
mesh: {netbird: {fqdn: nfs-export.netbird.selfhosted}}
|
|
age_pubkey: ""
|
|
|
|
paperless:
|
|
kind: lxc
|
|
pve_id: 103
|
|
host: hubris
|
|
os: linux
|
|
role: document-archive
|
|
lan_ip: 192.168.8.130
|
|
public_host: paperless.hubris.network
|
|
mesh: {netbird: {fqdn: paperless.netbird.selfhosted}}
|
|
mounts: [/mnt/library]
|
|
age_pubkey: ""
|
|
|
|
gitea:
|
|
kind: lxc
|
|
pve_id: 104
|
|
host: hubris
|
|
os: linux
|
|
role: git-server
|
|
lan_ip: 192.168.8.121
|
|
public_host: git.hubris.network
|
|
backend_port: 3000
|
|
mesh: {netbird: {fqdn: gitea.netbird.selfhosted}}
|
|
mounts: [/mnt/library]
|
|
notes:
|
|
- "Bare repos live at /mnt/library/repos/dtoro/*.git"
|
|
age_pubkey: ""
|
|
|
|
apps:
|
|
kind: lxc
|
|
pve_id: 105
|
|
host: hubris
|
|
os: linux
|
|
role: docker-apps
|
|
lan_ip: 192.168.8.205
|
|
public_hosts: [artifacto.hubris.network]
|
|
mesh: {netbird: {fqdn: apps.netbird.selfhosted}}
|
|
mounts: [/mnt/library]
|
|
runs:
|
|
- artifacto
|
|
- plantuml
|
|
- homelab-mcp # introduced by this plan
|
|
- secrets-issuance # introduced by this plan
|
|
age_pubkey: ""
|
|
|
|
nextcloud:
|
|
kind: lxc
|
|
pve_id: 114
|
|
host: hubris
|
|
os: linux
|
|
role: file-sync
|
|
lan_ip: 192.168.8.224
|
|
public_host: cloud.hubris.network
|
|
mesh: {netbird: {fqdn: nextcloud.netbird.selfhosted}}
|
|
mounts: [/mnt/library]
|
|
age_pubkey: ""
|
|
|
|
elementsynapse:
|
|
kind: lxc
|
|
pve_id: 118
|
|
host: hubris
|
|
os: linux
|
|
role: matrix-server
|
|
lan_ip: 192.168.8.239
|
|
public_host: matrix.hubris.network
|
|
mesh: {netbird: {fqdn: elementsynapse.netbird.selfhosted}}
|
|
age_pubkey: ""
|
|
|
|
sophia:
|
|
kind: lxc
|
|
pve_id: 119
|
|
host: hubris
|
|
os: linux
|
|
role: workshop
|
|
lan_ip: 192.168.8.157
|
|
mesh: {netbird: {fqdn: sophia.netbird.selfhosted}}
|
|
mounts: [/mnt/library]
|
|
age_pubkey: ""
|
|
|
|
mule-images:
|
|
kind: lxc
|
|
pve_id: 120
|
|
host: hubris
|
|
os: linux
|
|
role: photo-management
|
|
lan_ip: 192.168.8.136
|
|
public_host: photos.hubris.network
|
|
mesh: {netbird: {fqdn: mule-images.netbird.selfhosted}}
|
|
mounts: [/mnt/library]
|
|
age_pubkey: ""
|
|
|
|
caddy:
|
|
kind: lxc
|
|
pve_id: 121
|
|
host: hubris
|
|
os: linux
|
|
role: reverse-proxy
|
|
lan_ip: 192.168.8.175
|
|
notes:
|
|
- "Terminates all *.hubris.network"
|
|
- "/etc/caddy is a git checkout of dtoro/caddy-conf"
|
|
peers: [authentik, gitea]
|
|
mesh: {netbird: {fqdn: caddy.netbird.selfhosted}}
|
|
age_pubkey: ""
|
|
|
|
arriman:
|
|
kind: lxc
|
|
pve_id: 122
|
|
host: hubris
|
|
os: linux
|
|
role: arr-stack
|
|
lan_ip: 192.168.8.132
|
|
public_hosts: [jellyseerr.hubris.network, qbit.hubris.network, sab.hubris.network]
|
|
mesh: {netbird: {fqdn: arriman.netbird.selfhosted}}
|
|
mounts: [/mnt/library]
|
|
age_pubkey: ""
|
|
|
|
claudio-bot:
|
|
kind: lxc
|
|
pve_id: 123
|
|
host: hubris
|
|
os: linux
|
|
role: matrix-agent
|
|
lan_ip: 192.168.8.230
|
|
mesh: {netbird: {fqdn: claudio-bot.netbird.selfhosted}}
|
|
notes:
|
|
- "Reads /opt/homelab-context/ on startup"
|
|
age_pubkey: ""
|
|
|
|
authentik:
|
|
kind: lxc
|
|
pve_id: 124
|
|
host: hubris
|
|
os: linux
|
|
role: idp
|
|
lan_ip: 192.168.8.180
|
|
public_host: auth.hubris.network
|
|
notes:
|
|
- "Also hosts split-horizon dnsmasq: /etc/dnsmasq.d/hubris-split.conf"
|
|
mesh: {netbird: {fqdn: authentik.netbird.selfhosted}}
|
|
age_pubkey: ""
|
|
|
|
plato:
|
|
kind: lxc
|
|
pve_id: 126
|
|
host: hubris
|
|
os: linux
|
|
role: app
|
|
lan_ip: 192.168.8.190
|
|
public_host: plato.hubris.network
|
|
mesh: {netbird: {fqdn: plato.netbird.selfhosted}}
|
|
mounts: [/mnt/library/documents/plato]
|
|
age_pubkey: ""
|
|
|
|
mule-photos-new:
|
|
kind: lxc
|
|
pve_id: 127
|
|
host: hubris
|
|
os: linux
|
|
role: photo-management
|
|
lan_ip: 192.168.8.181
|
|
public_host: photos-new.hubris.network
|
|
mesh: {netbird: {fqdn: mule-photos-new.netbird.selfhosted}}
|
|
age_pubkey: ""
|
|
|
|
# ----- VMs (on hubris) -----
|
|
zimaos:
|
|
kind: vm
|
|
pve_id: 100
|
|
host: hubris
|
|
os: linux
|
|
role: nas-frontend-eval
|
|
public_host: zimaos.hubris.network
|
|
mesh: {netbird: {fqdn: zimaos.netbird.selfhosted}}
|
|
age_pubkey: ""
|
|
|
|
haos:
|
|
kind: vm
|
|
pve_id: 108
|
|
host: hubris
|
|
os: linux
|
|
role: home-automation
|
|
mesh: {netbird: {fqdn: haos.netbird.selfhosted}}
|
|
age_pubkey: ""
|
|
|
|
# ----- Workstations (roaming, primary agent clients) -----
|
|
republic-laptop:
|
|
kind: workstation
|
|
os: linux
|
|
role: primary-dev
|
|
mesh: {netbird: {fqdn: republic-laptop.netbird.selfhosted}}
|
|
age_pubkey: ""
|
|
|
|
mac-mini:
|
|
kind: workstation
|
|
os: macos
|
|
role: dev
|
|
mesh: {netbird: {fqdn: mac-mini.netbird.selfhosted}}
|
|
notes:
|
|
- "Only macOS in the fleet. Bootstrap uses launchd."
|
|
age_pubkey: ""
|
|
|
|
ludo-mini:
|
|
kind: workstation
|
|
os: linux
|
|
role: dev
|
|
mesh: {netbird: {fqdn: ludo-mini.netbird.selfhosted}}
|
|
age_pubkey: ""
|