182 lines
4.5 KiB
Markdown
182 lines
4.5 KiB
Markdown
# Pi
|
|
|
|
Rust service and deployment workflow for the Raspberry Pi at Noisebridge.
|
|
|
|
The current recommended setup is:
|
|
|
|
1. run Raspberry Pi OS Lite on the Pi
|
|
2. keep the Pi itself free of Nix
|
|
3. build a static `aarch64` Noisebell binary on your laptop with Nix
|
|
4. copy the binary, secrets, and systemd service to the Pi over SSH
|
|
|
|
This avoids the Raspberry Pi Zero 2 W NixOS boot issues while still keeping the application build reproducible.
|
|
|
|
## What stays on Raspberry Pi OS
|
|
|
|
- bootloader
|
|
- kernel
|
|
- firmware
|
|
- Wi-Fi and local networking
|
|
- SSH base access
|
|
- Tailscale package/runtime
|
|
- Avahi package/runtime
|
|
|
|
## What Nix manages
|
|
|
|
- building a static `noisebell` binary for `aarch64-linux`
|
|
- the exact app binary you deploy
|
|
- encrypted secrets in the repo
|
|
- repeatable deployment from your laptop
|
|
|
|
## Initial Pi OS setup
|
|
|
|
### 1. Flash Raspberry Pi OS Lite
|
|
|
|
```sh
|
|
curl -L "https://downloads.raspberrypi.org/raspios_lite_arm64_latest" | xz -d -c | sudo dd of=/dev/sdb bs=16M conv=fsync status=progress && sync
|
|
```
|
|
|
|
### 2. Configure the flashed SD card
|
|
|
|
Configure it for:
|
|
|
|
- Wi-Fi on `Noisebridge`
|
|
- SSH enabled
|
|
- serial enabled if you want a recovery console
|
|
|
|
The helper script is:
|
|
|
|
```sh
|
|
sudo scripts/configure-pios-sd.sh /run/media/jet/bootfs /run/media/jet/rootfs
|
|
```
|
|
|
|
This setup expects SSH key login for user `pi`; it does not configure a password.
|
|
|
|
### 3. Boot the Pi and verify SSH
|
|
|
|
After boot, verify SSH works:
|
|
|
|
```sh
|
|
ssh pi@noisebridge-pi.local
|
|
```
|
|
|
|
## Add the Pi host key to age recipients
|
|
|
|
The deploy flow decrypts secrets locally on your laptop, but the Pi host key should still be a recipient for the Pi-facing secrets so the repo stays accurate.
|
|
|
|
Grab the Pi host key:
|
|
|
|
```sh
|
|
ssh-keyscan noisebridge-pi.local 2>/dev/null | grep ed25519
|
|
```
|
|
|
|
Add that key to `secrets/secrets.nix` for:
|
|
|
|
- `pi-to-cache-key.age`
|
|
- `cache-to-pi-key.age`
|
|
- `tailscale-auth-key.age`
|
|
|
|
Then refresh recipients if needed:
|
|
|
|
```sh
|
|
cd secrets
|
|
agenix -r
|
|
```
|
|
|
|
## Edit secrets
|
|
|
|
```sh
|
|
cd secrets
|
|
agenix -e pi-to-cache-key.age
|
|
agenix -e cache-to-pi-key.age
|
|
agenix -e tailscale-auth-key.age
|
|
```
|
|
|
|
These stay encrypted in git. The deploy script decrypts them locally on your laptop and copies the plaintext files to the Pi as root-only files.
|
|
|
|
## Deploy to Raspberry Pi OS
|
|
|
|
From your laptop:
|
|
|
|
```sh
|
|
scripts/deploy-pios-pi.sh pi@noisebridge-pi.local
|
|
```
|
|
|
|
If you only know the IP:
|
|
|
|
```sh
|
|
scripts/deploy-pios-pi.sh pi@10.21.x.x
|
|
```
|
|
|
|
That script:
|
|
|
|
1. builds `.#packages.aarch64-linux.noisebell-static` locally
|
|
2. decrypts the Pi-facing secrets locally with `agenix`
|
|
3. uploads the binary and secrets to the Pi
|
|
4. installs Tailscale and Avahi if needed
|
|
5. writes `/etc/noisebell/noisebell.env`
|
|
6. installs `noisebell.service`
|
|
7. enables and starts the service
|
|
8. runs `tailscale up` with the decrypted auth key
|
|
|
|
## Files written on the Pi
|
|
|
|
The deploy script creates:
|
|
|
|
- `/opt/noisebell/releases/<timestamp>/noisebell`
|
|
- `/opt/noisebell/current` -> current release symlink
|
|
- `/etc/noisebell/pi-to-cache-key`
|
|
- `/etc/noisebell/cache-to-pi-key`
|
|
- `/etc/noisebell/tailscale-auth-key`
|
|
- `/etc/noisebell/noisebell.env`
|
|
- `/etc/systemd/system/noisebell.service`
|
|
|
|
All secret files are root-only.
|
|
|
|
## Tailscale
|
|
|
|
Tailscale is kept on Raspberry Pi OS rather than NixOS.
|
|
|
|
The deploy script:
|
|
|
|
- installs the Tailscale package if missing
|
|
- enables `tailscaled`
|
|
- runs `tailscale up --auth-key=... --hostname=noisebridge-pi`
|
|
|
|
So Tailscale stays part of the base OS, while its auth key is still managed as an encrypted `age` secret in this repo.
|
|
|
|
## Later updates
|
|
|
|
Normal iteration is just rerunning the deploy script:
|
|
|
|
```sh
|
|
scripts/deploy-pios-pi.sh pi@noisebridge-pi.local
|
|
```
|
|
|
|
That rebuilds the binary locally, uploads a new release, refreshes secrets, and restarts the service.
|
|
|
|
## Service configuration
|
|
|
|
The deployed service uses these environment variables:
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `NOISEBELL_GPIO_PIN` | `17` | GPIO pin number |
|
|
| `NOISEBELL_DEBOUNCE_SECS` | `5` | Debounce delay in seconds |
|
|
| `NOISEBELL_PORT` | `80` | HTTP server port |
|
|
| `NOISEBELL_ENDPOINT_URL` | required | Webhook URL to POST state changes to |
|
|
| `NOISEBELL_RETRY_ATTEMPTS` | `3` | Webhook retry count |
|
|
| `NOISEBELL_RETRY_BASE_DELAY_SECS` | `1` | Exponential backoff base delay |
|
|
| `NOISEBELL_HTTP_TIMEOUT_SECS` | `10` | Outbound request timeout |
|
|
| `NOISEBELL_BIND_ADDRESS` | `0.0.0.0` | HTTP bind address |
|
|
| `NOISEBELL_ACTIVE_LOW` | `true` | Low GPIO = door open |
|
|
|
|
## API
|
|
|
|
All endpoints require `Authorization: Bearer <token>`.
|
|
|
|
**`GET /`**
|
|
|
|
```json
|
|
{"status": "open", "timestamp": 1710000000}
|
|
```
|