AirPrint on macOS: HP LaserJet P3015dn + MacBook CUPS
Tested on: MacBook Pro, macOS 26.6.2, with an HP LaserJet P3015dn on the LAN. Private IPs are examples; replace them with your own.
Corrections since recording: The video uses a local sudo helper (
cat ~/.macos_sudo | sudo -S) so recording would not stall. The text below uses interactivesudo; do not copy the password-file pattern. The sleep, reboot andipptoolchecks are also newer than the video.
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 a MacBook on the same LAN can print to it.
The fix is macOS CUPS. It speaks the printer’s PCL5 on one side and AirPrint over Bonjour on the other. This page is the why and the exact commands; the videos show the same steps.
The printer is already on the network
The P3015dn (product number CE528A) sits at 192.168.2.83. Its JetDirect
advertises IPP, but the TXT record has no URF and the pdl list has no
image/urf, and it answers IPP 1.1. macOS’s everywhere driver wants IPP 2.0
and fails with:
server-error-version-not-supported
So we do not use IPP Everywhere. We use the standard socket backend on raw port 9100 and a PCL5 PPD. The P3015dn speaks PCL5, and macOS has the generic HP LaserJet Series PCL 4/5 PPD built in.
The bridge: macOS CUPS
The MacBook (192.168.2.37, macOS 26.6.2) owns the queue. The reference queue
is AirPrintLaserJet3015Mac; the device URI is socket://192.168.2.83:9100; the
driver is drv:///sample.drv/laserjet.ppd.
sudo lpadmin -p AirPrintLaserJet3015Mac -E \
-v socket://192.168.2.83:9100 \
-m drv:///sample.drv/laserjet.ppd
lpstat -t
lp -d AirPrintLaserJet3015Mac /usr/share/cups/data/testprint
lpstat -o
Run the sudo commands interactively. The video used a local helper so the
recording would not stall on a password prompt; that helper is a production
detail, not a pattern to copy. Never store a sudo password in a readable file.
The test page is the first cut: if it prints, the macOS queue is real.
Share it over Bonjour, then add the AirPrint TXT
Sharing the queue makes macOS CUPS advertise it, but that was not enough here.
The PCL5 queue’s TXT record lacks URF/image/urf and the airprint keys, so
the iPhone did not list it as an AirPrint printer:
sudo cupsctl --share-printers
sudo cupsctl BrowseLocalProtocols=dnssd
sudo lpadmin -p AirPrintLaserJet3015Mac -o printer-is-shared=true
lpstat -l -p AirPrintLaserJet3015Mac
perl -e "alarm 8; exec @ARGV" dns-sd -B _ipp._tcp local
dns-sd listed the CUPS service as:
AirPrintLaserJet3015Mac @ MacBook Pro
That is the Mac’s computer name; the static bridge deliberately uses the
shorter AirPrintLaserJet3015Mac @ MacBook. The iPhone still ignored the
CUPS instance. The fix is a static dns-sd -R
advertisement with a unique instance name, run as a launchd daemon so it
survives reboot:
/Library/LaunchDaemons/nu.tall.airprint-bridge.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>nu.tall.airprint-bridge</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/dns-sd</string>
<string>-R</string>
<string>AirPrintLaserJet3015Mac @ MacBook</string>
<string>_ipp._tcp,_universal</string>
<string>local</string>
<string>631</string>
<string>txtvers=1</string>
<string>qtotal=1</string>
<string>rp=printers/AirPrintLaserJet3015Mac</string>
<string>ty=HP LaserJet P3015dn</string>
<string>pdl=application/pdf,application/postscript,image/jpeg,image/png,image/pwg-raster,image/urf</string>
<string>URF=V1.4,CP1,W8,PQ3-4-5,RS300,DM1,FN3</string>
<string>Color=F</string>
<string>Duplex=T</string>
<string>airprint=1.8</string>
<string>ipp-features-supported=airprint-1.8</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
</dict>
</plist>
Save the XML block above as airprint-bridge.plist in the current directory,
then install and start it:
sudo install -o root -g wheel -m 644 airprint-bridge.plist \
/Library/LaunchDaemons/nu.tall.airprint-bridge.plist
sudo launchctl bootout system/nu.tall.airprint-bridge 2>/dev/null || true
sudo launchctl bootstrap system \
/Library/LaunchDaemons/nu.tall.airprint-bridge.plist
sudo launchctl list | grep airprint
The instance is deliberately AirPrintLaserJet3015Mac @ MacBook, not the bare
queue name, so it cannot collide with AirPrintLaserJet3015 @ Linux or
master’s CUPS instance. More importantly, the registration type is
_ipp._tcp,_universal: iOS browses the _universal._sub._ipp._tcp subtype
for AirPrint. Without it the printer shows up under “Other printers” but
cannot be selected. The job goes to macOS CUPS, which sends PCL5 to the
JetDirect on port 9100. The static record only advertises the queue; CUPS
still does the printing.
The perl -e "alarm 8; exec @ARGV" wrapper only bounds the dns-sd browse so
a recording does not hang; it is not needed interactively.
Verify the advertised IPP attributes from another machine (install
cups-ipp-utils on Linux if needed):
ipptool -tv ipp://192.168.2.37:631/printers/AirPrintLaserJet3015Mac \
/usr/share/cups/ipptool/get-printer-attributes.test
Check for URF, image/urf, pwg-raster, and duplex support. The static
record advertises them; the queue must actually accept them.
Keep the Mac awake
A sleeping MacBook does not answer Bonjour or IPP, so the iPhone cannot print. For a print server, prevent sleep on power. On current MacBooks the setting is under System Settings → Battery → Options (older macOS: Energy Saver). A version-independent command is:
sudo pmset -c sleep 0
Use caffeinate -s while testing if you do not want to change the setting.
The lid must stay open; a closed MacBook sleeps and cannot answer Bonjour or
IPP.
Print from the iPhone
On the iPhone: Print → choose AirPrintLaserJet3015Mac @ MacBook → Print. The filmed
segment shows the sheet and the paper path. The MacBook logs the job; the
P3015dn prints.
Reboot check
The point of the launchd daemon is that the advertisement survives a reboot. Restart the Mac, then verify:
sudo launchctl list | grep airprint
perl -e "alarm 8; exec @ARGV" dns-sd -B _ipp._tcp local
lp -d AirPrintLaserJet3015Mac /usr/share/cups/data/testprint
Print from the iPhone after the reboot as well. If the queue is gone, check
that the plist is in /Library/LaunchDaemons, that it is owned by root, and
that launchctl print system/nu.tall.airprint-bridge shows a running process.
Troubleshooting
everywhere fails with server-error-version-not-supported. The P3015dn
is IPP 1.1. Use the socket backend and a PCL5 PPD, not IPP Everywhere.
No P3010/3015 PPD in lpinfo -m. macOS 26.6 ships only generic drivers
here. The HP LaserJet Series PCL 4/5 PPD is enough for basic printing.
The queue prints but the iPhone does not see it. Check
cupsctl --share-printers, lpstat -l -p AirPrintLaserJet3015Mac, and
dns-sd -B _ipp._tcp local. Then inspect the TXT record for URF,
image/urf, pdl, and the instance name. The static dns-sd -R record above
is what supplies the AirPrint-specific TXT; the MacBook and iPhone must be on
the same LAN, and guest/client isolation blocks Bonjour.
The job is slow or garbled. The generic PCL5 PPD is a lowest common denominator; check the media size and the driver. The exact P3010 PPD would be better if HP ships one for your macOS version.
Security
The MacBook shares the queue on the LAN; do not expose port 631 or Bonjour to
the internet. Use interactive sudo; never keep a readable password file. The
P3015dn’s embedded web server is old (TLS 1.0/SSLv3); treat the printer as a
trusted LAN device.
The series
The playlist: AirPrint: macOS →
Three short videos: add the P3015dn to macOS CUPS, share it over Bonjour, and print from an iPhone.