TrueNAS Print Server: Running CUPS as an App
TrueNAS ships no print service at all. What it takes to run CUPS as a container app, share a USB printer, and why discovery needs host networking.
TrueNAS has no print server. There is no printing entry in the Services list, and CUPS does not appear anywhere in the official TrueNAS apps catalogue, which carries media and file-sharing apps such as Plex and Nextcloud but nothing for printing. The machine is a storage appliance, and printing was never part of that job.
That does not mean it cannot be done. Since the app backend moved to Docker, running CUPS on TrueNAS is a custom-app deployment like any other, and it works well enough for the two cases that actually justify it. It is also the kind of project where most of the difficulty is in three specific places, so it is worth knowing where those are before starting.
First, check whether you need one at all
A print server solves a problem many networks no longer have. Before building anything, work out which situation applies.
| Situation | Do you need CUPS on TrueNAS? |
|---|---|
| Network printer supporting IPP or AirPrint | No. Clients print to it directly. |
| Network printer, drivers only on one machine | Maybe. A shared queue centralises drivers. |
| USB-only printer, no network port | Yes, if you want more than one machine printing to it. |
| Old network printer, no AirPrint, iOS clients | Yes. CUPS can advertise it as an AirPrint queue. |
| Printer already shared from a desktop that is always on | No. You already have a print server. |
Modern printers with IPP Everywhere support are discovered and driven by clients with no server in the middle, on every major operating system. Adding CUPS in that case introduces a queue that can jam, a container that can fail an update, and a dependency on the NAS being up in order to print.
The two cases where it genuinely pays off are a USB-only printer that several machines need, and an older network printer you want to reach from phones and tablets that expect AirPrint.
What the deployment actually consists of
CUPS runs as a single container. Its administration interface listens on port 631. It needs three things to be useful, and each is a decision on the TrueNAS side:
- Persistent configuration. CUPS writes its printer definitions and settings under
/etc/cups, and its spool under/var/spool/cups. If those are not on a dataset, every app update wipes the printer you configured. - Access to the printer. For a network printer, ordinary outbound networking. For a USB printer, the container needs the USB device passed through from the host.
- Discoverability. Clients find print queues by mDNS broadcast. A container behind Docker’s default bridge network cannot broadcast onto the LAN, so nothing finds it.
Getting all three right is the whole project. Each maps onto a specific option in the TrueNAS app installer.
Deploying it via Compose
The guided Custom App form covers image, ports, storage and a fixed set of options. Anything involving device passthrough needs the YAML route, because the form exposes GPU allocation but not arbitrary host devices.
From Apps, open Discover, then the three-dot menu, then Install via YAML. That opens the Add Custom App screen, where the app takes a lowercase alphanumeric name and the Compose content goes into the Custom Config field, beginning at a top-level key such as name:, services: or include:.
The documentation is explicit that this route requires working knowledge of Docker Compose and YAML, and that TrueNAS applies only basic YAML syntax validation without checking the configuration parameters before running it. A file that parses cleanly but names a device that does not exist will save successfully and then fail at container start. Write it in a real editor first; indentation errors pasted into a browser field are the most common way this goes wrong.
The shape of a CUPS service is small:
services:
cups:
image: <cups image>
network_mode: host
volumes:
- /mnt/tank/apps/cups/etc:/etc/cups
- /mnt/tank/apps/cups/spool:/var/spool/cups
devices:
- /dev/bus/usb:/dev/bus/usb
restart: unless-stopped
Every line of that is a decision explained below. Substitute your own pool and dataset paths, and pick a CUPS image whose documentation you have read, because the environment variables that set the admin user and password differ between images.
Storage: use Host Path, not ixVolume
The installer offers four storage types: Host Path, which mounts an existing system path with optional read-only and ACL handling; ixVolume, which auto-creates a dataset on the apps pool; SMB/CIFS Share, which connects a Docker volume to a network share; and Tmpfs, which allocates a RAM-backed directory.
For CUPS, use Host Path against datasets you created and named yourself. The reason is recovery. A printer configuration takes real effort to get right, and it is a small amount of text under /etc/cups. On a named dataset it is covered by whatever snapshot and replication schedule the rest of the pool uses, and it can be found and copied by hand. Inside an ixVolume it sits in the hidden apps area under a generated name.
Create the datasets before installing the app, not during. Dataset layout is easier to get right up front, for the same reasons it is in pool and dataset planning generally.
Tmpfs has one legitimate use here: pointing the spool directory at RAM keeps print jobs, which can be large and are always transient, off the pool entirely. The tradeoff is that a job queued when the system loses power is gone, which for a print queue is usually the correct outcome anyway.
Networking: host mode, or nothing finds the printer
This is where most CUPS-on-TrueNAS attempts stall. The queue works when addressed directly by IP and port, and no client discovers it automatically.
Print queue discovery uses mDNS, which is multicast traffic on the local subnet. A container on Docker’s default bridge network sits behind a NAT boundary that multicast does not cross. The result is a working print server that appears not to exist.
The installer’s networking section allows binding the container to the TrueNAS host network, which disables port mapping for that app. That is the setting to use. In Compose terms it is network_mode: host. With it, CUPS advertises on the LAN and clients find the queue by name.
Host networking has one consequence worth planning for: the container’s ports land directly on the host’s addresses, so CUPS occupies port 631 on the NAS itself. Any other app wanting that port will collide, and the TrueNAS web interface’s own ports are already spoken for.
The alternative for people who prefer isolation is a macvlan network giving the container its own address on the LAN. It achieves the same discovery result and keeps the port off the host, at the cost of a more complex network definition and the usual macvlan quirk that the host cannot talk to the container directly.
USB passthrough, and why the device path matters
A USB printer needs the device visible inside the container. The Compose devices: key handles this, and mapping the whole /dev/bus/usb tree rather than a single device node is the more robust form.
The reason is that USB device nodes are addressed by bus and device number, and the device number changes when the printer is unplugged and replugged, or when the printer is power-cycled and re-enumerates. A container mapped to one specific node loses the printer at that point and needs its definition edited. Mapping the bus tree survives re-enumeration.
Two related cautions. Passing device access to a container is a privilege grant, and the installer’s own guidance is to grant specific Linux capabilities rather than enabling privileged mode, which it describes as giving nearly unrestricted access to the host system. Start with the device mapping alone and add capabilities only if the container logs say something specific is being denied. And USB passthrough is a physical dependency: the printer must be plugged into the NAS, which puts the printer wherever the NAS lives. For many people that alone settles the question in favour of a network printer.
What about sharing the printer over SMB?
Samba itself supports printer sharing. The smb.conf reference documents a [printers] section and the print-related parameters that go with it, and a Samba server configured that way advertises print queues to Windows clients the same way it advertises file shares.
That is not a route to take on TrueNAS. The appliance generates its Samba configuration from its own middleware, and the share types offered in the interface are file shares. A hand-edited smb.conf on an appliance whose configuration is machine-generated is not a persistence path you can rely on across updates, and the SMB share configuration TrueNAS does support is aimed squarely at datasets rather than devices.
If Windows clients need to reach the queue, CUPS handles that itself over IPP, which current Windows versions support natively. That keeps the print configuration inside the container where it is backed up with the rest of the app data.
Troubleshooting the four common failures
| Symptom | Most likely cause |
|---|---|
| Printer configuration gone after an app update | Config was on ixVolume or unmounted; move /etc/cups to a Host Path dataset |
| Queue reachable by IP, invisible to clients | Container not on host networking; mDNS cannot cross the bridge |
| Jobs queue and never print | Container cannot reach the device or the printer’s address; check the CUPS error log first |
| Printer vanishes after a power cycle | USB device node changed; map /dev/bus/usb rather than a single node |
| Admin interface refuses the login | CUPS Listen and access controls default to localhost in many images; the image’s own documentation covers the override |
The CUPS error log is the right first stop for all of these, and the project’s own documentation covers what its log levels mean and where the configuration directives are defined. Most failures at this stage are CUPS configuration questions rather than TrueNAS ones, and they are answered in the CUPS documentation rather than anywhere in the TrueNAS docs.
Keep it on the LAN
CUPS is an administrative web interface with the ability to execute filters on submitted jobs. There is no reason for it to be reachable from outside the network, and the reflexive move of adding a reverse proxy entry for every app should not extend to this one.
Bind it to the LAN, leave it out of any port forwarding, and reach it over the VPN if remote access is genuinely needed. The same reasoning applies to any custom app deployed through the YAML route, which is a deployment path with deliberately less validation than the catalogue apps get.
Where this fits
A print server is a small app with an outsized number of edge cases, and it is a good illustration of what the custom-app route on TrueNAS can and cannot do. The general mechanics behind it, including what changed when the app backend moved off Kubernetes, are covered in moving apps to Docker. If the machine is still on the shopping list, the memory a stack of small apps like this one adds up to is part of hardware sizing, and the TrueNAS sizer takes app count directly as an input.
Sources
Related
TrueNAS Apps: k3s to Docker Migration Guide
See what TrueNAS 24.10 moved automatically from k3s to Docker, what requires a manual rebuild, and how to retry or recover a stalled app migration.
TrueNAS SMB Share Permissions Setup: A Practical ACL Guide
Configure TrueNAS SMB users, groups, share ACLs, and NFSv4 dataset permissions, then verify access and back up the result.
TrueNAS Hardware Sizing: RAM, HBA, NIC and Boot Disk
Size TrueNAS hardware with the current 8 GB base, per-drive RAM rules, IT-mode HBA guidance, boot SSD minimums, and network limits.