Node Build & Deployment
Complete procedure for building, provisioning, and shipping an AMP gateway node from blank SD card to customer doorstep.
SSH Key Reference
| Key | File | When to use |
|---|---|---|
| Recovery key | ~/.ssh/id_ed25519 | Only if provisioning fails — SSH access before operational key is installed |
| Operational key | ~/.ssh/amp-deploy | All SSH access to provisioned nodes |
After provisioning completes, always use:
ssh -i ~/.ssh/amp-deploy pi@<ip>
Part 1 — One-Time Setup (skip if already done)
Run once on your laptop. Never run again unless rotating keys.
ssh-keygen -t ed25519 -C "amp-deploy" -f "$env:USERPROFILE\.ssh\amp-deploy"
SSH into Blue Triangle. Edit /opt/amp/blue-triangle/.env and confirm all three are present:
AMP_SALT_SECRET=<openssl rand -hex 32>
AMP_DEPLOY_PUBKEY=ssh-ed25519 AAAA... amp-deploy
TS_AUTHKEY=tskey-auth-<key from tailscale.com/admin>
Restart the API to pick up changes:
cd /opt/amp/blue-triangle && docker compose up -d --force-recreate api
docker exec amp-api env | grep -E "AMP_SALT|AMP_DEPLOY|TS_AUTHKEY"
Part 2 — Per-Node Build
Open Raspberry Pi Imager:
- OS: Raspberry Pi OS Lite (64-bit) — Debian Trixie
- Storage: SD card (32GB+, Class 10 / A1)
- OS Customization → Username: pi, set password, enable SSH
- WiFi: leave blank for Node 50+ (captive portal handles it)
Wait for write + verification to complete before ejecting.
Windows won't auto-mount the FAT32 boot partition. Open PowerShell as Administrator:
Get-Disk | Get-Partition
Find the SD card disk number. Look for the small (~500MB) FAT32 partition. Assign a letter:
Set-Partition -DiskNumber <X> -PartitionNumber 1 -NewDriveLetter E
Confirm bootfs (E:) appears in File Explorer.
In standard PowerShell (not admin):
cd C:\alamalu
.\build\prep-sdcard.ps1
The script writes to the boot partition:
- amp-provision.token — one-time token from BT
- amp-ts-authkey — Tailscale auth key from BT
- amp-recovery.pub — Leonard's personal SSH key
- amp-firstboot.sh — provisioning script
- user-data — AMP service hook appended to cloud-init
Eject SD card → insert into Argon NEO → connect power. No ethernet required.
Automated sequence:
- Boot 1: Cloud-init sets up user/SSH → installs amp-firstboot service → reboots
- Boot 2: amp-firstboot runs → WiFi check → Tailscale join → BT provision → hostname set → heartbeat installed
Total time: 5–10 minutes.
Find the Pi's IP on your router DHCP table. SSH using the operational key:
ssh -i ~/.ssh/amp-deploy pi@<local-ip>
Verify provisioning:
# Serial and hostname
cat /etc/amp-serial
hostname
# Tailscale
tailscale ip -4
tailscale status
# Heartbeat
crontab -l
sudo journalctl -u amp-firstboot --no-pager | tail -20
Tailscale joins before hostname is set. Update the display name:
sudo tailscale set --hostname=$(cat /etc/amp-serial)
If admin page still shows old name: tailscale.com/admin → Machines → ... → Edit name → set to AMP serial.
The recipient's WiFi can't be seen from your house. Add it without scanning:
sudo nmcli connection add type wifi con-name "TheirSSID" ssid "TheirSSID" \
wifi-sec.key-mgmt wpa-psk wifi-sec.psk "theirpassword" \
connection.autoconnect yes
Verify both networks saved:
nmcli connection show
Your home WiFi stays as a fallback for remote diagnostics.
Open https://100.113.114.32:8834 — login: pmp_nessie
New Scan → Basic Network Scan:
- Name: AMP Node XX — <serial>
- Target: Pi's Tailscale IP (tailscale ip -4 on the Pi)
Credentials tab → SSH → Public Key:
- Username: pi
- Private key: ~/.ssh/amp-nessus (copy from /root/.ssh/amp-nessus on BT if not on laptop)
- Passphrase: blank
Save → Launch. Review results:
- Critical / High → must remediate before shipping
- Medium → case-by-case
- Low → accept
Part 3 — Pack & Ship
- Power off the Pi
- Wrap Argon NEO in 4" × 6" clear bubble pouch
- Place in Eupako 4" × 4" × 2" white corrugated mailer
- Apply AMP logo sticker (2" × 2.5") to box lid and Pi unit
- Apply QR code sticker (1" × 1.5") to Pi unit — links to setup.alamalu.com
- If stickers not available: include printed QR code insert
Seal and ship. Notify recipient:
- Plug in and wait 10 minutes
- If no internet on first boot: connect to AMP-XXXX hotspot and open http://10.42.0.1
- Scan QR code → complete registration at setup.alamalu.com
Tailscale Key Rotation
Procedure for rotating the TS_AUTHKEY before it expires. Must be completed before August 23, 2026 and every 90 days thereafter.
Rotation Steps
Go to tailscale.com/admin → Settings → Keys → Generate auth key:
- Description: amp-provision
- Reusable: yes
- Ephemeral: no
- Tags: tag:exit-node
- Expiry: 90 days
Copy the full key (tskey-auth-...). Note the new expiry date.
nano /opt/amp/blue-triangle/.env
Replace the TS_AUTHKEY= value with the new key.
cd /opt/amp/blue-triangle
docker compose up -d --force-recreate api
docker exec amp-api env | grep TS_AUTHKEY
Invoke-RestMethod -Uri "http://100.113.114.32:5000/api/token/generate" -Method POST
Confirm response includes ts_authkey with the new key value.
Set a reminder for the new expiry date (90 days from today). Rotation takes ~10 minutes.
Node Recovery
Procedure for recovering a node that failed to provision, went offline, or is unreachable via SSH.
Scenario 1 — First Boot Failed (before provisioning completed)
ssh -i ~/.ssh/id_ed25519 pi@<local-ip>
sudo journalctl -u amp-firstboot --no-pager
Run on your laptop (old token may be consumed):
Invoke-RestMethod -Uri "http://100.113.114.32:5000/api/token/generate" -Method POST
On the Pi:
echo "<new-token>" | sudo tee /boot/firmware/amp-provision.token
sudo rm -f /etc/amp-firstboot-done
sudo systemctl restart amp-firstboot
Scenario 2 — Provisioned Node Unreachable
The Pi may be reachable via Tailscale even if the local IP changed:
tailscale status
Find the node by its AMP serial and SSH via its Tailscale IP:
ssh -i ~/.ssh/amp-deploy pi@<100.x.x.x>
sudo tail -20 /var/log/amp-heartbeat.log
sudo /usr/local/bin/amp-heartbeat.sh
tailscale status
tailscale ip -4
If Tailscale is down:
sudo tailscale up --authkey=<TS_AUTHKEY from BT .env> --advertise-exit-node --advertise-tags="tag:exit-node" --ssh
Node Range Reference
| Range | Type | Notes |
|---|---|---|
| 01–19 | Lab / internal | tag:private — never ships to customers |
| 20–49 | ʻOhana beta | Lifetime free — family units, pre-stage WiFi before shipping |
| 50+ | Production / paid | Full Nessus scan required before shipping |