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,
jqinstalled .envat the repo root withSSH_USER/SSH_PASSWORDfor the device's default user (see.env.example)CLOUDFLARE_API_TOKENandCLOUDFLARE_ACCOUNT_IDexported for Terraform and forjust 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¶
just setup-device rpi-prod-<serial> 192.168.1.106
This is just 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
just 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.
3. Print and stick the label¶
just docs label-print rpi-prod-<serial>
Prints a 40x20 mm label carrying a QR code of https://<device-id>.tagai.uk
plus the serial, environment prefix and location, on the Phomemo M110 over USB.
Stick it on the enclosure before the device leaves the bench — the serial is
otherwise only readable by opening the case or querying the fleet.
Scan the QR with a phone camera before fitting it; it should open the device's Cloudflare Access page. First time on a given Mac, see label-printing-provisioning.md for the one-time driver and CUPS queue setup.
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
just credentials export rpi-prod-<serial>
3. Provision the device (creates tagai user, installs cloudflared + Node-RED)
just provision rpi-prod-<serial> 192.168.1.106
4. Generate the MQTT client certificate (one-time: just mqtt init first,
if the CA doesn't exist yet)
just mqtt cert rpi-prod-<serial>
5. Sync configuration to the device
just sync single rpi-prod-<serial> 192.168.1.106
6. Deploy via Ansible
just ansible deploy rpi-prod-<serial>
# add --tunnel 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
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
just ansible health # all environments
ansible-playbook -i ansible/inventory/production/hosts.yml ansible/playbooks/healthcheck.yml