217 lines
5.9 KiB
Markdown
217 lines
5.9 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@noisebell-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 noisebell-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@noisebell-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. builds `.#packages.aarch64-linux.noisebell-relay-static` locally
|
|
3. decrypts the Pi-facing secrets locally with `agenix`
|
|
4. uploads the binaries and secrets to the Pi
|
|
5. installs Tailscale and Avahi if needed
|
|
6. writes `/etc/noisebell/noisebell.env`
|
|
7. writes `/etc/noisebell/noisebell-relay.env`
|
|
8. installs `noisebell.service` and `noisebell-relay.service`
|
|
9. enables and starts both services
|
|
10. runs `tailscale up` with the decrypted auth key
|
|
|
|
## Files written on the Pi
|
|
|
|
The deploy script creates:
|
|
|
|
- `/opt/noisebell/releases/<timestamp>/noisebell`
|
|
- `/opt/noisebell/releases/<timestamp>/noisebell-relay`
|
|
- `/opt/noisebell/current` -> current release symlink
|
|
- `/etc/noisebell/pi-to-cache-key`
|
|
- `/etc/noisebell/cache-to-pi-key`
|
|
- `/etc/noisebell/relay-webhook-secret`
|
|
- `/etc/noisebell/homeassistant-webhook-id`
|
|
- `/etc/noisebell/tailscale-auth-key`
|
|
- `/etc/noisebell/noisebell.env`
|
|
- `/etc/noisebell/noisebell-relay.env`
|
|
- `/etc/systemd/system/noisebell.service`
|
|
- `/etc/systemd/system/noisebell-relay.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=noisebell-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@noisebell-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_MS` | `50` | Debounce delay in milliseconds |
|
|
| `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 |
|
|
|
|
## Relay service configuration
|
|
|
|
The optional relay service accepts authenticated webhooks from cache-service and forwards them to Home Assistant on the local network.
|
|
|
|
| Variable | Default | Description |
|
|
|---|---|---|
|
|
| `NOISEBELL_RELAY_PORT` | `8090` | HTTP port for the relay webhook endpoint |
|
|
| `NOISEBELL_RELAY_BIND_ADDRESS` | `0.0.0.0` | HTTP bind address |
|
|
| `NOISEBELL_RELAY_TARGET_BASE_URL` | `http://homeassistant.local:8123` | Base URL for Home Assistant |
|
|
| `NOISEBELL_RELAY_TARGET_WEBHOOK_ID` | required | Home Assistant webhook ID |
|
|
| `NOISEBELL_RELAY_INBOUND_API_KEY` | required | Bearer token expected from cache-service |
|
|
| `NOISEBELL_RELAY_RETRY_ATTEMPTS` | `3` | Forward retry count |
|
|
| `NOISEBELL_RELAY_RETRY_BASE_DELAY_SECS` | `1` | Exponential backoff base delay |
|
|
| `NOISEBELL_RELAY_HTTP_TIMEOUT_SECS` | `10` | Outbound request timeout |
|
|
|
|
Example cache target for the relay:
|
|
|
|
```nix
|
|
{
|
|
services.noisebell-cache.outboundWebhooks = [
|
|
{
|
|
url = "http://noisebell-pi.local:8090/webhook";
|
|
secretFile = /run/agenix/noisebell-relay-webhook-secret;
|
|
}
|
|
];
|
|
}
|
|
```
|
|
|
|
## API
|
|
|
|
All endpoints require `Authorization: Bearer <token>`.
|
|
|
|
**`GET /`**
|
|
|
|
```json
|
|
{"status": "open", "timestamp": 1710000000}
|
|
```
|