What it is
Stirling PDF is a self-hosted web app for doing things to PDFs: merge, split, OCR, convert to/from other formats, watermark, redact, fill forms. Drag a PDF in, click a tool, get a result. No account, no upload to a third party, no "free version watermarks your output."
Why I run it
The PDF tools world is a parade of either limited free websites that upload your file to who-knows-where, or expensive desktop apps. For one-off office-paperwork tasks — combining a few scans, OCRing a receipt, redacting a number from a screenshot — Stirling does all of it locally and doesn't ask anything in return.
The privacy framing matters here. PDFs I run through it sometimes contain things I don't want online: passport pages, contracts, tax forms. The whole point of doing this self-hosted is that those files never leave my hardware.
How I use it
Open the page, drag the PDF in, pick the tool, download the result. The UI is a tile grid of every operation grouped by category. I use the merge-PDFs, the page-extract, and the OCR tools more or less weekly; the more exotic ones (signing, redacting, form-fill) once in a while.
For "advanced" operations — OCR, ebook conversion, HTML-to-PDF — Stirling has a tiered dependency model. The slim image doesn't ship LibreOffice and Calibre; you opt in via an env var that triggers their install on first start. Larger image, slower startup, but you only pay it if you use those features.
Setup notes
- Host: the dev-tools LXC, alongside the observability stack.
- Image pinned: never
:latest. Watchtower's advisor pipeline flags new releases for me to review. - Reverse proxy: yes. If you upload large PDFs through the proxy and they fail (but work direct-IP), increase
client_max_body_sizeon the proxy host's Advanced tab. - Auth: off by default — runs as anonymous access. Login can be enabled via
DOCKER_ENABLE_SECURITY=true; first start generates an admin password in the logs. I haven't enabled login; the service is internal-only. - Backups: PBS captures the LXC. Stirling itself has no persistent state worth backing up (each session is uploaded → processed → downloaded, no library).
- Update cadence: manual.
Runbook
- Healthy looks like: web UI loads, drag-drop accepts a file, a simple merge of two PDFs completes successfully.
- "Tool not available" on advanced operations: the optional dependencies (LibreOffice, Calibre, OCR engines) aren't installed. Set
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=true(or the equivalent for the operation you need),docker compose up -d, wait for the larger image to install. - Upload fails on large PDFs: proxy body-size limit is too small. Bump
client_max_body_sizeon the proxy host. - Container won't start: most often a permissions issue on a bind-mounted config volume — Stirling runs as a non-root user inside the container.
- Where logs live:
docker logs stirling-pdfon the host.