No description
  • Jinja 47.7%
  • Python 41.7%
  • JavaScript 7.1%
  • TypeScript 1.5%
  • Shell 1.4%
  • Other 0.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Bugsy dcf12a4a80
All checks were successful
CI Pipeline / Validate Ansible Syntax (pull_request) Successful in 1m29s
CI Pipeline / Test Ansible Playbooks (Syntax Only) (pull_request) Successful in 45s
CI Pipeline / Python Tests (pull_request) Successful in 24s
CI Pipeline / Validate Ansible Syntax (push) Successful in 1m27s
CI Pipeline / Test Ansible Playbooks (Syntax Only) (push) Successful in 42s
CI Pipeline / Python Tests (push) Successful in 23s
Create writable Director Gallery Inbox
2026-10-29 01:40:20 -04:00
.forgejo/workflows Spin Fabric engine off into the HomelabFabric repo 2026-10-08 11:33:06 -04:00
.taskmaster ansible: add podstead and windrose services with roles and playbooks 2026-05-13 00:55:08 +00:00
ansible Create writable Director Gallery Inbox 2026-10-29 01:40:20 -04:00
docs Add Interstitial Director deployment 2026-10-22 00:38:49 -04:00
examples Integrate Comfy Gallery bumper rendering 2026-10-21 02:03:43 -04:00
scripts Lock camera for ambient image animation 2026-10-21 14:45:54 -04:00
tests Lock camera for ambient image animation 2026-10-21 14:45:54 -04:00
.ansible-lint-ignore Add early-warning watchdog for channel100 TCP memory exhaustion 2026-10-04 01:04:10 -04:00
.env.example ansible: add podstead and windrose services with roles and playbooks 2026-05-13 00:55:08 +00:00
.gitignore Add device-backups/ for raw flash backups pulled off devices 2026-08-14 01:18:50 -04:00
AGENTS.md Deploy the Fabric dashboard from the registry image 2026-10-14 13:39:35 -04:00
README.md Add room-specific archive radio voice scripts 2026-10-19 13:58:36 -04:00

Home Network Starter (Prod-only)

This repo now assumes the homelab is provisioned entirely through Ansible. It deploys:

  • channel101 (edge host): Docker, Traefik, Authelia, Home Assistant, Dashy, RomM, VS Code Server, and all Traefik file-provider routes.
  • channel100 (services host): Docker, Unbound (recursive DNS) and Pi-hole (ad-blocking DNS front-end).

Inventory & variables

Update ansible/inventories/prod/hosts.yml with your hostnames/IPs, SSH details, and the resolver lists (bootstrap_dns for temporary bootstrap access and operational_dns for the steady-state settings). Runtime settings live under ansible/inventories/prod/group_vars/prod/. Public settings are split by domain in files such as core.globals.yml, edge.infra.yml, edge.routes.yml, unifi.config.yml, and *.services.yml; secrets are split across encrypted *.vault.yml files.

Vault note: *.vault.yml files are encrypted with Ansible Vault. Run playbooks from the ansible/ directory (or set ANSIBLE_CONFIG=ansible/ansible.cfg) so the vault_password_file = .vault_pass setting is picked up.

Bootstrap the entire lab

From a clean workstation with SSH access to each target:

cd ansible
ansible -i inventories/prod/hosts.yml all -m ping
ansible-playbook playbooks/bootstrap.yml

