# Printserver A containerized CUPS print server that shares a **Brother HL-4150CDN** network printer over IPP and advertises it via AirPrint (mDNS/DNS-SD). It prints by sending **PostScript (BR-Script3)** straight to the printer, so no vendor driver and no 32-bit libraries run in the container. The container bundles: - CUPS (IPP + web admin on port 631) with cups-filters for format conversion - Avahi / DNS-SD for AirPrint discovery (UDP 5353) - Brother's official HL-4150CDN **BR-Script3 PPD** for device options ## How it works The HL-4150CDN emulates PCL6 and BR-Script3 (PostScript 3), and accepts PostScript over raw AppSocket (port 9100). CUPS converts whatever a client sends into PostScript and the BR-Script3 PPD turns the selected queue options into PostScript `setpagedevice` instructions: ``` macOS / iOS / Windows / Linux container printer ┌─────────────────┐ IPP/AirPrint ┌──────────────────────────┐ raw ┌────────────┐ │ AirPrint (URF) │ ───────────────▶ │ CUPS │ ──────▶ │ HL-4150CDN │ │ PDF / PostScript│ │ URF/PWG/PDF → PostScript│ :9100 │ BR-Script3 │ └─────────────────┘ │ pstops → setpagedevice │ └────────────┘ └──────────────────────────┘ ``` For example, `Duplex=DuplexNoTumble BRPrintQuality=Color InputSlot=Tray2` becomes: ```postscript <>setpagedevice <>setpagedevice <> setpagedevice ``` ## Layout | Path | Purpose | | --- | --- | | `Containerfile` | Image definition (Debian base, CUPS + cups-filters + Avahi, BR-Script3 PPD) | | `cupsd.conf` | Container CUPS configuration (listen on all interfaces, share printers) | | `entrypoint.sh` | Starts D-Bus, Avahi and CUPS, then registers the printer queue | | `assets/Brother HL-4150CDN/ppd/` | Official BR-Script3 PPD used for the queue | | `assets/Brother HL-4150CDN/Windows/` | Vendor Windows driver the PPD was extracted from | ## Prerequisites - Podman (or a compatible builder such as Docker/Buildah) - The printer reachable on the network, with a known IP address or hostname ## Build Run from the repository root: ```sh podman build -t printserver:latest . ``` The image is architecture-independent (no i386 or other 32-bit binaries), so it builds natively on x86_64 and arm64 hosts alike. ## Run mDNS does not work through a normal container network, so use **host networking**: ```sh podman run -d --name printserver \ --network host \ -e PRINTER_IP=192.168.100.7 \ -e PRINTER_NAME=HL-4150CDN \ printserver:latest ``` ### Environment variables | Variable | Default | Description | | --- | --- | --- | | `PRINTER_IP` | *(empty)* | IP address / host name of the network printer. A device URI is derived from it (see `PRINTER_PROTOCOL`). | | `PRINTER_URI` | *(empty)* | Full device URI. Overrides `PRINTER_IP` when set. | | `PRINTER_PROTOCOL` | `socket` | Protocol used with `PRINTER_IP`: `socket`, `lpd` or `ipp`. | | `PRINTER_NAME` | `HL4150CDN` | CUPS queue name. Also used as the name advertised via AirPrint/DNS-SD. | | `PRINTER_DESCRIPTION` | *(empty)* | CUPS printer description (`lpadmin -D`), shown in the CUPS web UI. | | `PPD_FILE` | `/usr/share/cups/model/BR4150_2.PPD` | PPD used for the queue. | No queue is created when neither `PRINTER_IP` nor `PRINTER_URI` is set. ### Choosing the connection The HL-4150CDN accepts PostScript directly, so the default is raw AppSocket. Set `PRINTER_IP` and let the entrypoint build the URI: | `PRINTER_PROTOCOL` | Resulting URI | | --- | --- | | `socket` (default) | `socket://:9100` — raw AppSocket/JetDirect | | `lpd` | `lpd:///binary_p1` — LPR/LPD | | `ipp` | `ipp:///ipp/print` | For example, a printer at `192.168.100.7`: ```sh -e PRINTER_IP=192.168.100.7 ``` Or specify the URI explicitly for full control: ```sh -e PRINTER_URI=socket://192.168.100.7:9100 ``` ### Advertised name `PRINTER_NAME` is used as the CUPS queue name and as the name clients see in AirPrint discovery. To show a descriptive label in the CUPS web interface, set `PRINTER_DESCRIPTION` (this does not change the advertised name): ```sh -e PRINTER_NAME=HL4150CDN -e PRINTER_DESCRIPTION="Brother HL-4150CDN (Office)" ``` ## Printing options The BR-Script3 PPD exposes the HL-4150CDN's hardware options. Common ones: | Option | PPD keyword | Values | | --- | --- | --- | | Paper source | `InputSlot` | `AutoSelect`, `Tray1`, `Tray2`, `MPTray` | | Two-sided printing | `Duplex` | `None`, `DuplexNoTumble` (long edge), `DuplexTumble` (short edge) | | Colour / mono | `BRPrintQuality` | `Auto`, `Color`, `Black` | | Colour mode | `BRColorMode` | `Normal`, `Vivid`, `None` | | Media type | `BRMediaType` | `Plain`, `Thin`, `Thick`, `Recycled`, `Glossy`, `Label`, envelopes, … | | Print quality | `CAPT` | `Fine` (600×600), `SuperFine` (2400 dpi class) | | Toner save | `TonerSaveMode` | `True`, `False` | | Secure print | `BRJobHold` | `None`, `Private` (+ `BRJobPIN`) | They can be selected per job, e.g.: ```sh podman exec printserver lp -d HL4150CDN \ -o Duplex=DuplexNoTumble -o BRPrintQuality=Color -o InputSlot=Tray1 report.pdf ``` ## Client support | Platform | Path | Notes | | --- | --- | --- | | macOS | AirPrint / IPP Everywhere | Discovered via mDNS; no driver needed | | iOS / iPadOS | AirPrint | Discovered via mDNS; no driver needed | | Linux | IPP / IPP Everywhere | Native or with the shared PPD | | Windows | IPP or raw 9100 | Install Brother's **BR-Script3** Windows driver, pointed at the printer or the shared queue | Windows uses a client-side Brother driver; the server does not share via SMB. ## Verify Browse the CUPS web interface: ```sh open http://localhost:631/ # printers open http://localhost:631/admin # administration ``` From the host, or inside the container: ```sh podman exec printserver lpstat -t # queues and status podman exec printserver lpstat -v HL4150CDN # device URI podman exec printserver lpoptions -p HL4150CDN -l # available options podman exec printserver avahi-browse -rt _ipp._tcp # mDNS advertisement ``` A print job can be submitted with: ```sh podman exec printserver lp -d HL4150CDN /etc/hostname ``` On macOS/iOS the shared queue should appear in the printer list via AirPrint. ## Notes and limitations - **Host networking is required** for Avahi to send and receive mDNS traffic. `-p 631:631` alone is enough for direct IPP access but not for AirPrint discovery. - **Printer state is not persisted.** The queue is recreated on every start from `PRINTER_URI`. To keep CUPS configuration across container replacement, mount a volume over `/etc/cups`: ```sh -v printserver-cups:/etc/cups ``` - Colour handling is done by the printer's own PostScript RIP. Output may differ slightly from Brother's host-side (rasterising) driver. - The queue advertises AirPrint capabilities (`image/urf`, `image/pwg-raster`, `sides-supported`, `color-supported`). macOS and iOS printing is converted by cups-filters; verify end to end on your network.