10 KiB
FIPS on Raspberry Pi Zero 2W — Deployment Plan
Goal
Deploy the Rust FIPS mesh daemon on a Raspberry Pi Zero 2W as a personal mesh endpoint. The Pi joins the FIPS network, gets its own npub identity, and lets applications on the device (or forwarded from the LAN) reach other FIPS nodes by npub address.
Hardware Profile
| Spec | Pi Zero 2W | FIPS Requirement |
|---|---|---|
| SoC | BCM2710A1 — quad-core Cortex-A53 @ 1 GHz | Rust binary, Noise crypto |
| Architecture | ARMv8-A (aarch64) | First-class target in FIPS |
| RAM | 512 MB | ~10-30 MB typical for FIPS |
| WiFi | 802.11 b/g/n (2.4 GHz) | UDP/TCP transports |
| Bluetooth | BT 4.2 / BLE | BLE L2CAP transport (with BlueZ) |
| Storage | microSD | ~5-10 MB for binaries + config |
| GPIO | 40-pin header | Not needed for FIPS |
| USB | 1x micro-USB OTG | USB Ethernet adapter for wired transport |
Verdict: Fully capable. The Pi Zero 2W has the same Cortex-A53 cores found in many OpenWrt routers already running FIPS, with 4-16x more RAM than typical router targets.
Strategy
- Cross-compile from an x86_64 dev machine targeting
aarch64-unknown-linux-gnu(Raspberry Pi OS) oraarch64-unknown-linux-musl(static binary) - Deploy via systemd tarball — the simplest packaging path for Raspberry Pi OS
- Configure as leaf-only — minimize resource usage by delegating routing to an upstream peer
- Optionally enable BLE — the onboard Bluetooth can bridge nearby BLE mesh devices
OS Choice
graph TD
A["Pi Zero 2W"] --> B{"Which OS?"}
B -->|Simplest| C["Raspberry Pi OS 64-bit<br/>Debian bookworm based"]
B -->|Router-style| D["OpenWrt<br/>bcm27xx/bcm2710 target"]
C --> E["Deploy via .deb or systemd tarball"]
D --> F["Deploy via .ipk package"]
C --> G["Best for: personal endpoint,<br/>BLE bridge, development"]
D --> H["Best for: headless relay,<br/>network appliance"]
Recommended: Raspberry Pi OS 64-bit — it's the path of least resistance. Debian-based, so the existing FIPS .deb packaging or systemd tarball works directly. BlueZ is available from apt for BLE support.
Architecture
graph TD
subgraph "Pi Zero 2W"
subgraph "FIPS Daemon"
NODE["fips<br/>mesh node"]
TUN["fips0 TUN<br/>fd00::/8 IPv6"]
DNS["DNS responder<br/>127.0.0.1:5354"]
end
subgraph "Transports"
WIFI_UDP["UDP via WiFi<br/>0.0.0.0:2121"]
WIFI_TCP["TCP via WiFi<br/>0.0.0.0:8443"]
BLE_T["BLE L2CAP<br/>optional"]
end
subgraph "Applications"
SSH["SSH to npub.fips"]
PING["ping6 npub.fips"]
APP["Any IPv6 app"]
end
end
subgraph "FIPS Mesh"
UPSTREAM["Upstream Peer<br/>handles routing"]
OTHER["Other Mesh Nodes"]
end
APP --> TUN
SSH --> TUN
PING --> TUN
TUN --> NODE
NODE --> WIFI_UDP
NODE --> WIFI_TCP
NODE --> BLE_T
WIFI_UDP --> UPSTREAM
WIFI_TCP --> UPSTREAM
UPSTREAM --> OTHER
DNS --> NODE
Build & Deploy Steps
Phase 1: Cross-Compile
Build on an x86_64 host targeting the Pi's architecture.
Option A — Dynamic linking (Raspberry Pi OS):
# Install cross-compilation toolchain
sudo apt install gcc-aarch64-linux-gnu
# Add Rust target
rustup target add aarch64-unknown-linux-gnu
# Build FIPS
cd fips
cargo build --release --target aarch64-unknown-linux-gnu --features gateway
Option B — Static binary via cargo-zigbuild (any Linux):
cargo install cargo-zigbuild
cargo zigbuild --release --target aarch64-unknown-linux-musl --features gateway
Option C — Use the existing tarball script:
./packaging/systemd/build-tarball.sh --target aarch64-unknown-linux-gnu
# Output: deploy/fips-<version>-linux-aarch64.tar.gz
Option D — Build a .deb package:
cargo install cargo-deb
./packaging/debian/build-deb.sh --target aarch64-unknown-linux-gnu
# Output: deploy/fips_<version>_arm64.deb
Phase 2: Pi OS Setup
On the Pi Zero 2W running Raspberry Pi OS 64-bit:
# Update system
sudo apt update && sudo apt upgrade -y
# Install TUN support (usually already present)
sudo modprobe tun
# For BLE transport (optional):
sudo apt install bluez libdbus-1-dev
# Create fips user and directories
sudo useradd -r -s /usr/sbin/nologin fips
sudo mkdir -p /etc/fips /run/fips
sudo chown fips:fips /run/fips
Phase 3: Install FIPS
From tarball:
# Copy tarball to Pi
scp deploy/fips-*-linux-aarch64.tar.gz pi@raspberrypi:
# On the Pi:
sudo tar -xzf fips-*-linux-aarch64.tar.gz -C /
sudo systemctl daemon-reload
sudo systemctl enable fips
From .deb:
scp deploy/fips_*_arm64.deb pi@raspberrypi:
sudo dpkg -i fips_*_arm64.deb
Phase 4: Configure
Create /etc/fips/fips.yaml:
# Pi Zero 2W — leaf endpoint configuration
node:
identity:
persistent: true # Keep same npub across restarts
leaf_only: true # Delegate routing to upstream peer
cache:
coord_size: 1000 # Reduced from default 50,000
identity_size: 500 # Reduced from default 10,000
limits:
max_peers: 8 # Reduced from default 128
max_connections: 16 # Reduced from default 256
tun:
enabled: true
name: fips0
mtu: 1280
dns:
enabled: true
bind_addr: "127.0.0.1"
port: 5354
transports:
udp:
bind_addr: "0.0.0.0:2121"
tcp:
bind_addr: "0.0.0.0:8443"
# Uncomment for BLE mesh bridging:
# ble:
# adapter: "hci0"
# mtu: 2048
# advertise: true
# scan: true
# auto_connect: true
# accept_connections: true
peers:
- npub: "npub1..." # Your upstream peer's npub
alias: "upstream"
addresses:
- transport: udp
addr: "x.x.x.x:2121" # Upstream peer's address
connect_policy: auto_connect
Phase 5: Start & Verify
# Start the daemon
sudo systemctl start fips
# Check status
sudo systemctl status fips
journalctl -u fips -f
# Verify mesh connectivity
fipsctl show_node
fipsctl show_peers
# Test connectivity to another node
ping6 npub1<other-node>.fips
Resource Tuning for 512 MB RAM
The default FIPS configuration targets servers/desktops with ample RAM. For the Pi Zero 2W, these config overrides keep memory usage well under 50 MB:
| Parameter | Default | Pi Recommended | Why |
|---|---|---|---|
node.cache.coord_size |
50,000 | 1,000 | Small mesh, few destinations |
node.cache.identity_size |
10,000 | 500 | Few unique peers |
node.limits.max_peers |
128 | 8 | Leaf node, 1-3 peers typical |
node.limits.max_connections |
256 | 16 | Proportional to max_peers |
node.limits.max_pending_inbound |
1,000 | 50 | Leaf gets few inbound |
node.leaf_only |
false | true | Delegate routing overhead |
Transport Options on Pi Zero 2W
WiFi (UDP + TCP) — Primary
The onboard 2.4 GHz WiFi connects to your home network and reaches internet-connected FIPS peers. This is the default and requires no extra hardware.
BLE — Local Mesh Bridge
The Pi's Bluetooth 4.2 supports BLE L2CAP, which FIPS uses for short-range mesh links. Build with --features ble and install BlueZ. The Pi could bridge BLE-only devices (like ESP32 nodes) into the wider mesh.
graph LR
ESP1["ESP32<br/>BLE only"] -->|"BLE L2CAP"| PI["Pi Zero 2W<br/>BLE + WiFi"]
ESP2["ESP32<br/>BLE only"] -->|"BLE L2CAP"| PI
PI -->|"UDP over WiFi"| MESH["Internet Mesh<br/>Peers"]
USB Ethernet — Wired Option
A USB Ethernet adapter on the OTG port enables the raw Ethernet transport (EtherType 0x2121) for direct L2 mesh links to nearby nodes without IP overhead.
Tor — Anonymous Overlay
Install the tor package and configure the Tor transport for anonymous mesh participation. Adds latency (200ms-2s RTT) but works.
Leaf-Only Mode Status
The node.leaf_only config flag exists in the codebase and is wired through:
- Config parsing:
node.leaf_onlyinfips.yaml - Node constructor:
Node::leaf_only() - Bloom filter support: upstream peer includes leaf identity via
add_leaf_dependent() - Status reporting: visible in
fipsctl show_nodeandfipstopdashboard
The design docs mark it as "under development" — the config flag and data structures are in place, but the full behavioral changes (suppressing tree participation, simplified routing) may not all be active yet. Even without leaf-only mode fully enabled, a standard FIPS node with 2-3 peers runs comfortably on the Pi Zero 2W's hardware.
Monitoring
The Pi can run fipstop (the TUI dashboard) over SSH for live monitoring:
ssh pi@raspberrypi
fipstop
Or use fipsctl for scriptable status checks:
fipsctl show_node # Node identity and state
fipsctl show_peers # Connected peers
fipsctl show_links # Active transport links
fipsctl show_routing # Spanning tree and bloom filter state
fipsctl show_sessions # End-to-end encrypted sessions
Risks & Mitigations
| Risk | Impact | Mitigation |
|---|---|---|
| Compilation on Pi is slow | Dev friction | Cross-compile from x86_64 host |
| 512 MB RAM under heavy transit load | OOM if forwarding for many nodes | Use leaf_only: true + reduced cache sizes |
| WiFi-only networking (no Ethernet) | Single transport, no redundancy | Add USB Ethernet adapter for second transport |
| BLE range limited (~10m) | Short-range only | Use as bridge, not primary transport |
leaf_only mode not fully implemented |
May still participate in routing | Acceptable — Pi has enough resources for light routing |
| SD card wear from logging | Card failure over time | Use journald rate limiting, consider tmpfs for /run/fips |
Future Enhancements
- Headless auto-provisioning: Script that generates identity on first boot and registers with a known upstream peer
- BLE bridge mode: Dedicated configuration for bridging BLE-only devices into the mesh
- Watchdog integration: Use systemd watchdog to auto-restart on hang
- Read-only root filesystem: Protect SD card, write only to
/etc/fips/and/run/fips/