# 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: age1xkklkvnk5z0fsnh6cfgv70hy9ksfy8rdprwerzw4yk3p4p7cxcqs2yvpz6 # ----- 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} tailscale: {ip: 100.121.171.122} mounts: [/mnt/library] runs: - artifacto - plantuml - homelab-mcp # introduced by this plan - secrets-issuance # introduced by this plan age_pubkey: age1duyl8mkpgu80uv934dy8q7enqjms6yvdz264hme8uryuxmvvqesq6rusq0 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: ""