Skip to content

Gaisro Technika Infrastructure

Infrastructure as Code for a fleet of Raspberry Pi devices running Node-RED, reachable over Cloudflare Tunnels with Cloudflare Access (Zero Trust) in front, publishing to an mTLS-secured MQTT broker (EMQX). Domain: tagai.uk.

See architecture.md for how the pieces fit together, or devices.md for the current fleet and quick links to each device's Node-RED and SSH endpoints.

Quick start: provision one device

Everything is driven through Taskfile.yml at the repo root. The one-command path for a new device:

task setup-device DEVICE=rpi-prod-1883c404a12f IP=192.168.1.100

This runs task workflows:setup-device, which chains:

  1. terraform plan / terraform apply — creates the Cloudflare Tunnel and the three DNS records for this device (see architecture.md)
  2. task credentials:export — exports the tunnel credentials for the new device
  3. task provision:single — creates the tagai user on the device, installs cloudflared and Node-RED as native systemd services (no Docker)
  4. task mqtt:cert — generates a 2-year mTLS client certificate for MQTT
  5. task sync:single — copies configuration (tunnel credentials, MQTT certs, Node-RED settings) from this repo to the device
  6. task ansible:deploy — runs the Ansible role stack against the device

Device type is inferred from the DEVICE name: rpi-lite-* uses the light Node-RED project, everything else uses the standard one.

Prerequisites: Terraform, jq, SSH access to the device, and a .env file with SSH_USER/SSH_PASSWORD (see .env.example) plus Cloudflare credentials (CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID) for Terraform.

Before running this, add the device's serial number to config/devices.yml under the right environment — that file is the source of truth Terraform reads to know which devices should exist.

For the full step-by-step (including troubleshooting each stage), see runbooks/provisioning.md. For the whole fleet at once: task setup-fleet.

Verify it worked

curl -I https://rpi-prod-1883c404a12f.tagai.uk
# expect a redirect to Cloudflare Access

task ansible:health-prod   # or health-dev / health-staging

Where things live

Concern Location
Device inventory (source of truth) config/devices.yml
Tunnel + DNS + Access (Terraform) terraform/
Fleet configuration (Ansible) ansible/
Task runner Taskfile.yml + taskfiles/*.yml
Provisioning helper scripts scripts/

Documentation map