Files
fips_playground/plans/fips-raspberry-pi-zero-2w.md
2026-05-02 18:08:59 -04:00

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

  1. Cross-compile from an x86_64 dev machine targeting aarch64-unknown-linux-gnu (Raspberry Pi OS) or aarch64-unknown-linux-musl (static binary)
  2. Deploy via systemd tarball — the simplest packaging path for Raspberry Pi OS
  3. Configure as leaf-only — minimize resource usage by delegating routing to an upstream peer
  4. 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_only in fips.yaml
  • Node constructor: Node::leaf_only()
  • Bloom filter support: upstream peer includes leaf identity via add_leaf_dependent()
  • Status reporting: visible in fipsctl show_node and fipstop dashboard

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/