Admin UI & CLI
The daemon has a local admin UI in the browser and a command-line tool, print-daemon (run as node dist/cli.js from the
install folder). Both work with the same files in the home directory, so run the CLI with the service's home
(Install › Home directory).
Admin UI#
Open the link printed by node dist/cli.js admin url (http://127.0.0.1:10082/#token=…). Its tabs:
| Tab | What it does |
|---|---|
| Dashboard | Queues, printers and recent jobs; test prints. Label printers also have Custom test…, which opens the default test label as editable ZPL and prints your version as a one-off. |
| Add printer | Runs discovery, sets the scan ranges, and adds and edits printers (Printers). |
| Dead letters | The local dead-letter list; the tab's badge shows how many there are (Dead letters). |
| Queues | Adds, edits and deletes queues; changes apply without a restart (Queues › In the admin UI). |
| API | The message format, the firewall table, and how to send jobs to AWS SQS, Azure Service Bus and Google Pub/Sub in Java, TypeScript, Python and C#. |
| License | Installs a license key and shows the license in use (License). |
These pages are served by the daemon too, at http://127.0.0.1:10082/docs/ (no token needed), with the
Status page at /docs/status.html.
CLI#
| Command | What it does |
|---|---|
run |
Runs the daemon in the foreground (what the system service executes). |
service install | status | stop | start | uninstall |
The system service (Install › Run as a system service). |
config path | show | validate |
The config file path; the effective configuration with secrets redacted; a check of the file. |
schema |
Prints the JSON Schema of a print job message. |
admin url |
Prints the admin UI link with the token (needs read access to <home>/admin-token). |
printers list | add | remove | test | discover | scan-ranges | os |
Printers (Printers › Manual setup). |
dead-letters list | show | resend | delete |
The local dead-letter list (Dead letters). |
queues list | remove |
Queues in config.json (secrets masked). |
license, license install <file> |
Shows the license in use (--json for the same fields as the Status page), or installs a key (License). |
Global option: --home <dir> (default: PRINT_DAEMON_HOME or the platform default). --help works on every command.
Exit codes: 0 success, 1 an error (for dead-letters resend: any job failed), 3 not licensed (a test print or
re-send while printing is paused, or a license key that license install refused).
Dead letters#
In the admin UI, the Dead letters tab shows the list:
- Re-send prints the job right away from this daemon. It is not put back on the queue. If it prints, the entry is deleted. If it fails, the entry stays with the new reason.
- View/Edit shows the job as JSON. Large document data is shown as
@@document:n@@, and that placeholder keeps the original data of document n. Replace it only if you want to send new data. Change the printer, copies or options, then click Save edits & re-send. If the re-send fails, your edits are kept. - Re-send selected / all and Delete selected / all ask for confirmation, then show how many printed and how many failed.
The same actions from the CLI (no running daemon needed; use the service's home):
node dist/cli.js dead-letters list
node dist/cli.js dead-letters show <id> > job.json # summary goes to stderr
node dist/cli.js dead-letters resend <id> --edited job.json
node dist/cli.js dead-letters resend <id>... | --all # exit code 1 if any failed
node dist/cli.js dead-letters delete <id>... | --allDon't re-send the same entry from the UI and the CLI at the same time, or it can print twice.
Security#
- The admin UI binds to
127.0.0.1. Every/apicall needs thex-admin-tokenheader. The token is generated in<home>/admin-token(mode 0600). The UI page does not contain it: open the link printed byadmin url(http://127.0.0.1:10082/#token=...). The token is in the URL fragment, so the browser never sends it to the server. The page moves it tosessionStorageand removes it from the address bar. Without a token, or after a 401, the page asks for it. So only users who can read<home>/admin-token(root/Administrators onceservice installhas restricted the home) can use the UI. - Requests whose Host header isn't loopback or the configured host are rejected (DNS-rebinding defence). No CORS headers are
sent. CSP,
X-Frame-Options: DENYandReferrer-Policy: no-referrerare set. - These docs,
GET /v1/infoandGET /healthzneed no token; they show no secrets (no license key, no configuration). - If you bind the UI off loopback, the token travels over plain HTTP. Put it behind TLS and authentication, or set
admin.enabled: falseand use the CLI. - External programs (
lp, PowerShell, SumatraPDF, soffice) are run with argument arrays, never through a shell. Temp file names are sanitised. allowAdHocPrinters: truelets anyone who can write to the queue send data to any host the daemon can reach, on theadHocTcpPortsports (9100–9103 by default). Restrict queue write access, or turn it off and route only to registered printers.- Job
options.paperSizeis limited to[A-Za-z0-9._-], so it can't inject extra CUPS or SumatraPDF options. <home>holds secrets and settings that name executables (sumatraPdfPath,libreOfficePath), so it must not be writable by ordinary users.service installrestricts it (Install › Run as a system service). Files that already existed in<home>keep their owner and any explicit permissions, so if untrusted users could write there before, checkconfig.jsonand the rest of<home>before you install.