Diving into NixOS: Printing

I like to dive into problems to learn new skills. Especially when it comes to technology and crafts. This led to a self-made cargo-bike, basic welding skills, but also the basis for my profession: knowledge of embedded systems, programming in C and configuring various software systems.

In this and probably two future blog posts I want to document my last deep-dive into a new-to-me technology:

Nix/NixOS or more specifically getting my printer/scanner combo device to work well with NixOS.

Nix is a functional approach to packaging software, and approaching system configuration. The OS is configured declaratively by writing config files, instead of changing the system in an iterative way. I’ve used both Debian and Arch Linux based distributions before and experienced problems regarding software dependencies and malfunctioning packages now and then with them. Probably NixOS will have some challenges for me as well, but I’m more willing to tackle them. Whatever I do to mitigate those is documented and version controlled in my system configuration and won’t come back to haunt me (ooh, I remember I spent hours debugging and solving this problem, but what the heck did I do?). I’ve had NixOS installed on my personal laptop for 3 months, with barely enough configuration for it to serve my everyday needs, but without wrapping my head around it yet. So it’s about time to develop better skills around the system I’m using.

I’ll use this post to document the chunk that worked quite flawlessly: getting the printer to work. I’ll have a similar post for the scanner as well, which was more challenging to get running well.

I’ve bought a scanner/printer combo device (Canon PIXMA TR4551) with USB and Wi-Fi connectivity about one and a half years ago. It worked OK with my previous Arch Linux setup but needed proprietary software and drivers provided by the vendor.

IPP Everywhere

Before installing those drivers again on NixOS, I tried out using the printer with available free software drivers. The printer supports IPP (InternetPrintingProtocol) for access via the network. CUPS (CommonUnixPrintingService, the standard way to access printers on Linux) has a built-in Generic IPP Everywhere Printer driver. To get this working on NixOS I added the line

services.printing.enable = true;

to my configuration.nix file.

Turns out this driver works OK with my printer, but there are some pitfalls:

  • The driver allows selecting the print quality in DPI from a drop-down with many many options. Selecting a value that’s not well-supported by my printer causes no error message, but weirdly scaled pages
  • A similar issue arises with the color-profile selection
  • The duplex printing function is inversed

Those pitfalls are more or less cosmetic, but would probably be a constant source of failed printouts in the future. I’m human and tend to forget which options I need to choose. I don’t want to be able to select unsupported modes.

It’s nice to have the printer supported kinda-out-of-the-box. I decided to try using Canon’s proprietary drivers as I remember them to work a little better.

Proprietary Driver

The drivers provided by Canon are already available as a package in NixOS! The right keyword to use in the Nix package search is cnijfilter2 which is also part of the filename of the driver archive offered for download at Canon’s website.

I went on extending my configuration.nix file like suggested in the NixOS wiki

services.printing.enable = true;
services.printing.drivers = [ pkgs.cnijfilter2 ];

This led to an error while rebuilding the NixOS system:

$ sudo nixos-rebuild switch
building Nix...
building the system configuration...
error: Package ‘cnijfilter2-5.30’ in /nix/store/ywjr6djpwc1cp4hp52yqwwgyb9vphkql-nixos-19.09.2426.9237a09d8ed/nixos/pkgs/misc/cups/drivers/cnijfilter2/default.nix:117 has an unfree license (‘unfree’), refusing to evaluate.

a) For `nixos-rebuild` you can set
  { nixpkgs.config.allowUnfree = true; }
in configuration.nix to override this.

b) For `nix-env`, `nix-build`, `nix-shell` or any other _Nix_ command you can add
  { allowUnfree = true; }
to ~/.config/nixpkgs/config.nix.

(use '--show-trace' to show detailed location information)

following the hint in the error message and adding

nixpkgs.config.allowUnfree = true;

to configuration.nix solved the problem. The printer works with the new driver and I’m glad it offers fewer options and therefore fewer possibilities for me to screw up, but […]

A Note on Free Software

[…] I don’t like the allowUnfree = true setting. I’m a big fan of free software and use it whenever there’s a viable solution available. Being pragmatic I use proprietary software on my devices as well. The decision should remain on a per-package base though, not to give carte blanche for all unfree packages. I found the relevant section in the nixpkgs manual, but the solution presented there didn’t work. Turns out there’s also a github issue mentioning the documentation being incorrect and offering a working alternative for allowing individual unfree packages.

nixpkgs.config.allowUnfreePredicate = (pkg: builtins.elem
  pkg.pname [
    "cnijfilter2"
  ]
);

Network Printing

The printer offers USB and Wi-Fi as means of communication. Using the cnijfilter2 driver CUPS finds the printer via it’s USB connection, but not via Wi-Fi. Printing via Wi-Fi works after configuring the printer manually (ipp://123.ip.of.printer). It would be nice to have CUPS auto-detect network printers. Without going into detail (I really don’t know a lot about auto-discovery of networked devices and just followed the clues from the NixOS wiki) here’s what I had to add to my configuration.nix for CUPS to automatically find the printer via Wi-Fi:

services.avahi.enable = true;
services.avahi.nssmdns = true;

Note: the printer needs to be in the same IP-subnet as the computer for auto-discovery to work.

Declarative Printer Configuration

I’ve skipped over the part of actually configuring the printer, since I’ve not done it the Nix way yet. Configuring printers declaratively in NixOS seems to be possible and I’ll take a look into it later.

Config File

To summarize, this is the section in my configuration.nix related to printing

{
  #...

  services.printing.enable = true;
  services.printing.drivers = [ pkgs.cnijfilter2 ];

  nixpkgs.config.allowUnfreePredicate = (pkg: builtins.elem
    pkg.pname [
      "cnijfilter2"
    ]
  );

  services.avahi.enable = true;
  services.avahi.nssmdns = true;

  #...
}

Feel free to contact me via mail or mastodon if you’ve got any notes on this post or start a public discussion via this blogs github issue tracker. Like I mentioned above, I’ve got more posts planned on Nix and my printer/scanner, so if this interests you subscribe to the RSS feed to stay tuned!

CC-BY-SA-4.0

Written on April 30, 2020