Skip to content

Latest commit

 

History

History
317 lines (258 loc) · 22.3 KB

File metadata and controls

317 lines (258 loc) · 22.3 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

See README.md for full requirements and status per machine.

Project Overview

Personal infrastructure-as-code (Ansible) managing a home network with four devices:

  • NSA (192.168.1.183): Debian 13 home server running Docker containers (Pi-hole, Home Assistant, Plex, WireGuard, nginx, Mosquitto, Zigbee2MQTT, ntopng, OpenClaw, Matter Server) + Cockpit web admin
  • Mini (192.168.1.116): Mac Mini M1 for Syncthing, iCloud backup, and Ollama LLM (available for local inference)
  • MB4 (mb4): MacBook Pro M4 workstation with Syncthing and Docker (Colima) for local dev
  • MKT (192.168.1.1): MikroTik hAP ax³ router (PPPoE WAN, DHCP, firewall, WiFi)

Commands

# Run playbooks (vault password auto-retrieved from macOS Keychain)
ansible-playbook site.yml          # All hosts
ansible-playbook nsa.yml           # NSA only
ansible-playbook mini.yml          # Mini only
ansible-playbook mb4.yml           # MB4 only
ansible-playbook mkt.yml           # MikroTik router only

# Dry run with diff
ansible-playbook nsa.yml --check --diff

# Run specific tags
ansible-playbook nsa.yml --tags docker
ansible-playbook nsa.yml --tags pihole
ansible-playbook nsa.yml --tags wireguard
ansible-playbook mb4.yml --tags hosts    # Update /etc/hosts entries
ansible-playbook mb4.yml --tags docker   # Set up Colima + dev containers
ansible-playbook mkt.yml --tags dhcp     # DHCP server config
ansible-playbook mkt.yml --tags firewall # NAT and filter rules
ansible-playbook nsa.yml --tags github-runner  # CI/CD runner + deps
ansible-playbook mini.yml --tags cloudflared   # Cloudflare Tunnel (always-on)
ansible-playbook mb4.yml --tags cloudflared    # Cloudflare Tunnel config (on-demand)

# Available tags: common, ssh, cockpit, avahi, docker, colima, ssl, https, nftables, pihole, wireguard, syncthing, backup, plex, openclaw, ollama, homeassistant, ha, github-runner, ci, power, autologin, homebrew, icloud-backup, mackup, hosts, dns, identity, bridge, network, ip, pppoe, wan, dhcp, nat, filter, wifi, wireless, services, security, traffic-flow, monitoring, dashboard, cleanup, disk-stats, cloudflared

# Vault operations
ansible-vault view vault.yml
ansible-vault edit vault.yml

# Testing
./tests/quick-check.sh             # Fast smoke test
./tests/run-all.sh                 # Full test suite (auto-logs to tests/results/)

# Security scanning (MB4, Docker/Colima required)
docker compose -f ~/docker/docker-compose.yml --profile security run --rm nmap -sV 192.168.1.0/24
docker compose -f ~/docker/docker-compose.yml --profile security up openvas  # http://localhost:9392

# Test logs
# tests/results/                   # Auto-saved by run-all.sh
# ~/docker/nmap/reports/           # nmap scan reports
# ~/docker/openvas/data/           # OpenVAS data (web UI managed)

Architecture

site.yml                    # Master playbook - imports all host playbooks
├── nsa.yml                 # Linux server: Docker services, firewall, VPN
├── mini.yml                # macOS: Syncthing, iCloud backup, Homebrew
├── mb4.yml                 # macOS: Syncthing, Homebrew
└── mkt.yml                 # MikroTik router: PPPoE, DHCP, firewall, WiFi

