MOP-001 — Node Build & Deployment

Last updated: 2026-05-25

Node Build & Deployment

Complete procedure for building, provisioning, and shipping an AMP gateway node from blank SD card to customer doorstep.

SSH Key Reference

KeyFileWhen to use
Recovery key~/.ssh/id_ed25519Only if provisioning fails — SSH access before operational key is installed
Operational key~/.ssh/amp-deployAll 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)

1.1 — Generate the deploy keypair

Run once on your laptop. Never run again unless rotating keys.

ssh-keygen -t ed25519 -C "amp-deploy" -f "$env:USERPROFILE\.ssh\amp-deploy"
1.2 — Set BT environment variables

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>
AMP_SALT_SECRET must never change after the first node registers — it will break serial generation for all existing nodes.

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

2.1 — Flash the SD card

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.

2.2 — Assign drive letter (admin PowerShell)

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.

2.3 — Prep the SD card

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
Confirm output ends with: SD card ready.
2.4 — Boot the Pi

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.

If no WiFi pre-staged: Pi broadcasts AMP-XXXX hotspot (password: amp-setup). Connect and open http://10.42.0.1 to enter WiFi credentials.
2.5 — SSH in and verify

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
Check Hoike — node should appear within 5 minutes of boot completing.
2.6 — Fix Tailscale display name

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.

2.7 — Pre-stage WiFi (ʻOhana beta nodes 21–23 only)

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.

2.8 — Nessus burn-in scan (Node 50+ required; beta recommended)

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
To reset Nessus password: /opt/nessus/sbin/nessuscli chpasswd pmp_nessie (run on BT)

Part 3 — Pack & Ship

3.1 — Pack the unit
  • 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
3.2 — Ship

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.

The Tailscale free plan caps auth key expiry at 90 days. Current key expires August 23, 2026. Nodes already on Tailscale are unaffected — only new provisioning breaks if the key expires.

Rotation Steps

1 — Generate a new Tailscale auth key

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.

2 — Update BT .env
nano /opt/amp/blue-triangle/.env

Replace the TS_AUTHKEY= value with the new key.

3 — Restart the API
cd /opt/amp/blue-triangle docker compose up -d --force-recreate api docker exec amp-api env | grep TS_AUTHKEY
Confirm the new key is shown in the container env output.
4 — Test with a token generate call
Invoke-RestMethod -Uri "http://100.113.114.32:5000/api/token/generate" -Method POST

Confirm response includes ts_authkey with the new key value.

5 — Update calendar reminder

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)

The recovery key (id_ed25519) is installed early in first boot and stays in place if provisioning fails. Use it to get in.
1 — SSH in with recovery key
ssh -i ~/.ssh/id_ed25519 pi@<local-ip>
2 — Check what failed
sudo journalctl -u amp-firstboot --no-pager
3 — Generate a new provision token

Run on your laptop (old token may be consumed):

Invoke-RestMethod -Uri "http://100.113.114.32:5000/api/token/generate" -Method POST
4 — Write new token and re-run

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

1 — Check Tailscale first

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>
2 — Check heartbeat and Hoike
sudo tail -20 /var/log/amp-heartbeat.log sudo /usr/local/bin/amp-heartbeat.sh
3 — Check Tailscale status on the node
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

RangeTypeNotes
01–19Lab / internaltag:private — never ships to customers
20–49ʻOhana betaLifetime free — family units, pre-stage WiFi before shipping
50+Production / paidFull Nessus scan required before shipping