Printing

From NixOS Wiki
Revision as of 15:07, 3 October 2023 by imported>Jiltq (added info + made it clear what config changes do)

IPP everywhere capable printer

Most printers manufactured after 2013 support the IPP Everywhere protocol, i.e. printing without installing drivers. This is notably the case of all WiFi printers marketed as Apple-compatible (list).

To detect these printers, add the following to /etc/nixos/configuration.nix:

{
  ...
  services.printing.enable = true; # enables printing support via the CUPS daemon
  services.avahi.enable = true; # runs the Avahi daemon
  services.avahi.nssmdns = true; # enables the mDNS NSS plug-in
  services.avahi.openFirewall = true; # opens the firewall for UDP port 5353
  ...
}

After running nixos-rebuild switch, detected printers should appear automatically.

Driver-based printing

  1. Add to /etc/nixos/configuration.nix:
    {
      ...
      services.printing.enable = true;
      services.printing.drivers = [ YOUR_DRIVER ];
      ...
    }
    

    where YOUR_DRIVER is the driver package appropriate for your printer. Commonly used driver packages include:

    • pkgs.gutenprint — Drivers for many different printers from many different vendors.
    • pkgs.gutenprintBin — Additional, binary-only drivers for some printers.
    • pkgs.hplip — Drivers for HP printers.
    • pkgs.hplipWithPlugin — Drivers for HP printers, with the proprietary plugin. Use
      NIXPKGS_ALLOW_UNFREE=1 nix-shell -p hplipWithPlugin --run 'sudo -E hp-setup'
      
      to add the printer, regular CUPS UI doesn't seem to work.
    • pkgs.postscript-lexmark — Postscript drivers for Lexmark
    • pkgs.samsung-unified-linux-driver — Proprietary Samsung Drivers
    • pkgs.splix — Drivers for printers supporting SPL (Samsung Printer Language).
    • pkgs.brlaser — Drivers for some Brother printers
    • pkgs.brgenml1lpr and pkgs.brgenml1cupswrapper — Generic drivers for more Brother printers [1]
    • pkgs.cnijfilter2 — Drivers for some Canon Pixma devices (Proprietary driver)
    • Some printers might be supported by built-in CUPS drivers.
    • Search for other printer drivers in the NixOS package directory: the official list of packages is here but does not list unfree packages (which is the case of many printer drivers). To list unfree packages, see The appropriate FAQ entry for installing unfree packages.

    (Add the driver to services.printing.drivers, not environment.systemPackages.)

  2. Rebuild:
    $ sudo nixos-rebuild switch
    
    CUPS will be started automatically.
  3. Navigate to http://localhost:631/ in a web browser to configure printers. Alternatively, some desktop environments may provide GUI interfaces for adding printers, for example system-config-printer.

    You may need to authenticate when you add the printer. Search the web for e.g. “cups add printer” for further information.

With a raw PPD

Provide the PPD imperatively

If no driver is found for your printer, even when services.printing.drivers is correctly populated (see above), you can try to give cups a PPD file.

  • Download the required PPD file, for example from openprinting.org
  • Open the PPD as a text file, and check that it does not mention FHS paths like /usr/bin. If it does, this method is unlikely to work, as the PPD file depends on executables not present on your system. You can certainly install the binaries yourself and point to the new binary, but it is certainly easier to patch the executables in a derivation (see below) to avoid garbage collection of your binaries.
  • add the printer with system-config-printer (for example) and at the 'choose driver' screen choose 'provide PPD file'
Provide the PPD declaratively

You can also declaratively add the PPD as a new driver by creating a simple derivation. You just need to create a derivation that puts the PPD file in $out/share/cups/model/yourfile.ppd (you can also put it in a subfolder like $out/share/cups/model/HP/yourfile.ppd to limit conflicts between ppd having the same name). Note that the name of the file does not change the way cups will list it as the model/manufacturer is written inside the (text) ppd.

As in the imperative method, first check that your file does not contain any reference to binaries outside the store like /bin/ or /usr/. If it does not contain any reference then you should be able to simply do this:

{
  ...
  services.printing.enable = true;
  services.printing.drivers = [
    (writeTextDir "share/cups/model/yourppd.ppd" (builtins.readFile ./yourppd.ppd))
  ];
  ...
}

If your ppd contains links to external binaries, you can instead patch the file using for instance substituteInPlace. For that, create a file, say, myPrinter.nix containing something like:

{ stdenv }:
stdenv.mkDerivation rec {
  name = "myprinter-${version}";
  version = "1.0";

  src = ./.;

  installPhase = ''
    mkdir -p $out/share/cups/model/
    cp myprinter.ppd $out/share/cups/model/
    # If you need to patch the path to files outside the nix store, you can do it this way
    # (if the ppd also comes with executables you may need to also patch the executables)
    substituteInPlace $out/share/cups/model/myprinter.ppd \
      --replace "/usr/yourProgram/" "${yourProgram}/bin/yourProgram"
  '';
}

Of course update the name of the files and adapt the substituteInPlace command to your needs. Then add your driver as:

{
  ...
  services.printing.enable = true;
  services.printing.drivers = [
    (pkgs.callPackage ./myPrinter.nix {})
  ];
  ...
}

Your PPD file should now appear next to the other PPD files installed on your system when you add a new printer.

