- Jinja 47.7%
- Python 41.7%
- JavaScript 7.1%
- TypeScript 1.5%
- Shell 1.4%
- Other 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
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
|
||
| .forgejo/workflows | ||
| .taskmaster | ||
| ansible | ||
| docs | ||
| examples | ||
| scripts | ||
| tests | ||
| .ansible-lint-ignore | ||
| .env.example | ||
| .gitignore | ||
| AGENTS.md | ||
| README.md | ||
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:
- Applies the
bootstrap_dnsresolvers defined per host (seeinventories/prod/hosts.yml) so apt can reach upstream repositories even while Pi-hole is offline. - Installs Docker everywhere (
site.yml). - Deploys Unbound, then Pi-hole on channel100 (Pi-hole is already configured to use
127.0.0.1#5335as upstream). - Deploys Traefik on channel101, purges stale dynamic configs, and rehydrates ACME storage.
- Deploys Authelia, writes the portal + middleware routes (with the production resolver), then renders all edge routes.
- Deploys Home Assistant and publishes its Traefik file-provider config.
- Deploys Dashy on channel101 and exposes it through Traefik.
- Deploys RomM + MariaDB on channel101 so the library is fronted by Traefik.
- Deploys CloudCLI on deskpi so Codex sessions can be managed through a browser UI behind Traefik.
- Restores each host’s permanent resolver list from the
operational_dnsvalues 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– comparejlesage/makemkvand 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 AMMusic 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 theworld-intelMCP server (stdio over ssh, viamcp_tool_filter_proxy.py) and to local Ollama models via the bundledmcp_ollama_bridge.pytool-calling bridge. Which tools are visible to each is controlled byworld_intel_mcp.enabled_tools/disabled_toolsinai.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 allprodhosts.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 + itsgames.services.ymlvar block per additional game (same pattern asdeploy_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 optionallysudo_password) inansible/inventories/prod/group_vars/prod/dev.vault.ymlbefore deploying. - Add any host paths you want to edit remotely under
code_server.workspace_mountsinansible/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 athttps://code.<home_domain>through Traefik + Authelia. - Codex is not provisioned from the vault: log in once with
codex loginfrom 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: falseso sudo is allowed, redeploy the role, then usesudo apt install ...from the web terminal. - The role now auto-generates an SSH keypair in
/config/.ssh/(configurable viacode_server.ssh_key). Grab the public key from/config/.ssh/id_ed25519.pubin the container and add it to your Git host so clones over SSH succeed. code_server.packageslists deb packages that should always exist inside the container (default:ansible,curl,dnsutils). After the stack comes up, the role runsapt-get installviadocker execso 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). Aftermanage_host_ssh_keys.ymlruns, 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) orcode_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_pathto the host-side private key (default:/home/director/.ssh/id_ed25519). The role copies it into/config/.ssh/controller_id, writes an SSH config forcingUser {{ code_server.controller_ssh_user }}, and exportsANSIBLE_SSH_ARGSsoansible-playbookuses 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
deskpiby default and is published athttps://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 loginfrom the CloudCLI terminal; the login persists in/opt/stacks/cloudcli/config/.codex/auth.jsonand is covered by the management-plane backup. - Add or change editable mounts under
cloudcli.workspace_mountsinansible/inventories/prod/group_vars/prod/dev.services.yml, then runansible-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 inansible/inventories/prod/group_vars/workstations/baseline.yml(login username, git identity, pinned Godot version) and inansible/inventories/prod/hosts.yml(theomarchy-laptopentry's IP/user), then runansible-playbook playbooks/deploy_workstation.yml. On a freshly wiped laptop, bootstrap its SSH key first the same way asbwtvmonitor/channel11(password auth via theunkeyedgroup, seeplaybooks/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 toworkstation.aur_packages, make sureyay/paruis already installed first -- the role fails loudly rather than guessing. - Windows desktop uses
scripts/windows/bootstrap-workstation.ps1instead -- 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 itsTODOs (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, seedocs/windows-hermes-rollout.md. The helper scriptsscripts/windows/update-wsl-portproxy.ps1andscripts/windows/register-wsl-portproxy-task.ps1refresh 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_packagesin baseline.yml,$WingetPackagesin the script) -- the starting set is justgit/git-lfs, expected to grow over time.