Skip to content

Runbook: Provisioning a device

One-command path (recommended) and the manual step breakdown for when something in the middle fails and needs a retry.

Prerequisites

  • Terraform installed, jq installed
  • .env at the repo root with SSH_USER / SSH_PASSWORD for the device's default user (see .env.example)
  • CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID exported for Terraform and for task credentials:export
  • The device is booted, on the network, with SSH enabled
  • Ansible Vault password at ansible/.vault-password

0. Register the device

Add it to config/devices.yml under the right environment (production, staging, development, or the lite_environments equivalent):

production:
  devices:
    <new-12-hex-serial>:
      ip_address: "192.168.1.106"
      location: "Lab"

This is the only place the device needs to be declared for Terraform.

1. One-command provisioning

task setup-device DEVICE=rpi-prod-<serial> IP=192.168.1.106

This is task workflows:setup-device — see architecture.md for what it chains together. Expect ~10-15 minutes.

2. Verify

curl -I https://rpi-prod-<serial>.tagai.uk
# expect a redirect toward Cloudflare Access

task ansible:health-prod   # or the matching -dev / -staging / -lite variant

Open https://rpi-prod-<serial>-nodered.tagai.uk in a browser — you should hit Cloudflare Access first, then the Node-RED editor after authenticating.

Manual step-by-step (if the one-command flow fails partway)

Each of these is safe to re-run on its own.

1. Terraform (tunnel + DNS)

cd terraform && terraform plan && terraform apply

2. Export tunnel credentials

task credentials:export DEVICE=rpi-prod-<serial>

3. Provision the device (creates tagai user, installs cloudflared + Node-RED)

task provision:single DEVICE=rpi-prod-<serial> IP=192.168.1.106

4. Generate the MQTT client certificate (one-time: task mqtt:init first, if the CA doesn't exist yet)

task mqtt:cert DEVICE=rpi-prod-<serial>

5. Sync configuration to the device

task sync:single DEVICE=rpi-prod-<serial> IP=192.168.1.106

6. Deploy via Ansible

task ansible:deploy DEVICE=rpi-prod-<serial>
# add TUNNEL=true to route over the Cloudflare Tunnel instead of the LAN IP

Troubleshooting

Device not reachable on LAN

ping 192.168.1.106
sudo nmap -sn 192.168.1.0/24   # find it if the IP changed

SSH connection refused — connect a monitor/keyboard directly and check:

sudo systemctl status ssh && sudo systemctl enable --now ssh

Provisioning failed mid-way — SSH in and check both services:

ssh tagai@rpi-prod-<serial>-ssh.tagai.uk   # or the LAN IP directly
sudo systemctl status cloudflared node-red
sudo journalctl -u cloudflared -n 50
sudo journalctl -u node-red -n 50
Then re-run the specific manual step above that failed.

Domain doesn't resolve / tunnel shows no connections

nslookup rpi-prod-<serial>.tagai.uk
# on the device:
sudo cloudflared tunnel info
sudo systemctl status cloudflared

Fleet-wide health check

task ansible:health           # all environments
ansible-playbook -i ansible/inventory/production/hosts.yml ansible/playbooks/healthcheck.yml