stack/ansible
tim 3bf1726a99 Centralize demo config in .env and add bootstrap-stack.sh
Expand .env.example with ports, AI, Usenet, WireGuard, demo logins, and
bootstrap flags. One script creates dirs, downloads the model, starts
compose, heals gluetun, and configures SABnzbd from the same file.
2026-07-22 13:06:08 -07:00
..
group_vars Centralize demo config in .env and add bootstrap-stack.sh 2026-07-22 13:06:08 -07:00
inventory Initial commit: arr-stack homelab + local AI 2026-07-22 06:28:49 -07:00
roles Centralize demo config in .env and add bootstrap-stack.sh 2026-07-22 13:06:08 -07:00
ansible.cfg Initial commit: arr-stack homelab + local AI 2026-07-22 06:28:49 -07:00
README.md Initial commit: arr-stack homelab + local AI 2026-07-22 06:28:49 -07:00
requirements.yml Initial commit: arr-stack homelab + local AI 2026-07-22 06:28:49 -07:00
site.yml Initial commit: arr-stack homelab + local AI 2026-07-22 06:28:49 -07:00

Homelab Ansible — Ubuntu 24.04 (SER5 PRO)

Bootstraps the headless mini PC for arr-stack + Ternary-Bonsai (Vulkan).

Item Value
Host 192.168.8.123:22
User tim
SSH key ~/.ssh/id_ed25519
Stack /opt/stack
Media /storage

What it installs

  1. common — apt upgrade, essentials (curl wget nano build-essential net-tools), Microsoft Edit, tools, unattended-upgrades, fail2ban
  2. docker — Docker CE + Compose plugin, enabled on boot, user in docker
  3. amd_vulkan — Mesa Vulkan, VA-API, firmware, video/render groups, udev rules
  4. firewall — UFW: deny inbound, allow stack ports from LAN only (192.168.8.0/24)
  5. stack/opt/stack + /storage, rsync project, .env, Vulkan compose override, arr-stack.service so compose comes up after reboot (restart: unless-stopped on every service)

Prerequisites (control machine)

# Debian/Ubuntu control node
sudo apt install -y ansible git rsync

cd /path/to/arr-stack/ansible
ansible-galaxy collection install -r requirements.yml

SSH must already work:

ssh -i ~/.ssh/id_ed25519 tim@192.168.8.123

On the server, either enable passwordless sudo (recommended for automation):

echo 'tim ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/tim
sudo chmod 440 /etc/sudoers.d/tim

…or pass the sudo password each run with -K / --ask-become-pass.

Run

cd ansible

# Full bootstrap (prompt for sudo if not NOPASSWD)
ansible-playbook site.yml -K

# Or limit / tags
ansible-playbook site.yml -K --tags docker,amd,firewall
ansible-playbook site.yml -K --tags stack,deploy
ansible-playbook site.yml -K --check   # dry-run (partial)

First connection may prompt for host key (accept-new is set in ansible.cfg).

After the playbook

On the server (or via SSH):

ssh tim@192.168.8.123
# new shell so docker/video/render groups apply
cd /opt/stack

# WireGuard (if not copied): edit wireguard/wg0.conf
# Model (~7.2G):
./scripts/download-bonsai-model.sh

# Vulkan image + stack
docker compose build bonsai
docker compose up -d
docker compose ps

Verify GPU / tools inside the host:

vulkaninfo --summary
ls -l /dev/dri
groups   # should include docker, video, render
edit --version   # Microsoft terminal editor
curl --version && wget --version && nano --version

Survive reboots:

systemctl is-enabled docker arr-stack
systemctl status arr-stack
# containers use restart: unless-stopped; arr-stack.service runs compose up -d on boot

Layout on the server

/opt/stack/                 # compose, config, models, workspace, wireguard
  docker-compose.yml
  docker-compose.override.yml   # /dev/dri for bonsai + jellyfin
  .env
  config/
  models/bonsai/
  workspace/
  wireguard/wg0.conf

/storage/                   # 1TB media disk
  media/{movies,tv,music}
  torrents/{movies,tv,music}

.env points DATA_DIR=/storage and CONFIG_DIR=/opt/stack/config.

Variables

Edit group_vars/all.yml (or host_vars) for:

  • lan_subnet, timezone
  • bonsai_backend / bonsai_ngl (default vulkan / 99)
  • ufw_allow_ssh_from_anywhere (default false — SSH only from LAN)
  • deploy_stack_files — set false to skip rsync

Security notes

  • Do not commit wireguard/wg0.conf or production .env.
  • UFW allows service ports only from lan_subnet.
  • Fail2ban protects SSH.
  • Re-login after first run so group membership (docker, render) is active.