For debugging purpose, it may be interesting to note that the data folder used by cups (containing the drivers and more) can be obtained by looking in the environment $CUPS_DATADIR (the contents of $out/share/cups/ contained in your drivers are linked in this folder).

Networked printers

In some cases (e.g.: the Brother HL-3170CDW), you don't even need drivers or a PPD file. Simply open up the CUPS dashboard, add a printer at ipp://your-printer-ip, and make sure to select the "IPP Everywhere" driver.

Setting up shared printers

Server

  1. If you want to share a local printer on the network, follow the steps in Basic Configuration, but check “Share This Printer” when adding it to CUPS. If you have already added the printer to CUPS, reconfigure it to make it a shared printer.
  2. You should probably check that printing works locally at this point.
  3. Amend /etc/nixos/configuration.nix:
    {
      ...
    
      # Enable automatic discovery of the printer from other Linux systems with avahi running.
      services.avahi.enable = true;
      services.avahi.publish.enable = true;
      services.avahi.publish.userServices = true;
      services.printing.browsing = true;
      services.printing.listenAddresses = [ "*:631" ]; # Not 100% sure this is needed and you might want to restrict to the local network
      services.printing.allowFrom = [ "all" ]; # this gives access to anyone on the interface you might want to limit it see the official documentation
      services.printing.defaultShared = true; # If you want
    
      networking.firewall.allowedUDPPorts = [ 631 ];
      networking.firewall.allowedTCPPorts = [ 631 ];
    
      ...
    }
    
  4. Rebuild:
    $ sudo nixos-rebuild switch
    

Note: I think I had to check "Share printers connected to this system" and "Allow printing from the internet" at http://192.168.11.9:631/admin but I'm not sure.

Once printer sharing is enabled, it could be additionally advertised in the home network via the Samba protocol, see.

Client (Linux)

If you want to use a printer shared on the network, and if you enabled services.avahi.publish.userServices in the server configuration, enabling printing and avahi on the client should be sufficient for the printer to be detected:

{
  ...
  services.printing.enable = true;
  services.avahi.enable = true;
  # Important to resolve .local domains of printers, otherwise you get an error
  # like  "Impossible to connect to XXX.local: Name or service not known"
  services.avahi.nssmdns = true;
}

If CUPS complains about "Impossible to connect to XXX.local: Name or service not known" even if services.avahi.nssmdns is enabled as shown above, the reason could be that mdns does not work properly with IPv6 in your network. In such a case, switching to mdns4-only setup can help:

{
  ...
  services.avahi.nssmdns = false; # Use the settings from below
  # settings from avahi-daemon.nix where mdns is replaced with mdns4
  system.nssModules = pkgs.lib.optional (!config.services.avahi.nssmdns) pkgs.nssmdns;
  system.nssDatabases.hosts = with pkgs.lib; optionals (!config.services.avahi.nssmdns) (mkMerge [
    (mkBefore [ "mdns4_minimal [NOTFOUND=return]" ]) # before resolve
    (mkAfter [ "mdns4" ]) # after dns
  ]);
}

See this bug report for details.

See also

Troubleshooting

Upgrade Required

Described in: Github issue 23993
Problem
Using the cups web interface, the page tells you "Upgrade Required" and then redirects you to a page that fails to load.

Cause
When you are using http and cups wants authentication it will redirect you to a https version by default.
In order to use https it needs ssl keys. However it is possible that cups fails to generate these keys, and then the page will fail to load.

Solution
Either we can help cups to get ssl keys, or we can tell it to not use https at all.
Generating ssl keys:
First make sure the directory /etc/cups/ssl exists:
sudo mkdir -p /etc/cups/ssl
Try restarting cups and using the web interface again. This might be enough to get it working.
If this didn't help, then check if cups has generated ssl keys in /etc/cups/ssl
Disabling ssl:
Edit your /etc/nixos/configuration.nix and add the following lines:

services.printing.extraConf = ''
    DefaultEncryption Never
  '';

Unable to launch Ghostscript: gs: No such file or directory

Described in: Github issue 20806 and issues 22062
Problem
When printing, cups will report an error: Unable to launch Ghostscript: gs: No such file or directory

Cause
Some drivers use the ghostscript binary.
Cups will look for the binary path in it's config file: cupsd.conf
This file is normally a link. But it can be overwritten, and consequentially become outdated.

Solution
You could try to manually fix the path variable in /var/lib/cups/cupsd.conf
Alternatively you could try to delete the file and run sudo nixos-rebuild switch

File is missing (Gnome 3)

When you add an printer in Gnome (using gnome-control-center printers) you create a profile for your printer.

Problem
But, later you may experience an error like "/nix/store/.../lib/cups/filter/pstospl not available: No such file or directory".

Cause
When you create a printer profile you get a freeze version of cups filter and when cups is updated, because you have upgraded your system, and garbage collected this version is gone.

Solution
Go into the gnome-control-center printers settings, remove the printer and recreate it.

Debugging a broken printer driver

Add to /etc/nixos/configuration.nix

services.printing.logLevel = "debug";

Rebuild

sudo nixos-rebuild switch

Watch the cups logs

journalctl --follow --unit=cups

# or
journalctl --follow --unit=cups | grep -C10 --color=always -i -e 'No such file or directory' -e 'error:'

Start a print job

Now watch the cups logs for errors like No such file or directory