bootstrap.yml runs every role in dependency order:

  1. Applies the bootstrap_dns resolvers defined per host (see inventories/prod/hosts.yml) so apt can reach upstream repositories even while Pi-hole is offline.
  2. Installs Docker everywhere (site.yml).
  3. Deploys Unbound, then Pi-hole on channel100 (Pi-hole is already configured to use 127.0.0.1#5335 as upstream).
  4. Deploys Traefik on channel101, purges stale dynamic configs, and rehydrates ACME storage.
  5. Deploys Authelia, writes the portal + middleware routes (with the production resolver), then renders all edge routes.
  6. Deploys Home Assistant and publishes its Traefik file-provider config.
  7. Deploys Dashy on channel101 and exposes it through Traefik.
  8. Deploys RomM + MariaDB on channel101 so the library is fronted by Traefik.
  9. Deploys CloudCLI on deskpi so Codex sessions can be managed through a browser UI behind Traefik.
  10. Restores each host’s permanent resolver list from the operational_dns values in the inventory (channel100 points at itself/Unbound; other nodes point at Pi-hole).

After the play finishes you should be able to reach:

  • https://traefik.<home_domain> for the Traefik dashboard.
  • https://login.<home_domain> for Authelia SSO.
  • https://pihole.<home_domain> for the Pi-hole UI (fronted by Traefik).
  • https://code.<home_domain> for VS Code Server (gated by Authelia + the container password).

Day-2 operations

  • Comfy Gallery standalone project – owns the application, tests, and container image; this repository owns production configuration and deployment via ansible-playbook playbooks/deploy_comfy_gallery.yml.
  • docs/disc-ripper-comparison.md – compare jlesage/makemkv and Automatic Ripping Machine (ARM) for physical-media ingest.
  • docs/private-archive-radio-options.md – deferred options for turning archived shows into a private continuous radio stream, including Android Auto access and resource estimates.
  • docs/homeassistant-maintenance.md – current Home Assistant ownership, voice, Music Assistant, Protect, and Plex maintenance notes.
  • docs/emergency-recovery.md – recover management, edge, and DNS services from broadcaster.
  • docs/comfyui-workflow-shards.md – prioritized backlog for improving ComfyUI workflows and prompt tooling.
  • docs/comfyui-workflow-validation.md – validate ComfyUI graph structure and assets, then runtime-smoke canonical workflows.
  • docs/comfyui-prompt-librarian.md – generate, review, merge, and sync ComfyUI prompt-library drafts and seed templates.
  • docs/comfyui-prompt-bundles.md – define reusable, family-validated prompt bundles.
  • ansible-playbook playbooks/deploy_management_backup.yml – configure and run management-plane state backups.
  • ansible-playbook playbooks/deploy_pihole.yml – reconfigure Pi-hole.
  • ansible-playbook playbooks/deploy_unbound.yml – refresh Unbound/root hints.
  • ansible-playbook playbooks/deploy_traefik.yml – roll Traefik or change ports/certs.
  • ansible-playbook playbooks/deploy_authelia.yml – update Authelia config and Traefik middleware.
  • ansible-playbook playbooks/publish_routes.yml – regenerate Traefik dynamic routes.
  • ansible-playbook playbooks/homeassistant.yml – deploy/update Home Assistant.
  • The Home Assistant role keeps proxy networking in the UI-managed HTTP integration and installs Coast to Coast AM Music Assistant scripts for Bathroom (default), Office, Kitchen, and Everywhere.
  • ansible-playbook playbooks/deploy_dashy.yml – deploy/update Dashy.
  • ansible-playbook playbooks/deploy_many_notes.yml – deploy/update Many Notes on channel101.
  • ansible-playbook playbooks/deploy_romm.yml – deploy/update RomM + MariaDB on channel101.
  • ansible-playbook playbooks/deploy_makemkv.yml – deploy/update the automatic MakeMKV disc ripper on scruffybcc.
  • ansible-playbook playbooks/deploy_archive_radio.yml – deploy/update the private shuffled Art Bell/Coast to Coast archive stream on scruffybcc.
  • ansible-playbook playbooks/deploy_music_assistant.yml – deploy/update the authenticated Music Assistant frontend for private local and remote radio playback.
  • ansible-playbook playbooks/deploy_code_server.yml – deploy/update VS Code Server.
  • ansible-playbook playbooks/deploy_ollama.yml – deploy/update Ollama and Open WebUI on aibench.
  • ansible-playbook playbooks/deploy_world_intel_mcp.yml – deploy/update the world-intel-mcp image (113-tool world intelligence MCP server, free public APIs) on aibench. Exposed to Claude Code as the world-intel MCP server (stdio over ssh, via mcp_tool_filter_proxy.py) and to local Ollama models via the bundled mcp_ollama_bridge.py tool-calling bridge. Which tools are visible to each is controlled by world_intel_mcp.enabled_tools / disabled_tools in ai.services.yml — edit and re-run the playbook, no image rebuild needed.
  • ansible-playbook playbooks/deploy_cloudcli.yml – deploy/update CloudCLI on its configured host.
  • ansible-playbook playbooks/deploy_hindsight.yml – deploy/update the standalone Hindsight memory server (Hermes + cloudcli memory backend) on its configured host.
  • ansible-playbook playbooks/deploy_beszel.yml – deploy/update the Beszel monitoring hub + agents (host/container metrics, alerting) across all prod hosts.
  • ansible-playbook playbooks/deploy_diun.yml – deploy/update DIUN on every managed Docker host to check image registries every six hours and send update notifications to Discord. DIUN only reports updates; use the service's Ansible playbook to apply them.
  • ansible-playbook playbooks/deploy_gatus.yml – deploy/update Gatus (HTTP/TCP endpoint monitoring for Traefik, Authelia, Pi-hole, Gitea, and the NAS share) on its configured host. Alerts post to the same Discord webhook as Beszel (discord_bot_secret.webhook_url).
  • ansible-playbook playbooks/manage_host_ssh_keys.yml – (re)generate SSH keypairs for channel100, channel101, and scruffybcc.
  • ansible-playbook playbooks/deploy_act_runner.yml – deploy/update the shared Gitea Actions self-hosted runner on scruffybcc (used by every project's CI, not just one game).
  • ansible-playbook playbooks/deploy_godot_project_one.yml – deploy/update the first Godot game's dedicated server on scruffybcc. Copy this playbook + its games.services.yml var block per additional game (same pattern as deploy_minecraft_atm10.yml).

Use playbooks/verify_routes.yml if you only need to smoke-test the reverse proxy without redeploying anything.

VS Code Server access

  • Update code_server_secret.password (and optionally sudo_password) in ansible/inventories/prod/group_vars/prod/dev.vault.yml before deploying.
  • Add any host paths you want to edit remotely under code_server.workspace_mounts in ansible/inventories/prod/group_vars/prod/dev.services.yml. By default the Dashy config directory is mounted so you can tweak that UI directly.
  • Run ansible-playbook playbooks/deploy_code_server.yml (or the full bootstrap) and reach it at https://code.<home_domain> through Traefik + Authelia.
  • Codex is not provisioned from the vault: log in once with codex login from the code-server terminal (or the ChatGPT extension). The login lives in /config/.codex/auth.json, refreshes itself, and is covered by the management-plane backup.
  • Need to install packages in the container? set code_server.no_new_privileges: false so sudo is allowed, redeploy the role, then use sudo apt install ... from the web terminal.
  • The role now auto-generates an SSH keypair in /config/.ssh/ (configurable via code_server.ssh_key). Grab the public key from /config/.ssh/id_ed25519.pub in the container and add it to your Git host so clones over SSH succeed.
  • code_server.packages lists deb packages that should always exist inside the container (default: ansible, curl, dnsutils). After the stack comes up, the role runs apt-get install via docker exec so the tools survive every redeploy. Set the list to [] if you don't want anything installed.
  • Host nodes also get an SSH keypair (see host_ssh_key). After manage_host_ssh_keys.yml runs, fetch /home/director/.ssh/id_ed25519.pub (or your overridden path) on each host and register it with your Git or jump hosts.
  • Add additional public keys to code_server.authorized_key_files (paths on optibcc) or code_server.authorized_keys (raw strings) and the role will publish them to /config/.ssh/authorized_keys, letting you SSH to the container without using the password.
  • To run Ansible from the code-server terminal, set code_server.controller_private_key_path to the host-side private key (default: /home/director/.ssh/id_ed25519). The role copies it into /config/.ssh/controller_id, writes an SSH config forcing User {{ code_server.controller_ssh_user }}, and exports ANSIBLE_SSH_ARGS so ansible-playbook uses the mounted key automatically.

Codex integration to Code server: https://github.com/openai/codex/blob/main/docs/authentication.md#connecting-on-a-headless-machine

CloudCLI access

  • CloudCLI deploys to deskpi by default and is published at https://cloudcli.<home_domain>.
  • It builds a local image with Node 22, @cloudcli-ai/cloudcli, @openai/codex, and a complete Playwright/Chromium runtime for browser automation, then mounts its state under /opt/stacks/cloudcli/config.
  • Log Codex in once with codex login from the CloudCLI terminal; the login persists in /opt/stacks/cloudcli/config/.codex/auth.json and is covered by the management-plane backup.
  • Add or change editable mounts under cloudcli.workspace_mounts in ansible/inventories/prod/group_vars/prod/dev.services.yml, then run ansible-playbook playbooks/deploy_cloudcli.yml.

Dev workstations (wipe/redeploy-able)

These are personal dev machines, not prod servers -- no Docker/Traefik/etc roles apply to them.

  • Omarchy (Arch Linux) laptop is Ansible-managed like any other host. Fill in the TODOs in ansible/inventories/prod/group_vars/workstations/baseline.yml (login username, git identity, pinned Godot version) and in ansible/inventories/prod/hosts.yml (the omarchy-laptop entry's IP/user), then run ansible-playbook playbooks/deploy_workstation.yml. On a freshly wiped laptop, bootstrap its SSH key first the same way as bwtvmonitor/channel11 (password auth via the unkeyed group, see playbooks/bootstrap_ssh_key.yml) before it's reachable as a normal host. Copy the SSH pubkey the role generates into Gitea manually afterward (same pattern as the code-server/host keys above). If you ever add AUR-only packages to workstation.aur_packages, make sure yay/paru is already installed first -- the role fails loudly rather than guessing.
  • Windows desktop uses scripts/windows/bootstrap-workstation.ps1 instead -- WinRM setup on a fresh Windows box is itself a manual step, so a plain winget-based script is simpler and equally repeatable. Fill in its TODOs (git identity, verified Godot winget package ID) and run it once manually after a wipe/fresh install. If WSL-hosted services need to be reachable from the homelab LAN, see docs/windows-hermes-rollout.md. The helper scripts scripts/windows/update-wsl-portproxy.ps1 and scripts/windows/register-wsl-portproxy-task.ps1 refresh Windows portproxy/firewall rules from the desktop LAN IP to WSL's current NAT IP.
  • Both sides intentionally keep their package lists as plain, easily-edited data (workstation.pacman_packages/aur_packages in baseline.yml, $WingetPackages in the script) -- the starting set is just git/git-lfs, expected to grow over time.