tasks/                      # Reusable task modules
├── common.yml              # SSH dirs, shell config, Sync folder
├── ssh.yml                 # SSH keys, hardening (Linux)
├── cockpit.yml             # Web admin interface (Linux)
├── avahi.yml               # mDNS for .local resolution (Linux)
├── docker.yml              # Docker install, compose deployment
├── docker-macos.yml        # Colima + Docker on macOS
├── nftables.yml            # Linux firewall rules
├── pihole.yml              # Pi-hole config, disable dnsmasq
├── wireguard.yml           # VPN server config
├── syncthing-{linux,macos}.yml
├── backup.yml              # Docker backup script + cron
├── icloud-backup.yml       # rsync to iCloud (Mini only)
├── homebrew.yml            # Homebrew packages/casks
├── mackup.yml              # App settings backup (macOS)
├── hosts-macos.yml         # /etc/hosts entries for NSA services
├── plex.yml                # Media server directories
├── ssl.yml                 # Self-signed cert for OpenClaw HTTPS
├── openclaw.yml            # OpenClaw AI assistant directories
├── ollama.yml              # Ollama LLM server (Mini)
├── homeassistant.yml       # HA config deployment (configuration.yaml, secrets.yaml)
├── github-runner.yml       # GitHub Actions self-hosted runner + CI deps
├── monitoring.yml          # health-check, daily-status, docker-backup scripts
├── monitoring-mini.yml     # NSA liveness monitor on Mini
├── dashboard.yml           # Build + deploy Vue dashboard to docs site
├── cleanup-macos.yml       # Remove unwanted startup items (macOS)
├── power-macos.yml         # Auto-login, sleep settings (macOS)
├── disk-stats-macos.yml    # Disk usage stats for dashboard
├── cloudflared-macos.yml   # Cloudflare Tunnel config (Mini: always-on, MB4: on-demand)
└── mikrotik/               # MikroTik router tasks
    ├── identity.yml        # Router name
    ├── bridge.yml          # LAN bridge config
    ├── ip-address.yml      # LAN IP
    ├── dhcp-server.yml     # DHCP pool, leases, DNS
    ├── pppoe.yml           # WAN PPPoE connection
    ├── firewall-nat.yml    # NAT masquerade, port forwards
    ├── firewall-filter.yml # Input/forward chain rules
    ├── wifi.yml            # WiFi config
    ├── guest-network.yml   # Guest isolation (192.168.10.0/24)
    ├── traffic-flow.yml    # NetFlow export to ntopng
    └── services.yml        # Enable/disable services

files/nsa/                  # Static config files deployed to NSA
├── docker-compose.yml      # All Docker service definitions
├── nftables.conf           # Firewall rules (IPv4 + IPv6)
├── nginx.conf              # Reverse proxy config (all services)
├── mosquitto.conf          # MQTT broker config
└── pihole/05-local-dns.conf # Local DNS entries (dnsmasq address= format)

files/scripts/              # Monitoring scripts deployed to NSA
├── health-check            # 5min cron — alerts on service issues
├── daily-status            # 7:30am cron — HTML email + status.json
└── docker-backup           # Sunday 3am — backup Docker volumes

templates/nsa/              # Jinja2 templates
├── wg0.conf.j2             # WireGuard config (uses vault peers)
├── docker.env.j2           # Docker environment vars
├── ha-configuration.yaml.j2 # Home Assistant configuration.yaml
└── ha-secrets.yaml.j2      # Home Assistant secrets.yaml

dashboard/                  # Vue 3 + TypeScript dashboard (deployed to http://docs)
├── src/
│   ├── views/              # StatusView, ServicesView, NetworkView, DataView,
│   │                       # OperationsView, TestingView
│   ├── components/         # StatusDot, DiskBar, ServiceRow, SyncthingPanel
│   ├── composables/        # useStatusData, useServiceCheck, useSyncthing
│   ├── types/status.ts     # StatusData type definition
│   └── router/index.ts     # SPA routes
└── dist/                   # Built output, deployed by tasks/dashboard.yml

