Print Bridge on Raspberry Pi Zero W
This document covers deploying the apps/print-bridge app natively on a Raspberry Pi Zero W and connecting it to the FlowPOS staging or production backend.
Architecture overview
FlowPOS Backend (Cloud Run)
└── Socket.IO /restaurant namespace
└── Print Bridge (Raspberry Pi Zero W)
└── Thermal Printer (TCP or USB)
The print-bridge is a Node.js Express server that:
- Serves a React configuration UI on port 3456
- Connects to the FlowPOS backend via Socket.IO (WebSocket)
- Receives kitchen print jobs in real-time
- Renders ESC/POS receipts and sends them to the printer
Why not Docker on Pi Zero W
The Pi Zero W uses an ARMv6 CPU. Docker's binaries (written in Go) require ARMv7 instructions — running Docker results in:
Illegal instruction
The solution is to run Node.js natively using the unofficial armv6l builds maintained specifically for the Pi Zero.
Prerequisites
Hardware and software from Raspberry Pi Zero W Setup Guide:
- Pi Zero W with Raspberry Pi OS Lite (32-bit) installed
- SSH access via
ssh luis@flowpi.local - Wi-Fi connected (2.4 GHz)
Step 1 — Install Node.js 20 LTS (ARMv6)
The official Node.js builds do not include ARMv6. Use the unofficial armv6l builds:
NODE_VER=v20.18.0
curl -fsSL "https://unofficial-builds.nodejs.org/download/release/${NODE_VER}/node-${NODE_VER}-linux-armv6l.tar.gz" \
| sudo tar -xz -C /usr/local --strip-components=1
node --version
npm --version
Install pnpm and native build tools:
sudo npm install -g pnpm
sudo apt-get install -y python3 make g++ libvips-dev
libvips-dev allows sharp to use the system library for image processing instead of compiling it from scratch.
Step 2 — Build on your Mac
From the workspace root on your Mac:
pnpm --filter @flowpos-workspace/print-bridge run build
This compiles:
apps/print-bridge/dist/agent/— Node.js CommonJS agentapps/print-bridge/dist/ui/— Vite React SPA
Why build on Mac and not on the Pi
The Vite UI build uses @swc/core which has no pre-built binary for ARMv6. Building must happen on an x86/ARM64 machine.
Step 3 — Copy to the Pi
From the workspace root on your Mac:
rsync -avzR --exclude='node_modules' --exclude='.git' \
./pnpm-workspace.yaml \
./package.json \
./pnpm-lock.yaml \
./apps/print-bridge \
./packages/global \
./packages/receipt-layout \
./packages/receipt-escpos \
luis@flowpi.local:~/print-bridge/
The -R flag preserves the full relative path so the workspace structure is correct on the Pi.
Step 4 — Install production dependencies on the Pi
ssh luis@flowpi.local
cd ~/print-bridge
Remove the husky prepare script (it is a dev dependency and will cause install to fail):
python3 -c "
import json
with open('package.json') as f:
p = json.load(f)
p.setdefault('scripts', {}).pop('prepare', None)
with open('package.json', 'w') as f:
json.dump(p, f, indent=2)
print('prepare script removed')
"
Approve native build scripts (required in pnpm v10+):
pnpm approve-builds
Select bcrypt and sharp when prompted (skip protobufjs — it is optional for Firebase).
Install:
pnpm install --filter @flowpos-workspace/print-bridge... --prod --frozen-lockfile
This compiles bcrypt natively for ARMv6. Expect 5–15 minutes.
Step 5 — Generate a permanent secret
The BRIDGE_SECRET encrypts the config file on disk. It must stay the same across restarts or the config will be unreadable.
openssl rand -hex 32
Save the output in a password manager or Doppler before continuing.
Step 6 — Systemd service
Staging
sudo tee /etc/systemd/system/print-bridge.service > /dev/null << 'EOF'
[Unit]
Description=FlowPOS Print Bridge
After=network-online.target
Wants=network-online.target
[Service]
User=luis
WorkingDirectory=/home/luis/print-bridge/apps/print-bridge
ExecStart=/usr/local/bin/node dist/agent/index.js
Restart=always
RestartSec=5
Environment=FLOWPOS_API_URL=https://api.staging.flowandgrow.tech
Environment=BRIDGE_SECRET=REPLACE_WITH_YOUR_SECRET
Environment=BRIDGE_DATA_DIR=/home/luis/print-bridge-data
[Install]
WantedBy=multi-user.target
EOF
Production
Same as above but set:
Environment=FLOWPOS_API_URL=https://api.flowandgrow.tech
Enable and start:
mkdir -p ~/print-bridge-data
sudo systemctl enable print-bridge
sudo systemctl start print-bridge
sudo systemctl status print-bridge
Step 7 — Access the UI
Open in your browser:
http://flowpi.local:3456
Step 8 — Pair with FlowPOS
- In the FlowPOS admin panel, navigate to Kitchen Stations or Printers.
- Generate a new pairing code.
- Paste the code immediately into the bridge UI at
http://flowpi.local:3456/config.
The pairing code is stored in Redis with a short TTL (~5 minutes). Generate and use it without delay.
Verify the configured API URL
cat ~/print-bridge-data/config.json
The apiUrl field must match the environment where you generated the pairing code:
| Environment | apiUrl |
|---|---|
| Staging | https://api.staging.flowandgrow.tech |
| Production | https://api.flowandgrow.tech |
A staging pairing code will not validate against the production backend.
Useful commands
View live logs
journalctl -u print-bridge -f
Check service status
sudo systemctl status print-bridge
Stop the service
sudo systemctl stop print-bridge
Verify it stopped:
sudo systemctl status print-bridge
Restart after a config change
sudo systemctl restart print-bridge
Test backend connectivity from the Pi
curl -s https://api.staging.flowandgrow.tech/health
curl -s https://api.flowandgrow.tech/health
Updating the app
After a new build on your Mac and rsync:
sudo systemctl stop print-bridge
cd ~/print-bridge
pnpm install --filter @flowpos-workspace/print-bridge... --prod --frozen-lockfile
sudo systemctl start print-bridge
journalctl -u print-bridge -f
Troubleshooting
"Illegal instruction" on any binary
The binary was compiled for ARMv7 or ARM64 and will not run on the Pi Zero W's ARMv6 CPU. Ensure you are using the armv6l Node.js build from unofficial-builds.nodejs.org.
"Pairing failed"
- The pairing code expired — generate a new one and use it within 5 minutes.
- The pairing code is from staging but the bridge points to production (or vice versa). Check
config.json. bcryptnative module was not compiled — runpnpm approve-buildsand reinstall.
"Cannot find module" on startup
The dist/agent/ directory is missing. Run the build on your Mac first:
pnpm --filter @flowpos-workspace/print-bridge run build
Then rsync and reinstall.
UI not loading at http://flowpi.local:3456
Check that the service is running and the port is open:
sudo systemctl status print-bridge
curl http://localhost:3456
pnpm install fails with "husky not found"
Remove the prepare script from the root package.json using the Python snippet in Step 4.
sharp or bcrypt errors at runtime
Run pnpm approve-builds, select both packages, then reinstall and restart the service.
Notes
- The Pi Zero W has 512MB RAM. The print-bridge uses ~80–120MB at idle.
- No swap file is needed when running natively (unlike Docker, which adds significant overhead).
- The
BRIDGE_DATA_DIRvolume holdsconfig.json(encrypted),dedup.json(prevents duplicate prints), and.secret(fallback key). Back up this directory if you reconfigure the Pi.