Skip to main content

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 agent
  • apps/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​

  1. In the FlowPOS admin panel, navigate to Kitchen Stations or Printers.
  2. Generate a new pairing code.
  3. 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:

EnvironmentapiUrl
Staginghttps://api.staging.flowandgrow.tech
Productionhttps://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.
  • bcrypt native module was not compiled — run pnpm approve-builds and 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_DIR volume holds config.json (encrypted), dedup.json (prevents duplicate prints), and .secret (fallback key). Back up this directory if you reconfigure the Pi.