Windows (MSI)
The MSI is per machine and needs administrator rights. Interactive: double-click, accept, finish; the tray helper starts at the end and again at every logon. Silent, with unattended enrollment:
msiexec /i PrintHook-1.4.0-x64.msi /qn /norestart ^
SERVER=https://api.printhook.io CLIENTKEY=ck-... ^
/l*v %TEMP%\printhook-install.logSERVER and CLIENTKEY enroll before the service starts; the key never appears in the log. TRAY=0 skips the per-user tray auto-start, INSTALLFOLDER changes the location, and WIPEDATA=1 on uninstall also deletes %PROGRAMDATA%\PrintHook. The service is PrintHookAgent.
macOS (.pkg)
The package is universal (Intel and Apple silicon), Developer ID signed with the hardened runtime and notarized, so Gatekeeper opens it without warnings. Double-click, or:
sudo PRINTHOOK_SERVER=https://api.printhook.io PRINTHOOK_CLIENT_KEY=ck-... \
installer -pkg PrintHook-1.4.0.pkg -target /The package installs the LaunchDaemon io.printhook.agent (RunAtLoad, KeepAlive) and the menu bar app /Applications/PrintHook.app. For MDM (Jamf, Kandji, Mosyle), deploy the .pkg as a package policy and pass the two variables through a pre-install script, or run enroll from a post-install script. Uninstall with sudo /Library/PrintHook/uninstall.sh (add --wipe-data to remove the data directory).
Linux (.deb / .rpm)
sudo apt install ./printhook-agent_1.4.0_linux_amd64.deb # Debian, Ubuntu, Raspberry Pi OS 64-bit
sudo dnf install ./printhook-agent_1.4.0_linux_amd64.rpm # Fedora, RHEL, Rocky, Alma
sudo zypper install ./printhook-agent_1.4.0_linux_amd64.rpm # openSUSEThe package creates the printhook system user, installs the unit printhook-agent.service (Restart=always) and enables it at once. Put PRINTHOOK_SERVER and PRINTHOOK_CLIENT_KEY in /etc/printhook/agent.env and the service enrolls itself on first start, or export them for the package-manager run, or enroll afterwards:
sudo printhook-agent enroll --server https://api.printhook.io --client-key ck-... --data-dir /var/lib/printhook
sudo chown -R printhook:printhook /var/lib/printhook/config
sudo systemctl restart printhook-agentFor a remote CUPS server set CUPS_SERVER=host:631 in agent.env. apt remove keeps the data directory; apt purge removes it and the user.
Docker
The image runs the agent with the CUPS backend and contains no CUPS server of its own. Printers must exist on the CUPS server it reaches; network label printers are added there with lpadmin.
docker run -d --name printhook-agent --restart unless-stopped \
-e PRINTHOOK_SERVER=https://api.printhook.io -e PRINTHOOK_CLIENT_KEY=ck-... \
-v printhook-data:/var/lib/printhook \
-v /run/cups/cups.sock:/run/cups/cups.sock \
ghcr.io/printhook/printhook-agent:1.4.0Enrollment
Enrollment ties a computer to an account with an agent-scoped computer key (ck- followed by 44 characters). Whichever path you use, the result is the same config.json.
- Sign in from the tray helper. Enter the console email and password once. The agent exchanges them for a computer key bound to this computer's
install_uuidand stores only the key; the password is never written to configuration, state, logs or diagnostics. Accounts with two-step verification are asked for a code. The account owner receives a "new computer signed in" notice naming the machine. - Paste a computer key created in the console under Computers > Add computer.
- Unattended: pass the server URL and key to the installer, or run
printhook-agent enroll --client-keyas an administrator. This path needs no network at enrollment time; the service validates the key when it first connects.
Claiming a station. Add --station <code> to a sign-in enrollment: the six-character pairing code minted from the station in the console (fifteen minutes, single use), or the station's printed barcode (PHS-…, stable for the life of the station). The computer becomes that bench, and a re-imaged PC re-pairs by scanning the same laminated barcode. A wrong, used or expired code is refused after the password is accepted, so the message tells you which one to fix.
Re-running enroll replaces the key but keeps the install_uuid, so the computer keeps its id in the console. When cloning machine images, enroll after cloning or delete config/install_uuid before capturing, otherwise every clone claims the same computer.
Network and proxies
The agent only makes outbound connections; nothing needs to be opened inbound. Its local control API listens on 127.0.0.1:8895, token-authenticated, for the tray helper.
| Destination | Port | Purpose |
|---|---|---|
api.printhook.io | 443 | Agent gateway (HTTPS and WebSocket, subprotocol printhook.v1), REST fallback, sign-in, release manifests |
| PrintHook content storage hosts | 443 | Presigned downloads of job content above the 64 KB inline limit; uploads of diagnostics bundles |
printhook.io | 443 | Agent update downloads |
Your own content.url hosts | as given | Only when your API calls submit URL jobs; the agent fetches them directly, with Basic or Digest auth if supplied |
Proxies: the agent honors HTTPS_PROXY, HTTP_PROXY and NO_PROXY from the environment, or an explicit proxy URL in its configuration. printhook-agent diag tests DNS, TLS, proxy (with 407 detection), the WebSocket upgrade, storage reachability and the spooler, and --export writes a diagnostics zip. Review and redact it before sharing, then email support for transfer guidance. Use the local diagnostics result to investigate connection failures.
Reliability
- Durable job journal. A job is recorded in a local SQLite ledger, with its content already on disk, before it is acknowledged; marked spooling immediately before the OS is asked to print; and closed with a terminal state. That turns the server's at-least-once delivery into exactly-once printing across restarts and offline gaps.
- Outbox for state. A terminal state written while offline is reported when the connection returns.
- Service manager supervision.
Restart=alwayson Linux, KeepAlive on macOS, the Windows service recovery settings on Windows. - Session takeover handled. If a second agent claims the same install, the server keeps one session and closes the other with a distinct close code, and the console records a
computer.supersededevent.
Updates
Once enrolled, the service checks GET /v1/agent-releases/latest hourly. A newer release is downloaded, its SHA-256 and ed25519 manifest signature verified, the in-flight job finished, the executable swapped, and the service restarted by its service manager. Platform signatures (Authenticode, notarization) are checked by the OS when installers run. PRINTHOOK_AUTO_UPDATE=0 disables the hourly check; printhook-agent update --check exits 10 when a newer release exists, and update --rollback restores the previous version.
Data directories
| Platform | Data directory |
|---|---|
| Windows | C:\ProgramData\PrintHook |
| macOS | /Library/Application Support/PrintHook |
| Linux | /var/lib/printhook (environment in /etc/printhook/agent.env) |
| Docker | /var/lib/printhook (volume) |
config/ holds config.json and install_uuid, readable by administrators and the service only. state/ holds the ledger, the spool of content until it is printed, and state/logs/agent.log (JSON lines, rolled at 5 MB, ten files kept). The computer key appears in logs and diagnostics with only its prefix visible.