Add print server for label printer to have it easily usable via SSH
Add and configure a print server for the Brother P-touch QL 500 label printer, so that it can be easily used via SSH. Do the following to make that work: - Configure the print server host. - Package printer-driver-ptouch to have a working driver for the label printer. - Configure CUPS. - Add a script "forcecommand-lpr-wrapper", which works together with the ForceCommand sshd_config option and wraps lpr to provide an easy interface to use the Brother QL 500 label printer via SSH. - Add a print user and configure SSH to have the "forcecommand-lpr-wrapper" script accessible without a password using the print user via SSH.
This commit is contained in:
parent
6a0218c132
commit
c97f169b77
7
config/hosts/ptouch-print-server/configuration.nix
Normal file
7
config/hosts/ptouch-print-server/configuration.nix
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
networking.hostName = "ptouch-print-server";
|
||||||
|
|
||||||
|
system.stateVersion = "23.11";
|
||||||
|
}
|
9
config/hosts/ptouch-print-server/default.nix
Normal file
9
config/hosts/ptouch-print-server/default.nix
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./configuration.nix
|
||||||
|
./networking.nix
|
||||||
|
./printing.nix
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# A script for usage with the ForceCommand sshd_config option.
|
||||||
|
# It calls lpr with some standard arguments, but also parses
|
||||||
|
# SSH_ORIGINAL_COMMAND to potentially provide a different set of arguments to
|
||||||
|
# lpr.
|
||||||
|
#
|
||||||
|
# This wrapper is written for interacting with the Brother QL 500 label printer.
|
||||||
|
#
|
||||||
|
# The following options can be provided as an SSH command and this script will
|
||||||
|
# then pass them to the lpr call: <MediaType> <PageSize>
|
||||||
|
# - MediaType can be one of:
|
||||||
|
# - Labels
|
||||||
|
# - Tape (this is the default)
|
||||||
|
# - PageSize can be one of:
|
||||||
|
# - 12mm
|
||||||
|
# - 12mm-circular
|
||||||
|
# - 17x54mm
|
||||||
|
# - 17x87mm
|
||||||
|
# - 23x23mm
|
||||||
|
# - 24mm-circular
|
||||||
|
# - 29mm
|
||||||
|
# - 29x90mm
|
||||||
|
# - 38mm
|
||||||
|
# - 38x90mm
|
||||||
|
# - 50mm
|
||||||
|
# - 54mm
|
||||||
|
# - 58mm-circular
|
||||||
|
# - 62mm
|
||||||
|
# - 62x29mm
|
||||||
|
# - 62x100mm
|
||||||
|
# - Custom.WIDTHxHEIGHT (with WIDTH and HEIGHT needing to be either one to
|
||||||
|
# three digits)
|
||||||
|
# - label-wide (this being a convenience alias for Custom.62x35mm and it also
|
||||||
|
# being the default)
|
||||||
|
# - label-item (this being a convenience alias for 38x90mm)
|
||||||
|
#
|
||||||
|
# So using these options in a complete setup would look like this for example:
|
||||||
|
# cat label-item.pdf | ssh print@ptouch-print-server.z9.ccchh.net labels label-item
|
||||||
|
# This being equivalent to:
|
||||||
|
# cat label-item.pdf | ssh print@ptouch-print-server.z9.ccchh.net Labels 38x90mm
|
||||||
|
#
|
||||||
|
# The options are case-insensitive.
|
||||||
|
#
|
||||||
|
# The options are derived from: lpoptions -p Brother-QL-500 -l
|
||||||
|
|
||||||
|
import os, re, subprocess
|
||||||
|
|
||||||
|
mediaType = "Tape"
|
||||||
|
pageSize = "Custom.62x35mm"
|
||||||
|
|
||||||
|
def parseGivenOptions():
|
||||||
|
givenOptionsString = os.environ["SSH_ORIGINAL_COMMAND"]
|
||||||
|
givenOptionsIterator = iter(givenOptionsString.split(" "))
|
||||||
|
|
||||||
|
givenMediaType = next(givenOptionsIterator, "")
|
||||||
|
givenPageSize = next(givenOptionsIterator, "")
|
||||||
|
|
||||||
|
global mediaType
|
||||||
|
if givenMediaType.lower() == "labels":
|
||||||
|
mediaType = "Labels"
|
||||||
|
elif givenMediaType.lower() == "tape":
|
||||||
|
mediaType = "Tape"
|
||||||
|
|
||||||
|
global pageSize
|
||||||
|
pageSizeRegex = re.compile(r"^((12mm(-circular)?)|(24mm-circular)|(58mm-circular)|(((17x(54|87))|(23x23)|((29|38)(x90)?)|(62x(29|100))|50|54|62)mm))$", re.ASCII | re.IGNORECASE)
|
||||||
|
pageSizeMatch = pageSizeRegex.match(givenPageSize)
|
||||||
|
pageSizeCustomRegex = re.compile(r"^custom\.(\d{1,3})x(\d{1,3})$", re.ASCII | re.IGNORECASE)
|
||||||
|
pageSizeCustomMatch = pageSizeCustomRegex.match(givenPageSize)
|
||||||
|
if givenPageSize.lower() == "label-wide":
|
||||||
|
pageSize = "Custom.62x35mm"
|
||||||
|
elif givenPageSize.lower() == "label-item":
|
||||||
|
pageSize = "38x90mm"
|
||||||
|
elif pageSizeMatch:
|
||||||
|
pageSize = givenPageSize.lower()
|
||||||
|
elif pageSizeCustomMatch:
|
||||||
|
width = pageSizeCustomMatch.group(1)
|
||||||
|
height = pageSizeCustomMatch.group(2)
|
||||||
|
pageSize = "Custom.{}x{}".format(width, height)
|
||||||
|
|
||||||
|
if "SSH_ORIGINAL_COMMAND" in os.environ:
|
||||||
|
parseGivenOptions()
|
||||||
|
|
||||||
|
subprocess.run(["lpr", "-P", "Brother-QL-500", "-o", "MediaType={}".format(mediaType), "-o", "PageSize={}".format(pageSize)])
|
|
@ -0,0 +1,7 @@
|
||||||
|
from distutils.core import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name = "forcecommand-lpr-wrapper",
|
||||||
|
version = "0.0.1",
|
||||||
|
scripts = ["./forcecommand-lpr-wrapper.py"]
|
||||||
|
)
|
23
config/hosts/ptouch-print-server/networking.nix
Normal file
23
config/hosts/ptouch-print-server/networking.nix
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
networking = {
|
||||||
|
interfaces.net0 = {
|
||||||
|
ipv4.addresses = [
|
||||||
|
{
|
||||||
|
address = "10.31.208.13";
|
||||||
|
prefixLength = 25;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
defaultGateway = "10.31.208.1";
|
||||||
|
nameservers = [
|
||||||
|
"10.31.208.1"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.network.links."10-net0" = {
|
||||||
|
matchConfig.MACAddress = "BC:24:11:F2:CF:8F";
|
||||||
|
linkConfig.Name = "net0";
|
||||||
|
};
|
||||||
|
}
|
104
config/hosts/ptouch-print-server/printing.nix
Normal file
104
config/hosts/ptouch-print-server/printing.nix
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
# Sources for this configuration:
|
||||||
|
# - https://nixos.wiki/wiki/Printing
|
||||||
|
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
# https://github.com/philpem/printer-driver-ptouch
|
||||||
|
printer-driver-ptouch = pkgs.stdenv.mkDerivation rec {
|
||||||
|
pname = "printer-driver-ptouch";
|
||||||
|
version = "1.7";
|
||||||
|
|
||||||
|
src = pkgs.fetchgit {
|
||||||
|
url = "https://github.com/philpem/printer-driver-ptouch";
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-3ZotSHn7lERp53hAzx47Ct/k565rEoensCcltwX/Xls=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.autoreconfHook
|
||||||
|
pkgs.perl
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.cups
|
||||||
|
pkgs.libpng
|
||||||
|
pkgs.perlPackages.XMLLibXML
|
||||||
|
pkgs.foomatic-db-engine
|
||||||
|
];
|
||||||
|
|
||||||
|
patches = [
|
||||||
|
# Add this patch to have the package actually build sucessfully.
|
||||||
|
# https://github.com/philpem/printer-driver-ptouch/pull/35
|
||||||
|
(pkgs.fetchpatch {
|
||||||
|
name = "fix-brother-ql-600.xml.patch";
|
||||||
|
url = "https://patch-diff.githubusercontent.com/raw/philpem/printer-driver-ptouch/pull/35.patch";
|
||||||
|
hash = "sha256-y5bHKFeRXx8Wdl1++l4QNGgiY41LY5uzrRdOlaZyF9I=";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
# Used the following as a reference on how to generate the ppd files.
|
||||||
|
# https://salsa.debian.org/printing-team/ptouch-driver/-/blob/4ba5d2c490ea1230374aa4b0bf711bf77f1ab0c7/debian/rules#L34
|
||||||
|
postInstall = ''
|
||||||
|
mkdir -p $out/share/cups
|
||||||
|
FOOMATICDB=$out/share/foomatic ${pkgs.foomatic-db-engine}/bin/foomatic-compiledb -t ppd -d $out/share/cups/model
|
||||||
|
rm -r $out/share/foomatic
|
||||||
|
'';
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
|
patchShebangs --build foomaticalize
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
forcecommand-lpr-wrapper = pkgs.python3Packages.buildPythonApplication {
|
||||||
|
name = "forcecommand-lpr-wrapper";
|
||||||
|
src = ./forcecommand-lpr-wrapper;
|
||||||
|
|
||||||
|
propagatedBuildInputs = [
|
||||||
|
pkgs.cups
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.printing = {
|
||||||
|
enable = true;
|
||||||
|
drivers = [ printer-driver-ptouch ];
|
||||||
|
stateless = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
hardware.printers = {
|
||||||
|
ensurePrinters = [
|
||||||
|
{
|
||||||
|
name = "Brother-QL-500";
|
||||||
|
location = "Z9";
|
||||||
|
deviceUri = "usb://Brother/QL-500?serial=J8Z249208";
|
||||||
|
model = "Brother-QL-500-ptouch-ql.ppd";
|
||||||
|
ppdOptions = {
|
||||||
|
PageSize = "Custom.62x35mm";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ensureDefaultPrinter = "Brother-QL-500";
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.print = {
|
||||||
|
isNormalUser = true;
|
||||||
|
description = "User for printing via SSH.";
|
||||||
|
password = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
# PasswordAuthentication being set to false just puts "auth required
|
||||||
|
# pam_deny.so # deny (order 12400)" for pam.d/sshd, so enable
|
||||||
|
# PasswordAuthentication to have it not do that.
|
||||||
|
services.openssh.settings.PasswordAuthentication = lib.mkForce true;
|
||||||
|
# The following doesn't need to be set in order for empty passwords to work
|
||||||
|
# apparently:
|
||||||
|
# security.pam.services.sshd.allowNullPassword = true;
|
||||||
|
services.openssh.extraConfig = ''
|
||||||
|
Match User print
|
||||||
|
PubkeyAuthentication no
|
||||||
|
AuthenticationMethods none
|
||||||
|
PermitEmptyPasswords yes
|
||||||
|
ForceCommand ${forcecommand-lpr-wrapper}/bin/forcecommand-lpr-wrapper.py
|
||||||
|
Match User *
|
||||||
|
'';
|
||||||
|
}
|
14
flake.nix
14
flake.nix
|
@ -197,6 +197,20 @@
|
||||||
./config/hosts/forgejo-actions-runner
|
./config/hosts/forgejo-actions-runner
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ptouch-print-server = {
|
||||||
|
deployment = {
|
||||||
|
targetHost = "ptouch-print-server.z9.ccchh.net";
|
||||||
|
targetPort = 22;
|
||||||
|
targetUser = "colmena-deploy";
|
||||||
|
tags = [ "thinkcccluster" ];
|
||||||
|
};
|
||||||
|
imports = [
|
||||||
|
./config/common
|
||||||
|
./config/proxmox-vm
|
||||||
|
./config/hosts/ptouch-print-server
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
packages.x86_64-linux = {
|
packages.x86_64-linux = {
|
||||||
|
|
Loading…
Reference in a new issue