AirPrint on Linux: HP LaserJet P3015dn + Debian CUPS
Tested on: Debian 13, CUPS 2.4.10 and Avahi 0.8, with an HP LaserJet P3015dn on the LAN. The private IPs are examples; replace them with your own.
Corrections since recording: The video shows the Avahi file,
systemctl reload avahi-daemon,avahi-browse, andlpstat. This text addscupsctl --share-printers,OptionDuplex=True, and theipptoolchecks. Use the text for a fresh setup; the video is the recorded demo.
An HP LaserJet P3015dn is a network printer. It has Ethernet, automatic duplex, and a built-in JetDirect. What it does not have is AirPrint — so the iPhone’s print sheet ignores it, even though every Linux box on the LAN can print to it.
The fix is a small Debian VM running CUPS. It speaks the printer’s raw socket protocol on one side and AirPrint on the other. This page is the why; the video shows the recorded run, and the text below includes the corrections.
The printer is already on the network
The P3015dn (product number CE528A) sits at 192.168.2.83. Its JetDirect
advertises IPP over mDNS:
HP LaserJet P3010 Series [333F03] _ipp._tcp
pdl=application/postscript,application/vnd.hp-PCL,application/vnd.hp-PCLXL
That is a perfectly good network printer service. It is not AirPrint, because
the pdl list has no image/urf and the TXT record has no URF. iOS does
not fall back to PostScript or PCL; it wants the AirPrint raster (URF) or a
driverless IPP printer that speaks PDF/PWG-Raster.
The bridge: CUPS
A Debian 13 VM (airprint-linux-lab, 192.168.2.113, CUPS 2.4.10, Avahi 0.8) talks to the JetDirect on
raw port 9100 and owns the driver. The queue is called
AirPrintLaserJet3015; the driver is the p3010-series PCL3/hpcups PPD
(it sends PCL5 data to the printer).
PPD="hplip:0/ppd/hplip/HP/hp-laserjet_p3010_series-pcl3.ppd"
URI="socket://192.168.2.83:9100"
sudo apt install cups cups-client cups-filters cups-ipp-utils hplip avahi-daemon avahi-utils
sudo lpadmin -p AirPrintLaserJet3015 -E -v "$URI" -m "$PPD" -o OptionDuplex=True
sudo systemctl enable --now cups avahi-daemon
lpstat -t
lp -d AirPrintLaserJet3015 /usr/share/cups/data/testprint
The p3010-series PPD is the correct family driver: HPLIP’s list covers the
P3015 and P3011. hp-laserjet_3015 belongs to the HP LaserJet 3015 All-in-One,
a different printer with fax. That is why lpinfo -m | grep -i 3015 can point
you at the wrong PPD. HPLIP also ships a PostScript version
(hp-laserjet_p3010_series-ps.ppd); test it if the PCL5 path gives trouble.
The test page is the first cut: if it prints, the bridge is real.
The part that actually made the iPhone see it: one small Avahi file
Sharing the CUPS queue is necessary, but it was not enough on this setup. CUPS
2.4.10 advertises the queue over DNS-SD with URF and image/urf:
sudo lpadmin -p AirPrintLaserJet3015 -o printer-is-shared=true
sudo cupsctl --share-printers
avahi-browse -rt _ipp._tcp
avahi-browse showed the queue, yet the iPhone still did not list it. CUPS
2.4.10 already advertises _universal._sub._ipp._tcp and supplies
image/urf through the Debian patch, but its TXT record for this PCL5 queue
did not make the queue selectable here.
The static Avahi service is a second record alongside CUPS’s own
advertisement, not a replacement for it. That is why the instance name must be
unique. It changes several things at once: the instance name, the TXT record, and the
absence of CUPS’s TLS/UUID/air fields. That makes it a working fix, not a
minimal proof of which single key iOS requires. If you want to know whether the
extra TXT keys matter, remove them and retest from the iPhone;
avahi-browse -rt _ipp._tcp shows what is still advertised.
The full file is in The static Avahi service; create it there first, then run:
cat /etc/avahi/services/airprint.service
sudo systemctl reload avahi-daemon
avahi-browse -rt _ipp._tcp
The relevant fields are:
AirPrintLaserJet3015 @ Linux _ipp._tcp
pdl=application/pdf,...,image/urf
URF=V1.4,CP1,W8,PQ3-4-5,RS300,DM1,FN3
airprint=1.8
ipp-features-supported=airprint-1.8
Duplex=T
rp=printers/AirPrintLaserJet3015
URF and image/urf describe what the queue accepts, not what a particular
filter can produce. The static file does not create a second print queue; it
advertises the existing CUPS queue. The iPhone lists that queue, not the
JetDirect.
Verify the IPP side from another Linux host (the cups-ipp-utils package
provides ipptool):
ipptool -tv ipp://192.168.2.113:631/printers/AirPrintLaserJet3015 \
/usr/share/cups/ipptool/get-printer-attributes.test
ipptool reads IPP attributes, not the DNS-SD TXT record. Look for:
sides-supportedcontainingtwo-sided-long-edgeandtwo-sided-short-edge. CUPS adds these only when duplex does not conflict withOptionDuplex; this is the check that confirms the duplex fix.urf-supported(for exampleV1.4,CP1,W8,...).document-format-supportedcontainingimage/urf.
CUPS may answer ipp-features-supported = ipp-everywhere,... without any
airprint-* value. That is normal and does not mean the queue is broken; it is
a different attribute from the DNS-SD TXT keys.
A few TXT fields are worth reading correctly:
Duplex=Tcomes from the static file. The PPD defaultsOptionDuplex=False; thelpadmin ... -o OptionDuplex=Trueabove makes the queue agree with the advertisement. The P3015dn has an automatic duplexer.product=(HP LaserJet p3011 Printer)comes from CUPS’s own advertisement, not from the static file. It is cosmetic: iOS uses the service name and the raster capabilities.- The static file sets
Color=F; the printer is monochrome, so that is correct. A missingColorkey would also mean monochrome. - The Bonjour service instance name is what iOS shows. The queue is still
AirPrintLaserJet3015(rp=printers/AirPrintLaserJet3015), but the static advertisement usesAirPrintLaserJet3015 @ Linuxso it cannot collide with the CUPS instanceAirPrintLaserJet3015 @ master(masteris the VM hostname) or the macOS bridge.
Print from the iPhone
On the iPhone: Print → choose AirPrintLaserJet3015 @ Linux → Print. The job goes to
CUPS over IPP, CUPS rasterizes it with the P3010 driver, and sends PCL to the
JetDirect on port 9100. The printer does the rest.
The P3015dn can print double-sided. OptionDuplex=True makes the queue agree
with the static TXT’s Duplex=T and the URF’s duplex mode; the iPhone offered
double-sided before that setting too. If it produces a duplex page, that is the
proof that the whole chain — not just a one-page demo — is real.
Make it survive a reboot
A print server that only works until the next reboot is not finished.
systemctl is-enabled cups avahi-daemon
ls -l /etc/avahi/services/airprint.service
sudo systemctl restart cups avahi-daemon
lpstat -t
avahi-browse -rt _ipp._tcp
- Reserve the print server’s address (
192.168.2.113) and the printer’s (192.168.2.83) in DHCP, or configure them statically. - Enable
cupsandavahi-daemon. - Back up
/etc/cups(cupsd.conf, printers.conf, ppd/) and/etc/avahi/services/airprint.service. The Avahi file is what keeps the iPhone-visible AirPrint keys after a restart. - Reboot, reconnect, and print again from the iPhone.
Troubleshooting
The queue appears, but the job fails. Check the CUPS error log and the
queue state (lpstat -l -p AirPrintLaserJet3015, lpstat -o). A wrong PPD,
a missing filter, or a URF that promises something the driver cannot deliver
will show up here. The printer’s own JetDirect service is not the queue; make
sure the iPhone selected the CUPS queue.
The queue does not appear. avahi-browse -rt _ipp._tcp on the server
tells you whether CUPS advertises it at all. Check that the queue is shared
and that cupsctl shows _share_printers=1 and BrowseLocalProtocols=dnssd.
Then check the network: mDNS does not cross VLANs or client isolation without
a reflector, and UDP 5353 plus TCP 631 must be allowed on the LAN.
The printer is visible but the job is slow or garbled. The P3010-series PPD is generic; it lists more trays than the P3015dn has. Check the driver choice and the media size. The exact 3015 PPD is an alternative if the generic one misbehaves.
hpfax errors in the log. The P3015dn has no fax; the hplip fax plugin
logs an error at startup. It is unrelated to printing.
The JetDirect web UI will not open in a modern browser. The embedded server is old (TLS 1.0/SSLv3). That is another reason to leave it alone and let CUPS do the modern protocol work.
Security
CUPS on a LAN is fine; CUPS on the internet is not. Do not forward port 631.
cupsctl --share-printers writes Allow @LOCAL; do not add
--remote-any (CUPS documents that as allowing internet clients). Verify
cupsd.conf and keep the firewall scoped to the LAN. The /admin UI already
requires an authenticated @SYSTEM user. cups-browsed is not needed for this
queue; if it is installed for another printer, keep it patched and do not
expose it.
The JetDirect’s old TLS is a good reminder: the printer is a trusted LAN device, not an internet-facing one.
The static Avahi service
This is the file that worked on the lab VM. Put it in
/etc/avahi/services/airprint.service, reload avahi-daemon, and verify with
avahi-browse -rt _ipp._tcp. The service name is deliberately
AirPrintLaserJet3015 @ Linux: the queue is still AirPrintLaserJet3015, but
a unique instance name avoids colliding with another host’s CUPS or bridge
advertisement.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name>AirPrintLaserJet3015 @ Linux</name>
<service>
<type>_ipp._tcp</type>
<subtype>_universal._sub._ipp._tcp</subtype>
<port>631</port>
<txt-record>txtvers=1</txt-record>
<txt-record>qtotal=1</txt-record>
<txt-record>rp=printers/AirPrintLaserJet3015</txt-record>
<txt-record>ty=HP LaserJet P3015dn</txt-record>
<txt-record>pdl=application/pdf,application/postscript,image/jpeg,image/png,image/pwg-raster,image/urf</txt-record>
<txt-record>URF=V1.4,CP1,W8,PQ3-4-5,RS300,DM1,FN3</txt-record>
<txt-record>Color=F</txt-record>
<txt-record>Duplex=T</txt-record>
<txt-record>airprint=1.8</txt-record>
<txt-record>ipp-features-supported=airprint-1.8</txt-record>
</service>
</service-group>
The pdl list has to include image/urf. URF describes the raster formats
the queue accepts; it is not a promise about what a particular CUPS filter can
produce. If you use another queue name, change rp and the service name to
match; iOS prints to the CUPS queue named in rp.
The series
The playlist: AirPrint: Linux →
Four short videos: add the P3015dn to CUPS, make it AirPrint-capable, print from the iPhone, and keep it working after a reboot.