Pre-made deployment recipes for different reverse-proxy stacks. Pick the one that matches your setup.
Note: the container images are not published yet — this project is in early development. These compose files describe the intended deployment. They will be functional once the first release lands. Track progress in the project board.
The hub ships as two containers:
ghcr.io/strausmann/label-printer-hub-backend— Python/FastAPI, talks to printers, runs the queueghcr.io/strausmann/label-printer-hub-frontend— Go web server, serves the UI + PWA assets, proxies API calls and SSE to the backend
Both images are versioned together. Pin both with the same HUB_VERSION env var in your .env. Mixing major.minor versions between backend and frontend is unsupported.
Only the frontend is exposed to the network. The backend stays on the internal hub-internal docker network.
| Your setup | Use |
|---|---|
| Just a LAN, no reverse proxy | compose.standalone.yml |
| You already run Traefik | compose.traefik.yml |
| You already run Pangolin | compose.pangolin.yml |
| You already run Caddy | compose.caddy.yml |
| Anything else (nginx, HAProxy, ...) | Start with compose.standalone.yml and add your own front |
Each file is self-contained — copy the one you need plus .env.example.
- Brother printer on your network: PT-Series (PT-E550W/P710BT/P750W) or QL-Series (QL-800/810W/820NWB). USB-only models are out of scope at this stage.
- Printer IP addresses noted. Find them via your DHCP leases, the printer's web UI, or:
nmap -p 9100,161 192.0.2.0/24 --open
- Container runtime: Docker Engine 24+ (or Docker Desktop, Podman with compose plugin).
- For reverse-proxy variants: an existing reverse proxy (Traefik/Caddy/Pangolin) and a domain name with DNS pointing at it.
Copy the example env file and adjust:
cp .env.example .env
$EDITOR .envRequired values:
PRINTERS— comma-separated<slug>:<ip>pairs, e.g.pt750w:192.0.2.10,ql820:192.0.2.11WEBHOOK_API_KEY— random 32-byte string for Spoolman/Grocy webhooks (generate withopenssl rand -hex 32)PRINTERHUB_HOST— your domain (only for reverse-proxy variants), e.g.printerhub.example.com
Optional:
SNIPEIT_URL+SNIPEIT_API_TOKEN— Snipe-IT integrationGROCY_URL+GROCY_API_KEY— Grocy integrationSPOOLMAN_URL— Spoolman integration
docker compose -f compose.<variant>.yml up -dThen open https://<your-host>/ (or http://<host-ip>:8080 for standalone) in a browser.
Before hitting "Print", confirm the hub can talk to the printer. Run on the host that runs the hub:
# TCP/9100 (raster print)
nc -zv <printer-ip> 9100
# SNMP — should respond with "MFG:Brother;CMD:...;MDL:<model>;CLS:PRINTER;..."
snmpwalk -v 2c -c public <printer-ip> 1.3.6.1.4.1.2435.2.3.9.1.1.7.0If SNMP fails: open the printer's web UI, navigate to Network → Protocols → SNMP, enable SNMPv1/v2c with community public.
After the UI is up:
- Open the URL in Chrome/Safari/Firefox on your phone
- Browser will offer "Add to Home Screen" — accept
- App icon appears on your home screen and behaves like a native app
- Optional: enable browser notifications when prompted (toast on print complete/failed)
- Web UI loads but no printers shown — check
PRINTERSenv var format and that printer IPs are reachable from the container (network namespace). - Print job stuck in
printingstate — usually means the printer never sent the "complete" notification. Check the printer LCD; cover may be open. - SSE/live updates not working through Traefik — make sure the
responseforwarding.flushintervallabel is set (already in the sample). - Webhooks return 401 — check
WEBHOOK_API_KEYmatches between hub.envand Spoolman/Grocy settings.
For more, open a Discussion or check existing issues.
Want to support a model that isn't on the list? See docs/plugin-development.md and open a plugin request.