About Nelson Home
Nelson Home
Infrastructure as Code for a self-hosted homelab. This repo is the single source of truth for provisioning, configuring, and deploying all services across a Proxmox VE host (with two LXC nodes: nelson-manager and nelson-edge), and a legacy Ubuntu monolith being gradually decommissioned.
Current Architecture
┌──────────────────────────────────────────────────────────────────┐
│ Proxmox VE — Beelink S13 Pro (N100, 16 GB RAM, 4-core) │
│ nelson-pve · 192.168.1.10 │
│ │
│ ┌──────────────────────────────┐ ┌──────────────────────────┐ │
│ │ nelson-manager │ │ nelson-edge │ │
│ │ LXC 300 · 192.168.1.30 │ │ LXC 301 · 192.168.1.2 │ │
│ │ │ │ │ │
│ │ · Semaphore + Postgres │ │ · AdGuard Home (DNS) │ │
│ │ · Vaultwarden │ │ · Tailscale (mesh VPN) │ │
│ │ · Homepage dashboard │ │ · NPM (→ Caddy WIP) │ │
│ │ · Uptime Kuma │ │ · DuckDNS │ │
│ │ · UniFi Network App │ └──────────────────────────┘ │
│ │ · Grafana + Prometheus │ │
│ │ · Pulse, Glances │ │
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ ┌──────────────────────────┐ │
│ │ ubuntu-server │ │ nelson-apps │ │
│ │ VM 100 · 192.168.1.11 │ │ VM (planned) · .40 │ │
│ │ (legacy monolith, draining) │ │ │ │
│ │ │ │ · Nextcloud │ │
│ │ · Home Assistant │ │ · Plex / Jellyfin │ │
│ │ · Plex, Nextcloud, n8n │ │ · Immich, Paperless │ │
│ │ · Pulse, Glances │ │ · n8n │ │
│ └──────────────────────────────┘ └──────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ bolt-claw │ │
│ │ VM 105 · role TBD │ │
│ │ (audit pending) │ │
│ └──────────────────────────────┘ │
│ │
│ 5TB WD Elements · /mnt/nelson-backups │
└──────────────────────────────────────────────────────────────────┘
┌────────────────────────────────┐
│ ender3 · 192.168.1.123 │
│ Raspberry Pi (physically │
│ remote from homelab) │
│ · 3D printer controller │
└────────────────────────────────┘
Node Roles & Design Rationale
nelson-manager (LXC · 192.168.1.30)
Role: IaC control plane + observability
All infrastructure orchestration lives here. Semaphore is the execution engine for every Ansible playbook — it can never be on the machine it deploys to (self-termination risk), so it needs its own stable node. Vaultwarden sits alongside it so secrets are always available to the control plane. Monitoring (Grafana/Prometheus, Uptime Kuma, Pulse, Glances) lives here to observe all other nodes from a neutral vantage point. UniFi Network Application is here because it needs to be reachable by all LAN devices, independent of the monolith.
nelson-edge (LXC 301 · 192.168.1.2)
Role: Network edge — DNS, VPN, reverse proxy, and SSL
nelson-edge is a Proxmox LXC on nelson-pve. It owns everything at the network boundary before traffic reaches an application node. AdGuard handles all DNS queries for *.nelson.home. Tailscale provides the mesh VPN fabric. NPM handles reverse proxying now, and will be replaced by Caddy for automatic HTTPS via Let's Encrypt (DNS-01 challenge through DuckDNS) — both staying on nelson-edge since SSL termination is inherently a network-edge concern. Concentrating all network services here means this layer survives independently of application nodes and reboots cleanly.
nelson-apps (VM · planned)
Role: Heavy compute workloads
Nextcloud, Plex/Jellyfin, Immich, and Paperless-ngx are compute and memory-intensive. Isolating them into a VM with 10–12 GB RAM keeps them from competing with control-plane and network services. Direct access to the 5TB backup drive via Samba (NAS) targets this node.
bolt-claw (VM 105 · on nelson-pve)
Role: Unknown — audit pending
Existing VM consuming ~7.8 GB RAM with no documented purpose. Scheduled for audit to determine whether to keep or decommission.
ender3 (Raspberry Pi · 192.168.1.123)
Role: 3D printer controller
Physically remote from the homelab. Runs the 3D printer. Included in the network map for inventory completeness; not managed by Ansible.
ubuntu-server (VM 100 · 192.168.1.11)
Role: Legacy monolith (draining)
A Proxmox VM hosting all pre-migration services. All services here are scheduled for migration to other Proxmox nodes. It stays online until every service has a tested replacement. Nothing new is deployed here.
Service Map
| Service | Current Host | Target Host | Domain |
|---|---|---|---|
| Semaphore (IaC) | nelson-manager | nelson-manager | semaphore.nelson.home |
| Vaultwarden | nelson-manager | nelson-manager | vault.nelson.home |
| Homepage | ubuntu-server | nelson-manager | homepage.nelson.home |
| Uptime Kuma | — | nelson-manager | uptime.nelson.home |
| UniFi Network App | nelson-manager | nelson-manager | unifi.nelson.home |
| Grafana + Prometheus | — | nelson-manager | grafana.nelson.home |
| Pulse | ubuntu-server | nelson-manager | pulse.nelson.home |
| Glances | ubuntu-server | nelson-manager | glances.nelson.home |
| AdGuard Home (DNS) | nelson-edge | nelson-edge | adguard.nelson.home |
| Tailscale | nelson-edge | nelson-edge | — |
| DuckDNS | ubuntu-server | nelson-edge | — |
| Nginx Proxy Manager | nelson-edge | → replaced by Caddy | npm.nelson.home |
| Caddy (SSL) | — | nelson-edge | — |
| Home Assistant | ubuntu-server | ubuntu-server | ha.nelson.home |
| Plex | ubuntu-server | nelson-apps | plex.nelson.home |
| Proxmox (Public) | nelson-pve | nelson-pve | proxmox.tudhopenelson.duckdns.org |
| Jellyfin | ubuntu-server | nelson-apps | jellyfin.nelson.home |
| Nextcloud | ubuntu-server | nelson-apps | nextcloud.nelson.home |
| n8n | ubuntu-server | nelson-apps | n8n.nelson.home |
Networking
All internal DNS is managed by AdGuard Home on nelson-edge. Every *.nelson.home domain resolves to the node running the reverse proxy (nelson-edge), which routes by hostname to the correct upstream service.
Client → AdGuard DNS → *.nelson.home resolves to reverse proxy host
→ NPM (now) / Caddy (future) → upstream service:port
Future state: Caddy on nelson-edge replaces NPM, adding automatic HTTPS via Let's Encrypt DNS-01 (DuckDNS). DNS rewrites will continue pointing to nelson-edge — no IP change needed during the NPM → Caddy cutover.
Remote access: Tailscale mesh VPN. All nodes and the operator workstation are on the tailnet (tadpole-dory.ts.net). DNS queries on the tailnet route through AdGuard.
Roadmap
Phase 2.3: Manager Node — In Progress
- [x] Provision nelson-manager LXC (ID 300, 192.168.1.30)
- [x] Migrate Semaphore + Postgres to nelson-manager
- [x] Migrate Vaultwarden to nelson-manager
- [ ] Deploy Uptime Kuma to nelson-manager
- [ ] Deploy Monitoring (Prometheus/Grafana) to nelson-manager
- [ ] Migrate Pulse + Glances to nelson-manager
Phase 2.4: Networking (Edge) — Complete
- [x] Deploy NPM to nelson-edge [Gemini, 2026-02-19]
- [ ] Migrate DuckDNS to nelson-edge
- [x] Update internal DNS (AdGuard rewrites for new service locations) [Gemini, 2026-02-19]
- [ ] Replace NPM with Caddy on nelson-edge (automatic HTTPS via DuckDNS DNS-01)
- [x] Decommission nelson-identity LXC (.20) [Gemini, 2026-02-19]
Phase 2.1: Pre-Migration Cleanup — Not Started
- [ ] Audit bolt-claw VM 105 (keep or decommission)
- [ ] Decommission unused VMs (ubuntu-desktop 101, netbox 104)
- [ ] Remove 3 dead NPM rules pointing to retired 192.168.1.157
- [ ] Template plaintext compose credentials into Ansible Vault
- [ ] Reconcile unmanaged containers into IaC (duckdns, plex, nextcloud, glances, qdirstat, mongo-express)
- [ ] Audit and store all lab passwords in Vaultwarden
Phase 3: Apps Node (planned)
- [ ] Provision nelson-apps VM (10–12 GB RAM, 2–3 vCPU)
- [ ] Migrate Plex, Jellyfin, Nextcloud, n8n
- [ ] Deploy Immich, Paperless-ngx
- [ ] Samba NAS from 5TB drive
Phase 4: Hardening (planned)
- [ ] Compliance audit playbook (OS drift, SMART health, rogue processes)
- [ ] Lynis security hardening scoring
- [ ] Syncthing for device sync
- [ ] Decommission ubuntu-server (final goal)
Resource Budget (Proxmox Host)
| Node | Type | RAM | vCPU | Role |
|---|---|---|---|---|
| nelson-manager | LXC | 4 GB | 1 | IaC control plane + monitoring |
| bolt-claw | VM | ~8 GB | ? | TBD (audit pending) |
| nelson-apps | VM | 10–12 GB | 2–3 | Nextcloud, Plex, Immich, Paperless |
| (headroom) | — | ~2 GB | — | Buffer for Proxmox + expansion |
Hardware ceiling: 16 GB RAM, 4-core N100 Note: bolt-claw's ~8 GB is the primary constraint on available headroom until it is audited/decommissioned.
Repository Structure
├── ansible/
│ ├── ansible.cfg # Sets inventory path
│ ├── inventory/hosts.ini # All hosts — source of truth for IPs
│ ├── group_vars/all/
│ │ ├── common.yml # Shared variables (IPs, URLs, service map)
│ │ ├── secrets.yml # Ansible Vault encrypted secrets
│ │ └── containers.yml # Active Docker service list per node
│ ├── audit_*.yml # System audit playbooks
│ ├── backup_*.yml # Backup automation
│ ├── configure_*.yml # Service config (DNS rewrites, NPM hosts)
│ ├── deploy_*.yml # Service deployment
│ └── sync_*.yml # Repo sync and config push
├── docker-compose/ # Compose definitions per service
├── .ops/ # Project management workspace
│ ├── PROTOCOL.md # Shared rules for all agents
│ ├── ROADMAP.md # Phases and milestones
│ ├── SPRINT.md # Active tasks with next-actions
│ ├── KNOWLEDGE.md # Operational patterns and API details
│ ├── STANDUP.md # Rolling 3-day daily report
│ └── archive/ # Completed sprints and older reports
├── CLAUDE.md # Claude Code agent instructions
├── GEMINI.md # Gemini CLI agent instructions
└── CHANGELOG.md # Chronological log of all changes
How It Works
Ansible + Semaphore
All infrastructure changes go through Ansible playbooks, executed via Semaphore on nelson-manager. Playbooks are never run directly from the operator workstation against live infrastructure — Semaphore provides the audit trail, vault integration, and scheduling.
Shared variables (IPs, service locations, DNS entries) live in group_vars/all/common.yml. When a service migrates to a new node, update forward_host in common.yml and re-run configure_npm_hosts.yml and configure_adguard_dns.yml — no manual NPM or AdGuard edits needed.
Secrets (API tokens, passwords) live in group_vars/all/secrets.yml, encrypted with Ansible Vault. All Semaphore templates must have vault_key_id set or they fail on decryption.
Backups
Critical data is backed up to the 5TB WD Elements at /mnt/nelson-backups on nelson-pve:
backup_vaultwarden.yml— SQLite snapshots with retentionbackup_unifi.yml— UniFi controller config with retention
Audits
audit_master.yml runs all sub-audits and writes reports to the repo root (docker_audit.md, proxmox_audit.md, etc.) for a point-in-time snapshot of system health.
AI Agent Collaboration
This repo is co-maintained by two AI coding agents alongside the human operator:
- Claude Code — instructions:
CLAUDE.md - Gemini CLI — instructions:
GEMINI.md
Both agents follow the shared protocol in .ops/PROTOCOL.md. The .ops/ directory is the shared project workspace — agents read it at session start and update it after completing work. Both agents attribute all changes: [Agent, YYYY-MM-DD].
See .ops/STANDUP.md for the latest status, or .ops/SPRINT.md for active tasks.
Operator Workstation
SSH config for the MacBook Pro operator station:
# ~/.ssh/config
Host 192.168.1.* 100.*.*.*
User btnelson
IdentityFile ~/.ssh/id_ed25519
ForwardAgent yes