group_vars/                 # Variables by group
├── linux_servers.yml       # Linux-specific (apt, systemd)
├── macos.yml               # macOS-specific (homebrew paths)
└── network_devices.yml     # MikroTik connection settings

host_vars/                  # Variables by host (override group_vars)
├── nsa.yml                 # NSA-specific config
├── mini.yml                # Mini-specific config
├── mb4.yml                 # MB4-specific config
└── mkt.yml                 # MikroTik router config

docs/                       # Documentation
├── guest-wifi-qr.png       # Guest WiFi QR code
├── nsa-migration.md        # NSA rebuild runbook
└── iot-vlan-design.md      # IoT VLAN isolation design (planned)

NSA Services

URLs that work on both LAN and VPN (use short hostnames, not .local):

All browser services are accessible via nginx reverse proxy — no port numbers needed.

Service URL Notes
Home Assistant http://ha WebSocket supported
Pi-hole Admin http://pihole/admin Direct: http://192.168.1.183:8081/admin
Plex http://plex/web
Cockpit http://nsa Proxies to Cockpit HTTPS on 9090
OpenClaw https://openclaw HTTPS required (WebSocket secure context)
ntopng http://ntopng
Laya http://laya Static site
Hopo http://hopo Static site
Docs http://docs Vue 3 dashboard (status, services, network, data, ops, testing)
Minecraft - 3 servers: Laya (UDP 19132, survival), Richard (19133, creative), Mara (19134, creative). Data: /mnt/data/minecraft-*/
Mosquitto - Port 1883 (not browser)
Matter Server - Port 5580 (localhost only, HA connects via WebSocket)
WireGuard - Port 51820 (not browser)
GitHub Actions - Self-hosted runners: nsa-bkd-{1,2,3,4} (Buckden), nsa-fdz-{1,2} (Fourdotzero)

Note: Short hostnames (e.g., ha, pihole) are resolved by Pi-hole DNS and work over both LAN and WireGuard VPN. .local variants (e.g., ha.local) use mDNS (Avahi) and only work on LAN.

Cloudflare Tunnels (QA Access)

Dev servers exposed via Cloudflare Tunnels for QA testing before launch:

Slot URL Machine Notes
1 https://1.vulkitron.com Mini Always-on
2 https://2.vulkitron.com Mini Always-on
3 https://3.vulkitron.com Mini Always-on
4 https://4.vulkitron.com MB4 On-demand: cloudflared tunnel run mb4
5 https://5.vulkitron.com MB4 On-demand: cloudflared tunnel run mb4

Slot-to-port mapping configured in host_vars/{mini,mb4}.yml (cloudflared_slots). Config deployed to /etc/cloudflared/config.yml.

OpenClaw + Groq Architecture

OpenClaw gateway runs on NSA (Docker), connects to Groq cloud API for fast LLM inference.

Config: Gateway config stored in /srv/docker/openclaw/state/openclaw.json. Key settings:

  • Provider: groq with OpenAI-compatible API (api: "openai-responses")
  • Model: llama-3.3-70b-versatile (131K context, 32K max tokens)
  • Control UI origins: https://openclaw, https://openclaw. (trailing dot for Chrome 144+)

Access: https://openclaw/?token=<OPENCLAW_TOKEN> — token required for WebSocket auth. First-time access requires device pairing (approved via paired.json).

Performance: ~250-400ms response time (vs ~12s with local Ollama on M1).

Pairing new devices: When "pairing required" error appears, move pending device to paired:

ssh nsa
docker exec openclaw-gateway cat /home/node/.openclaw/devices/pending.json  # Get device info
# Edit paired.json to include the device (key by deviceId, not requestId)

Fallback: Ollama on Mini (192.168.1.116:11434) still available with qwen2.5:7b-16k for local/offline use.

NSA Storage

Two-tier storage balancing speed and capacity:

Drive Size Mount Use
NVMe 256GB / OS, Docker, databases
SATA SSD 1TB /mnt/data Media, backups

