The queue was still advertised over mDNS while cupsd never bound TCP 631: a rootless Podman container on the host network cannot bind the privileged port. Apple clients then discovered a printer they could not reach and reported a confusing _ipps connection failure. * entrypoint.sh: verify that CUPS accepts connections on 631 after startup and exit with an actionable message otherwise * entrypoint.sh: mark the script executable in the repository * cupsd.conf: drop BrowseRemoteProtocols, which CUPS 2.4 no longer supports and which logs an error on every start * README: add a troubleshooting section for the port-binding failure and the _ipps/TLS certificate requirement, and document the /etc/cups bind-mount caveat plus the CUPS 3 PPD deprecation
This commit is contained in:
1 parent
4c90ff1290
commit
7f26ca4f2f
3 files changed
+121
-4
No files matched your search
@@ -185,15 +185,112 @@ On macOS/iOS the shared queue should appear in the printer list via AirPrint.
|
|||||||
- **Host networking is required** for Avahi to send and receive mDNS traffic.
|
- **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
|
`-p 631:631` alone is enough for direct IPP access but not for AirPrint
|
||||||
discovery.
|
discovery.
|
||||||
- **Printer state is not persisted.** The queue is recreated on every start
|
- **Printer state is not persisted by default.** The queue is recreated on every
|
||||||
from `PRINTER_URI`. To keep CUPS configuration across container replacement,
|
start from `PRINTER_IP`/`PRINTER_URI`, so nothing has to survive a restart. To
|
||||||
mount a volume over `/etc/cups`:
|
keep CUPS state (extra queues, subscriptions) across container replacement,
|
||||||
|
mount a volume over `/etc/cups` — **use a named volume**:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
-v printserver-cups:/etc/cups
|
-v printserver-cups:/etc/cups
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Podman seeds a *new named volume* with the image's `/etc/cups`, so `cupsd.conf`
|
||||||
|
is present. A **bind mount to an empty host directory does not**: it hides the
|
||||||
|
image's configuration, `cupsd` then exits immediately (status 1, silently —
|
||||||
|
its default `ErrorLog` is syslog), the container stops, and the entrypoint's
|
||||||
|
`lpadmin` fails with a misleading
|
||||||
|
`lpadmin: Unable to connect to server: Bad file descriptor`. This is easiest
|
||||||
|
to hit from a quadlet that bind-mounts a share, e.g.
|
||||||
|
`Volume=/nfs/share/print-server/:/etc/cups/:Z`. If you must bind-mount, make
|
||||||
|
sure the directory already contains a `cupsd.conf`; also note that a read-only
|
||||||
|
share, NFS `root_squash` or SELinux relabeling can still prevent `cupsd` from
|
||||||
|
writing its state there. For a named volume in a quadlet, use
|
||||||
|
`Volume=printserver-cups:/etc/cups` (a bare name, no leading `/`).
|
||||||
- Colour handling is done by the printer's own PostScript RIP. Output may differ
|
- Colour handling is done by the printer's own PostScript RIP. Output may differ
|
||||||
slightly from Brother's host-side (rasterising) driver.
|
slightly from Brother's host-side (rasterising) driver.
|
||||||
- The queue advertises AirPrint capabilities (`image/urf`, `image/pwg-raster`,
|
- The queue advertises AirPrint capabilities (`image/urf`, `image/pwg-raster`,
|
||||||
`sides-supported`, `color-supported`). macOS and iOS printing is converted by
|
`sides-supported`, `color-supported`). macOS and iOS printing is converted by
|
||||||
cups-filters; verify end to end on your network.
|
cups-filters; verify end to end on your network.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### The container runs but nothing answers on 631
|
||||||
|
|
||||||
|
The queue can be advertised over mDNS while nothing is actually listening, so
|
||||||
|
clients discover a printer they cannot reach. Check inside the container:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
podman exec printserver curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:631/
|
||||||
|
podman exec printserver tail -20 /var/log/cups/error_log
|
||||||
|
```
|
||||||
|
|
||||||
|
**`Unable to open listen socket for address 0.0.0.0:631 - Permission denied`** —
|
||||||
|
`cupsd` never bound port 631. This is the normal outcome of **rootless Podman
|
||||||
|
with `Network=host`**: port 631 is privileged, and a rootless container does not
|
||||||
|
hold `CAP_NET_BIND_SERVICE` in the host network namespace (adding the capability
|
||||||
|
does not help, because the capability must belong to the *host* user namespace).
|
||||||
|
`cupsd` keeps running on its domain socket, so `lpadmin`/`lpstat` inside the
|
||||||
|
container still work — which makes the failure easy to miss. Fix one of:
|
||||||
|
|
||||||
|
- allow unprivileged binding of port 631 on the host, persistently (needs root):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
echo 'net.ipv4.ip_unprivileged_port_start=631' | sudo tee /etc/sysctl.d/90-unprivileged-ports.conf
|
||||||
|
sudo sysctl --system
|
||||||
|
```
|
||||||
|
|
||||||
|
- run the container as a rootful (system) service rather than a user quadlet;
|
||||||
|
- or serve on an unprivileged port (CUPS advertises the actual port in its SRV
|
||||||
|
record, but be aware some AirPrint clients assume 631).
|
||||||
|
|
||||||
|
On SELinux systems, verify there is no port-labelling denial as well
|
||||||
|
(`sudo ausearch -m avc -ts recent`). Also ensure 631/tcp and 5353/udp are open in
|
||||||
|
the firewall.
|
||||||
|
|
||||||
|
### macOS/iOS sees the printer but reports it cannot connect
|
||||||
|
|
||||||
|
If plain IPP works but the *secure* connection fails, this is the `_ipps`
|
||||||
|
service: macOS prefers `_ipps._tcp`, which CUPS advertises unconditionally
|
||||||
|
(also when no certificate exists). CUPS creates its TLS certificate lazily on
|
||||||
|
the first TLS connection, in `/etc/cups/ssl` — so that directory must be
|
||||||
|
writable. If it is not, CUPS logs
|
||||||
|
`Unable to encrypt connection: Unable to create server credentials` and the
|
||||||
|
secure connection fails while plain IPP keeps working. Use a **writable (named)
|
||||||
|
volume** for `/etc/cups`; see the bind-mount caveat under *Notes and
|
||||||
|
limitations*. After changing anything, remove the printer in macOS and add it
|
||||||
|
again — macOS caches the failed attempt.
|
||||||
|
|
||||||
|
## CUPS 3 and the future of PPDs
|
||||||
|
|
||||||
|
Adding the queue with a PPD makes `lpadmin` print:
|
||||||
|
|
||||||
|
```
|
||||||
|
lpadmin: Printer drivers are deprecated and will stop working in a future version of CUPS.
|
||||||
|
```
|
||||||
|
|
||||||
|
This is an advance notice, not an error. OpenPrinting deprecated PPDs, printer
|
||||||
|
drivers and filter executables during the CUPS 2.x series, and **CUPS 3.x drops
|
||||||
|
them entirely** in favour of an all-IPP architecture (a *local* server for
|
||||||
|
temporary driverless queues plus a *sharing* server for persistent ones, with
|
||||||
|
filtering limited to PDF, PWG Raster, Apple Raster and PCLm). Any queue created
|
||||||
|
with a PPD (`-P`) or a driver model (`-m <driver>`) triggers the message — it is
|
||||||
|
not specific to Brother, and there is no way to keep the PPD and silence it. A
|
||||||
|
raw queue and `-m everywhere` (driverless) do *not* print it.
|
||||||
|
|
||||||
|
The driverless replacement is a **Printer Application**: a PAPPL-based service
|
||||||
|
that emulates a driverless IPP printer and does the format/option conversion on
|
||||||
|
the other side. For a PostScript device like the HL-4150CDN that role is filled
|
||||||
|
by the **PostScript Printer Application** (`ps-printer-app`), which takes over
|
||||||
|
exactly what our BR-Script3 PPD does today — the PPD does not disappear, it just
|
||||||
|
moves out of CUPS and into the printer application.
|
||||||
|
|
||||||
|
Note the HL-4150CDN is itself *not* IPP Everywhere / AirPrint capable (Brother
|
||||||
|
lists it as such), so the plain `-m everywhere` shortcut is not available here.
|
||||||
|
This container instead advertises AirPrint to its *clients* and performs the
|
||||||
|
PostScript conversion itself.
|
||||||
|
|
||||||
|
Nothing needs to change right now: the distro images used here ship CUPS 2.4.x
|
||||||
|
and PPD-based drivers keep working for years. When you eventually move to
|
||||||
|
CUPS 3.x, run `ps-printer-app` (or `legacy-printer-app`) alongside CUPS and
|
||||||
|
create the queue driverlessly against it (`ipp://…`), leaving the PPD inside the
|
||||||
|
printer application.
|
||||||
@@ -18,7 +18,6 @@ Listen /run/cups/cups.sock
|
|||||||
# Advertise shared printers on the local network via mDNS/DNS-SD (Avahi).
|
# Advertise shared printers on the local network via mDNS/DNS-SD (Avahi).
|
||||||
Browsing On
|
Browsing On
|
||||||
BrowseLocalProtocols dnssd
|
BrowseLocalProtocols dnssd
|
||||||
BrowseRemoteProtocols none
|
|
||||||
BrowseWebIF Yes
|
BrowseWebIF Yes
|
||||||
|
|
||||||
# Default authentication type, when authentication is required...
|
# Default authentication type, when authentication is required...
|
||||||
|
|||||||
Regular → Executable
+21
@@ -111,6 +111,27 @@ if lpstat -p "${PRINTER_NAME}" >/dev/null 2>&1; then
|
|||||||
log "queue ${PRINTER_NAME} is shared and set as default"
|
log "queue ${PRINTER_NAME} is shared and set as default"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# --- Verify CUPS is reachable on the network --------------------------------
|
||||||
|
# cupsd also runs with nothing but its domain socket, e.g. when it cannot bind
|
||||||
|
# the privileged port 631 (rootless Podman with host networking). It then still
|
||||||
|
# advertises the queue over mDNS, so clients see a printer they cannot reach.
|
||||||
|
# Detect that and fail loudly instead of reporting a healthy server.
|
||||||
|
if ! curl -fsS --noproxy '*' --max-time 2 -o /dev/null http://127.0.0.1:631/ 2>/dev/null; then
|
||||||
|
log "ERROR: cupsd is not listening on TCP 631 - network clients (AirPrint/IPP) cannot reach this server"
|
||||||
|
if [ -f /var/log/cups/error_log ]; then
|
||||||
|
log " recent CUPS errors:"
|
||||||
|
tail -n 5 /var/log/cups/error_log | sed 's/^/ /'
|
||||||
|
fi
|
||||||
|
log " If the log shows 'Unable to open listen socket for address 0.0.0.0:631 - Permission denied',"
|
||||||
|
log " port 631 is privileged and this rootless container may not bind it on the host network."
|
||||||
|
log " Either allow unprivileged binding of 631 (host, needs root), persistently:"
|
||||||
|
log " echo 'net.ipv4.ip_unprivileged_port_start=631' > /etc/sysctl.d/90-unprivileged-ports.conf"
|
||||||
|
log " sysctl --system"
|
||||||
|
log " or run this container as a rootful (system) service."
|
||||||
|
log " See the Troubleshooting section of the README."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
log "ready: CUPS on 631/tcp, mDNS on 5353/udp"
|
log "ready: CUPS on 631/tcp, mDNS on 5353/udp"
|
||||||
|
|
||||||
# Keep the container running by waiting on cupsd.
|
# Keep the container running by waiting on cupsd.
|
||||||
|
|||||||
Reference in new issue
Block a user