{"id":16541312,"url":"https://github.com/thyrlian/airpdfprinter","last_synced_at":"2026-03-14T11:04:50.477Z","repository":{"id":141702460,"uuid":"257674237","full_name":"thyrlian/AirPdfPrinter","owner":"thyrlian","description":"Virtual PDF AirPrint printer","archived":false,"fork":false,"pushed_at":"2023-01-12T00:46:21.000Z","size":971,"stargazers_count":61,"open_issues_count":1,"forks_count":10,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-18T00:01:33.427Z","etag":null,"topics":["airprint","docker","pdf","printer"],"latest_commit_sha":null,"homepage":null,"language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thyrlian.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-04-21T18:00:00.000Z","updated_at":"2025-02-23T22:18:52.000Z","dependencies_parsed_at":"2024-01-16T20:30:08.627Z","dependency_job_id":"9c968e7b-0ac6-4015-af5e-a2b8ec30bf04","html_url":"https://github.com/thyrlian/AirPdfPrinter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thyrlian%2FAirPdfPrinter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thyrlian%2FAirPdfPrinter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thyrlian%2FAirPdfPrinter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thyrlian%2FAirPdfPrinter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thyrlian","download_url":"https://codeload.github.com/thyrlian/AirPdfPrinter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244772673,"owners_count":20508037,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["airprint","docker","pdf","printer"],"created_at":"2024-10-11T18:54:39.661Z","updated_at":"2026-03-14T11:04:50.465Z","avatar_url":"https://github.com/thyrlian.png","language":"Dockerfile","readme":"# AirPdfPrinter\n\n![headline](assets/design/AirPdfPrinter.png)\n\n[![Docker Hub](https://img.shields.io/badge/Docker%20Hub-info-blue.svg)](https://hub.docker.com/r/thyrlian/air-pdf-printer)\n\nWanna print or save something as a PDF from your iOS device, keeping the actual text rather than just images?  Apple devices don't offer this natively, but don't worry, we've got you covered with a virtual PDF AirPrint printer.  While designed for AirPrint, it also works as a standard IPP printer discoverable by any device on the network.\n\n## Philosophy\n\nTo enable [AirPrint](https://support.apple.com/en-us/HT201311) of a printer, below requirements must be fulfilled, as described [here](https://wiki.debian.org/CUPSAirPrint).\n\n  * The printer must be advertised with **Bonjour broadcasting**.\n\n  * The printer must communicate with the client using **IPP** (Internet Printing Protocol).\n\n## HOWTO\n\n* **Build**\n\n  Because `chmod` option is used for `ADD` instruction, which requires **BuildKit**, make sure it's enabled (please check [this](https://docs.docker.com/build/buildkit/#getting-started) to learn how to enable BuildKit).\n\n  ```bash\n  # Assume you're in this project's root directory, where the Dockerfile is located\n  docker build -t air-pdf-printer .\n\n  # Build with argument, set your own admin password instead of the default one\n  docker build --build-arg ADMIN_PASSWORD=\u003cYourPassword\u003e -t air-pdf-printer .\n\n  # Or directly pull the image from Docker Hub\n  docker pull thyrlian/air-pdf-printer\n  ```\n\n  The default admin username is `root`, and the default admin password is [here](https://github.com/thyrlian/AirPdfPrinter/blob/master/Dockerfile#L29).\n\n* **Run**\n\n  ```bash\n  # Run a container with interactive shell (you'll have to start CUPS print server on your own)\n  docker run --network=host -it -v $(pwd)/cups-pdf:/var/spool/cups-pdf --name air-pdf-printer air-pdf-printer /bin/sh\n\n  # Run a container in the background\n  docker run --network=host -d -v $(pwd)/cups-pdf:/var/spool/cups-pdf --name air-pdf-printer air-pdf-printer\n  ```\n\n* **Notes**\n\n  * **Multi-Arch**: The Alpine image provides [multi-arch](https://github.com/docker-library/official-images#architectures-other-than-amd64) manifests (amd64, arm64v8, arm32v7, etc.).  Combined with `buildx`, you can build this image for different architectures.  Note: `--load` only works with a single platform.  Multi-platform builds require `--push` to a registry to generate a proper multi-arch manifest.\n\n    ```bash\n    # Build for a single platform and load into local Docker\n    docker buildx build --platform linux/arm64 -t air-pdf-printer:arm64 --load .\n\n    # Build for multiple platforms and push to a registry\n    docker buildx build --platform linux/amd64,linux/arm64 -t thyrlian/air-pdf-printer:latest --push .\n\n    # If cross-platform build fails with \"exec format error\", register QEMU emulators first\n    docker run --rm --privileged multiarch/qemu-user-static --reset -p yes\n    ```\n\n  * **Network**: With the option `--network=host` set, the container will use the Docker host network stack.  When using host network mode, it would discard published ports, thus we don't need to publish any port with the `run` command (e.g.: `-p 631:631 -p 5353:5353/udp`).  And in this way, we don't require [dbus](https://www.freedesktop.org/wiki/Software/dbus/) (a simple interprocess messaging system) package in the container.  However, the `dbus` service is still needed on the host machine (to check its status, you can run for example `systemctl status dbus` on Ubuntu), and even it is deactivated, it would be automatically triggered to active when `avahi-daemon` starts running.  For more information about Docker's network, please check [here](https://docs.docker.com/engine/reference/run/#network-settings) and [here](https://docs.docker.com/network/host/).  Please be aware, the host networking driver only works on Linux hosts, and is not supported on Docker Desktop for Mac, Docker Desktop for Windows, as stated [here](https://docs.docker.com/network/network-tutorial-host/#prerequisites).\n\n      * **Port conflict**: in case any required port on the host machine is already in use, Docker will fail to bind the container port to the host port, when this happens, you'll find a line in `/var/log/cups/error_log`: `Unable to open listen socket for address 0.0.0.0:631 - Address already in use`.  To debug and fix it (on the **host** machine):\n\n        ```bash\n        # Check ports in use\n        sudo lsof -i -P -n | grep LISTEN\n        # Check if a specific port is in use on the host machine (e.g. port 631)\n        sudo lsof -i:631\n        \n        # If port 631 is in use, it's highly likely that the CUPS service is running, then check the service status\n        systemctl status cups\n        # Stop the CUPS service\n        systemctl stop cups\n        # Furthermore, you may want to disable the CUPS service\n        systemctl disable cups\n        # It may happen that the CUPS service will be activated again after reboot, because it's required by another service, to check this\n        systemctl --reverse list-dependencies cups.service\n        # To disable the CUPS service, disregard anything else\n        systemctl mask cups\n        ```\n\n  * **Port**: Apple is using UDP port 5353 to find capable services on your network via Bonjour automatically.  Even though mDNS discovery uses the predefined port UDP 5353, application-specific traffic for services like AirPlay may use dynamically selected port numbers.\n\n    Port | TCP or UDP | Service or protocol name | RFC | Service name | Used by\n    --- | --- | --- | --- | --- | ---\n    5353 | UDP | Multicast DNS (MDNS) | 3927 | mdns | Bonjour, AirPlay, Home Sharing, Printer Discovery\n\n* **Output**\n\n  CUPS-PDF output directory are defined under **Path Settings** which is located at `/etc/cups/cups-pdf.conf`.  And the default path usually is: `/var/spool/cups-pdf/${USER}`\n\n* **Troubleshoot**\n\n  * CUPS logs directory: `/var/log/cups/`\n\n  * Start Avahi daemon with verbose debug level: `avahi-daemon --debug`\n\n  * Log streaming: By default, the container runs silently without streaming any logs (to reduce noise and give you full control).  To follow the logs in real time, override the default command:\n\n    * Via docker run\n\n    ```bash\n    docker run --network=host -d -v $(pwd)/cups-pdf:/var/spool/cups-pdf --name air-pdf-printer air-pdf-printer sh -c \"start.sh \u0026\u0026 touch /var/log/cups/cups-pdf-PDF_log \u0026\u0026 tail -f /var/log/cups/error_log /var/log/cups/cups-pdf-PDF_log\"\n    ```\n\n    * Via Docker Compose\n\n    ```yaml\n    command: sh -c \"start.sh \u0026\u0026 touch /var/log/cups/cups-pdf-PDF_log \u0026\u0026 tail -f /var/log/cups/error_log /var/log/cups/cups-pdf-PDF_log\"\n    ```\n\n* **Commands**\n\n  ```bash\n  # Check CUPS and Avahi service status\n  ps aux | grep -E \"cups|avahi\"\n\n  # Start CUPS service\n  cupsd\n\n  # Start Avahi mDNS/DNS-SD daemon\n  avahi-daemon -D\n\n  # Start all printing services (helper script that handles service orchestration)\n  start.sh\n\n  # Stop all printing services\n  stop.sh\n\n  # Shows the server hostname and port.\n  lpstat -H\n\n  # Shows whether the CUPS server is running.\n  lpstat -r\n\n  # Shows all status information.\n  lpstat -t\n\n  # Shows all available destinations on the local network.\n  lpstat -e\n\n  # Shows the current default destination.\n  lpstat -d\n\n  # Display network connections, you need to have net-tools package installed\n  netstat -ltup\n\n  # Browse for all mDNS/DNS-SD services using the Avahi daemon and registered on the LAN\n  avahi-browse -a -t\n\n  # Find internet printing protocol printers\n  ippfind\n  ippfind --remote\n  ```\n\n* **Manage**\n\n  Web Interface: http://[*IpAddressOfYourContainer*]:631/\n\n* **Add Printer**\n\n  * **macOS**: `System Preferences` -\u003e `Printers \u0026 Scanners` -\u003e `Add (+)` -\u003e `IP`\n\n    * **Address**: [*IpAddressOfYourContainer*]\n    * **Protocol**: `Internet Printing Protocol - IPP`\n    * **Queue**: `printers/PDF` (find the info here: http://[*IpAddressOfYourContainer*]:631/printers/)\n    * **Name**: [*YourCall*]\n    * **Use**: `Generic PostScript Printer`\n\n    \u003ca href=\"https://github.com/thyrlian/AirPdfPrinter/blob/master/assets/screenshots/Add%20Printer%20-%20macOS.png\" target=\"_blank\"\u003e\u003cimg src=\"https://github.com/thyrlian/AirPdfPrinter/blob/master/assets/screenshots/Add%20Printer%20-%20macOS.png\" width=\"600\"\u003e\u003c/a\u003e\n\n  * **iOS**\n\n    \u003ca href=\"https://github.com/thyrlian/AirPdfPrinter/blob/master/assets/screenshots/Add%20Printer%20-%20iOS%20-%201.png\" target=\"_blank\"\u003e\u003cimg src=\"https://github.com/thyrlian/AirPdfPrinter/blob/master/assets/screenshots/Add%20Printer%20-%20iOS%20-%201.png\" width=\"250\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/thyrlian/AirPdfPrinter/blob/master/assets/screenshots/Add%20Printer%20-%20iOS%20-%202.png\" target=\"_blank\"\u003e\u003cimg src=\"https://github.com/thyrlian/AirPdfPrinter/blob/master/assets/screenshots/Add%20Printer%20-%20iOS%20-%202.png\" width=\"250\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/thyrlian/AirPdfPrinter/blob/master/assets/screenshots/Add%20Printer%20-%20iOS%20-%203.png\" target=\"_blank\"\u003e\u003cimg src=\"https://github.com/thyrlian/AirPdfPrinter/blob/master/assets/screenshots/Add%20Printer%20-%20iOS%20-%203.png\" width=\"250\"\u003e\u003c/a\u003e\n\n## License\n\nCopyright (c) 2020-2026 Jing Li.  It is released under the [Apache License](http://www.apache.org/licenses/).  See the [LICENSE](https://raw.githubusercontent.com/thyrlian/AirPdfPrinter/master/LICENSE) file for details.\n\n## Attribution\n\nThe [AirPrint-PDF.service](https://github.com/thyrlian/AirPdfPrinter/blob/master/AirPrint-PDF.service) static service XML file for Avahi is created via [airprint-generate](https://github.com/tjfontaine/airprint-generate) script.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthyrlian%2Fairpdfprinter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthyrlian%2Fairpdfprinter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthyrlian%2Fairpdfprinter/lists"}