Small FastAPI app for generating label PDFs and sending them to a Brother label printer through CUPS.
It may have gotten a little out of hand.
- Linux
- CUPS running locally
- A configured printer queue
- Required CUPS commands available in
PATHor at their system locations:lplpadminlpstatlpoptions
macOS is useful for local development, but the deployed target is still Linux.
Install the Homebrew system dependency first:
brew install pygobject3Then install Python dependencies and start the app:
uv sync
uv run uvicorn printpage:app --host 0.0.0.0 --port 8000Install dependencies with uv, then run the app with Uvicorn:
uv run uvicorn printpage:app --host 0.0.0.0 --port 8000Build and run the local container with mise:
mise run run_containerOr run the equivalent Docker commands directly:
docker build -t printpage:local .
docker run --rm -it -p 8000:8000 printpage:localThis container is aimed at local app startup and PDF preview. Real printer administration still depends on CUPS access and sudo /usr/sbin/lpadmin in the runtime environment.
The Docker image now also starts a local CUPS daemon and seeds a file-backed fake Brother_QL700 queue for integration testing. Print jobs written inside the container are sent to /tmp/printpage-jobs/label-output.pdf by default.
The app is designed to manage a local CUPS printer queue.
- Configuration reads use
lpstatandlpoptions. - Print submission uses
lp. - Configuration apply uses
sudo /usr/sbin/lpadmin. - The app assumes these commands can run non-interactively.
That means the deployed service user must have passwordless sudo for the required administrative command instead of prompting for a password at request time.
Example lpadmin command shape used for Brother label settings:
sudo lpadmin -p Brother_QL700 \
-o PageSize=62x29 \
-o media=62x29 \
-o BrCutLabel=1 \
-o BrCutAtEnd=ONThe intended setup is a narrowly scoped sudoers rule for lpadmin, not blanket sudo access.
Example:
printpage ALL=(root) NOPASSWD: /usr/sbin/lpadmin
Replace printpage with the actual service user account that runs the app.
Humans setting up the host need this because the web app queries printer state directly and applies printer defaults through CUPS from HTTP requests. Without passwordless sudo, config updates would block on an interactive password prompt and fail.