Files
racknerd/ansible/README.md
T
2026-07-15 21:09:29 -07:00

4.1 KiB

Ansible deploy

One playbook does both jobs: the first run provisions the host (Docker, WireGuard, sysctl, firewall) and deploys the stack; every later run is the update path — it only touches what changed and restarts only the affected services.

Deployed layout on the VPS (per-service dirs under /opt):

Path Contents
/opt/vpnhub/ docker-compose.yml, .env
/opt/openvpn/ build context, server.conf, pki/
/opt/duo-authproxy/ build context, cfg template, certs/
/opt/technitium/ init-job build context + config/ (live zone DB — never overwritten by the playbook)

The playbook renders the firewall and wg0 config from the same host/rules.v4.template / host/wg0.conf.example files the manual path uses — nothing is duplicated inside ansible/.

Prerequisites

A Linux control node (WSL is fine — this repo checked out inside WSL or accessed via /mnt/c/...), ansible-core >= 2.15, then:

cd ansible
ansible-galaxy collection install -r requirements.yml

Bootstrap (once per fresh VPS)

bootstrap.yml connects as root (it overrides whatever ansible_user the inventory has), creates the ansible automation user — SSH key only, locked password, passwordless sudo — proves the new user can log in and sudo in a second play, and only then locks sshd down: key-only auth (PasswordAuthentication no) and root SSH login disabled (PermitRootLogin no). Break-glass access after that is the provider's console, not SSH:

cp inventory.example.yml inventory.yml
ansible-playbook bootstrap.yml
# custom key or username:
ansible-playbook bootstrap.yml -e bootstrap_ssh_public_key_file=~/.ssh/vpnhub.pub

It prompts for the root SSH password up front (install sshpass on the control node for password auth). If root already logs in with your key, just press Enter at the prompt.

Everything after this runs as ansible (already the inventory example's default).

First-time setup

cp inventory.example.yml inventory.yml            # set host/user (if not done above)
cp group_vars/vpnhub.example.yml group_vars/vpnhub.yml
$EDITOR group_vars/vpnhub.yml                     # DC IPs, Duo keys, secrets
ansible-vault encrypt group_vars/vpnhub.yml       # both files are gitignored anyway

# Local key material (both gitignored, synced to /opt by the playbook):
#   ../openvpn/pki/            server.crt, server.key, ta.key  (offline CA)
#   ../duo-authproxy/certs/    ad-ldaps-ca.pem

ansible-playbook site.yml

The first run prints the hub WireGuard public key and stops short of starting wg0 (site peer keys are still empty). Add the hub as a peer at both sites (docs/SITE-SIDE.md), paste each site's public key into group_vars/vpnhub.yml (troch_wg_public_key / oswald_wg_public_key), and run it again — wg0 comes up and the stack starts.

Updating

What changed Command
Any config in the repo, .env values ansible-playbook site.yml (affected services recreate)
Just stack files, skip host checks ansible-playbook site.yml --tags stack
Base images / rebuild everything ansible-playbook site.yml -e vpnhub_force_rebuild=true
Duo Auth Proxy version bump duo_authproxy_version, then force-rebuild as above
Firewall only ansible-playbook site.yml --tags firewall
WireGuard peers/config ansible-playbook site.yml --tags wireguard

Note on duo_authproxy_version: latest: Docker's layer cache means "latest" won't re-download a newer tarball on rebuild. Pin a real version (the cache busts when it changes) — that's the reliable update mechanism.

Tags

docker, host (packages + sysctl + firewall + wg), firewall, wireguard, stack.