Key paths:

  • /srv/docker/ - Docker Compose and configs (NVMe)
  • /mnt/data/media/ - Plex library (SATA)
  • /mnt/data/backups/ - Docker backup archives (SATA)
  • /mnt/data/ntopng/ - Network traffic data, 30 day retention (SATA)
  • /mnt/data/minecraft-{laya,richard,mara}/ - Minecraft world data (SATA)

Vault

Password retrieved automatically from macOS Keychain via ~/.ansible/vault-pass.sh.

Key variables in vault.yml:

  • vault_wireguard_private_key, vault_wireguard_peers - VPN config
  • vault_pihole_password - Pi-hole admin
  • vault_plex_claim - Plex setup token (expires in 4 min, get from plex.tv/claim)
  • vault_ssh_authorized_keys - SSH public keys
  • vault_mikrotik_admin_password - Router admin password
  • vault_mikrotik_pppoe_username, vault_mikrotik_pppoe_password - ISP credentials
  • vault_mikrotik_wifi_ssid, vault_mikrotik_wifi_password - WiFi config
  • vault_mikrotik_guest_ssid, vault_mikrotik_guest_password - Guest WiFi config
  • vault_openclaw_token - OpenClaw API token
  • vault_groq_api_key - Groq cloud LLM API key (OpenClaw backend)
  • vault_tapo_camera_user, vault_tapo_camera_password - Tapo camera RTSP credentials
  • vault_mini_login_password - Mini macOS login password (for auto-login after reboot)

Network

  • WAN: 81.174.139.34 (static IP from Plusnet)
  • LAN IPv4: 192.168.1.0/24, Gateway: 192.168.1.1 (MikroTik hAP ax³)
  • Guest IPv4: 192.168.10.0/24, Gateway: 192.168.10.1 (isolated, public DNS)
  • LAN IPv6: fd7a:94b4:f195:7248::/64
  • VPN: 10.0.0.0/24 (WireGuard on NSA, endpoint: 81.174.139.34:51820)
  • DNS: Pi-hole at 192.168.1.183:53 (LAN), 1.1.1.1/8.8.8.8 (guest)
  • mDNS: Avahi for .local resolution (e.g., nsa.local)
  • Router: MikroTik hAP ax³ (replaced Plusnet Hub Two on 2026-01-20)
  • All services accessible from LAN or VPN only (except WireGuard port 51820)
  • Guest network isolated: can reach internet, blocked from LAN (192.168.1.0/24)

Known Issues

Issue Status Notes
VPN not connected on MB4 (LAN) ℹ️ Info WireGuard VPN shows disconnected when MB4 is on LAN — expected, not needed on home network.
OpenClaw self-signed cert ℹ️ Info https://openclaw uses self-signed cert. Browser shows warning on first visit — click "Proceed" once, then it's remembered.
iCloud Private Relay incompatible ℹ️ Info Guest WiFi shows "not compatible with Private Relay" - expected for IPv4-only networks.

Resolved Issues

