Cups

CUPS server as a container

One of the first services I needed to enable from my new “containerized” server is printing. We have a printer that could be used from different PCs, devices and members of the family, so CUPS is the perfect way to support this feature.
The printer we plan to share is a Samsung M2675F, a low-cost B&W laser printer.
First of all we need to create a new group named “printer”, so we can use it to control access to the device.

sudo addgroup printer

Alpine uses mdev to recognize devices, I prefer to manage them using udev rules, so I had to swap mdev with udev as device manager for my server. This requires installing udev, disabling mdev at boot, enable udev at boot.
It may sound scary but it’s a matter of few command line commands:

sudo apk add udev
sudo rc-update add udev
sudo rc-update del mdev sysinit

After a reboot dmesg shows that now udev is loaded at boot and will manage device add/removal.
With udev creating a unique symlink for our printer and allowing the printer group to read/write on it is a matter of adding a file named: etc/udev/rules.d/60-samsung-M2675.rules with the following content:

SUBSYSTEM=="usb", ATTRS{idVendor}=="04e8", ATTRS{idProduct}=="3461", GROUP="printer" MODE="0660", SYMLINK+="usbm2675"

To ensure that the rule is applied only to the printer I needed to reference it’s unique vendor/device id pair. You can get those by running lsusb from the console (just run it before and after plugging your device and you could easily spot the right line):

$ lsusb
Bus 001 Device 001: ID 1d6b:0002
Bus 001 Device 003: ID 04e8:3461
Bus 001 Device 002: ID 04d9:0024
Bus 002 Device 001: ID 1d6b:0003

Now we can reboot with the printer plugged in and we will have a device named /dev/usbm2675:

$ ls /dev/usbm2675 -la
lrwxrwxrwx    1 root     root            15 Apr 23 11:54 /dev/usbm2675 -> bus/usb/001/003

the actual device is showing the expected access rights:

$ ls /dev/bus/usb/001/003 -la
crw-rw----    1 root     printer   189,   2 May 24 11:19 /dev/bus/usb/001/003

Now we can create a container to run CUPS. Here’s the Dockerfile:

FROM debian:stretch-slim

ENV LANG en_US.UTF-8

RUN apt-get -y update
RUN apt-get -y install curl cups avahi-daemon

RUN apt-get -y install apt-transport-https
RUN bash -c 'echo "deb https://www.bchemnet.com/suldr/ debian extra" >> /etc/apt/sources.list'
RUN apt-get -y update
RUN apt-get -y --allow-unauthenticated install suld-driver2-1.00.39

# Expose SMB printer sharing
EXPOSE 137/udp 139/tcp 445/tcp

# Expose IPP printer sharing
EXPOSE 631/tcp

# Expose avahi advertisement
EXPOSE 5353/udp

ARG CUPS_PASSWORD

RUN echo root:${CUPS_PASSWORD} | /usr/sbin/chpasswd

COPY ./files /

CMD /run.sh

For this container I used a debian base container because drivers for my Samsung printer are available in .deb package format. I install cups and expose the ports required to share the printer on my home network and to admin the CUPS interface. You may notice that I add some files here. Actually is a single file, named “run.sh”, but I usually keep files I add to my containers in a subfolder named “files” with the same structure as the container filesystem. This are the contents of run.sh:

#!/bin/sh

echo "starting syslog"
/sbin/syslogd
echo "starting avahi"
/usr/sbin/avahi-daemon --daemonize --syslog
echo "starting cups"
/usr/sbin/cupsd -f -c /etc/cups/cupsd.conf

Cups needs some additional demons to be running and run.sh just starts them inside the same container. CUPS configuration will be stored in /etc/cups/cupsd.conf that will be a folder on the host filesystem, allowing us to update the container without losing configuration. I built the container and tagged it as valterminute/cups.

It’s time to start the container.

#!/bin/sh

docker run --privileged -d --restart always -p 631:631 -p 137:137 -p 129:139 -p 445:445 -p 5353 -v $(pwd)/cfg:/etc/cups --name cups --device /dev/usbm2675 --user 0:1001 valterminute/cups

Now you can connect to your server IP on port 631 and configure your printer. You can find documentation on CUPS own website about this and about how you can connect Linux, Windows or MacOS clients to your shared printer.