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.