Issue Resolution Date
mb4.yml missing ssh task import Added import_tasks: tasks/ssh.yml with tags: [ssh] to mb4.yml. SSH authorized keys were never deployed to MB4 via Ansible. 2026-02-24
mini.yml common/ssh imports untagged Added tags: [common] and tags: [ssh] to imports — --tags ssh was silently skipping all tasks. 2026-02-24
vault_groq_api_key missing from vault Recovered key from live openclaw config (/srv/docker/openclaw-gateway/state/openclaw.json) and added to vault. 2026-02-24
m365 zsh warning on machines without m365 Made source ~/.config/m365/m365.zsh conditional with [[ -f ... ]] guard in .zshrc. 2026-02-24
OpenClaw slow with local Ollama Switched from Ollama (Mini) to Groq cloud API. Response time improved from ~12s to ~300ms. Config in /srv/docker/openclaw/state/openclaw.json. 2026-02-09
OpenClaw "origin not allowed" error Added controlUi.allowedOrigins to config including https://openclaw. (trailing dot for Chrome 144 single-label hostname behavior). 2026-02-09
Matter server-side commissioning fails Meross plugs only accept commissioning from phone proxy. Use HA Companion App instead of server-side commission_with_code. 2026-02-02
matter-server --primary-interface None Added --primary-interface enp1s0 to docker-compose.yml command. Without it, CHIP SDK picks wrong/no interface. 2026-02-02
Pi-hole DNS not working on Mac Removed legacy /etc/hosts entries (10.0.0.1) that were overriding Pi-hole DNS. Pi-hole now handles local hostnames. 2026-01-21
Network issues (browsers/NSA failing) Removed duplicate bridge-lan - must use existing bridge (defconf). Set bridge_name: bridge in host_vars/mkt.yml. 2026-01-20
Browsers not loading (curl works) Added MSS clamping for PPPoE (MTU 1492). Without it, large TCP packets (TLS handshakes) fail silently. 2026-01-20

Verified Tests

Date Test Result
2026-02-24 Termius iOS SSH key auth ✅ Pass - Key deployed to NSA, Mini, MB4 via Ansible. Passwordless SSH from Termius iOS confirmed.
2026-02-24 SSH Mini→NSA, MB4→Mini ✅ Pass - Cross-machine SSH working with key auth on all three hosts
2026-02-09 OpenClaw + Groq ✅ Pass - Switched to Groq API (llama-3.3-70b-versatile), ~300ms responses, device pairing working
2026-02-03 Full test suite (run-all.sh) ✅ Pass - Quick: 11/11, MikroTik: 25/25. Fixed stale tests (etc→docs, nginx 8080→80, Pi-hole 443→8081)
2026-02-02 Tapo cameras (3x RTSP) ✅ Pass - Kitchen, Bedroom, Office streams in HA
2026-02-02 Matter smart plugs (4x) ✅ Pass - Meross plugs via Companion App, multi-admin with Apple Home
2026-02-02 Nanoleaf Thread bulb ✅ Pass - Commissioned via Companion App, Thread mesh
2026-02-02 Zigbee coordinator FW ✅ Pass - Sonoff ZBDongle-P 20210708 → 20240710
2026-02-02 Matter Server ✅ Pass - python-matter-server with --primary-interface enp1s0
2026-01-29 Comprehensive network test ✅ Pass - 9/9 DNS, 3/3 SSH, 8/8 HTTP services, Ollama LAN access
2026-01-29 Plex HTTPS requirement ⚠️ Note - HTTP returns empty reply, HTTPS works (302). Updated bookmarks to https://
2026-01-29 Ollama LAN access ✅ Pass - http://192.168.1.116:11434/ responds, qwen2.5:7b-16k active for OpenClaw
2026-01-29 MikroTik router health ✅ Pass - RouterOS 7.19.6, uptime 9+ days, 2% CPU
2026-01-21 Guest WiFi isolation ✅ Pass - Internet works, LAN blocked (192.168.1.x unreachable)
2026-01-21 WireGuard full tunnel (mobile) ✅ Pass - ping 10.0.0.1, http://ha:8123, https://pihole/admin
2026-01-21 Pi-hole DNS (LAN) ✅ Pass - All hostnames resolve via 192.168.1.183
2026-01-20 MikroTik Ansible (25 tests) ✅ Pass - ./tests/test-mkt.sh
2026-01-20 Guest WiFi connection ✅ Pass - SSID guestexpress working
2026-01-20 WiFi PMF (management-protection) ✅ Pass - Apple security warning resolved
2026-01-16 WireGuard split tunnel DNS ✅ Pass - dig @10.0.0.1 google.com resolves
2026-01-16 Pi-hole ad-blocking via VPN ✅ Pass - ads.google.com returns 0.0.0.0