Self-Host Stirling-PDF: 50+ Private PDF Tools on Your Server
You need to merge two PDFs, or strip a password, or OCR a scanned contract. So you do what everyone does: you Google "merge PDF free," click the first result, and upload a document with your client's signature and bank details to a server you know nothing about. We have all done it. The file sits in someone's S3 bucket, gets "deleted in one hour" (allegedly), and you move on.
Stirling-PDF fixes that by moving the whole toolbox onto a server you control. It is a self-hosted web app with 50+ PDF tools, and once it is running, your documents never touch a third party again.
What you actually get
Stirling-PDF is the most-starred PDF app on GitHub, and the feature list is genuinely broad. It is not a one-trick merge tool. You get:
| Category | What it does |
|---|---|
| Page ops | Merge, split, rotate, reorder, crop, extract pages, multi-page layouts |
| Convert | PDF to/from images, Office files via LibreOffice, HTML, URL, Markdown |
| Security | Add/remove passwords, set permissions, watermark, sign, sanitize, auto-redact |
| Cleanup | OCR, compress, repair, edit metadata, detect blank pages, convert to PDF/A |
Everything runs through a clean web UI that speaks 40+ languages. But the part I care about most is the REST API, and I will get to why in a minute.
Getting it running
The fastest path is to deploy Stirling-PDF on Elestio, which hands you a managed instance with SSL, backups, and auto-updates already wired up. The software itself is open source, so there are no license fees. You only pay for the box it runs on, which on Elestio starts around $11/month for a managed VM.
If you want to self-manage with Docker Compose, here is a minimal setup that survives restarts:
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:latest
ports:
- "8080:8080"
volumes:
- ./trainingData:/usr/share/tessdata # OCR language packs
- ./configs:/configs
- ./customFiles:/customFiles
environment:
DISABLE_ADDITIONAL_FEATURES: "false"
LANGS: "en_GB"
restart: unless-stopped
Run docker compose up -d, open http://your-server:8080, and you have a working PDF suite. The trainingData volume is where OCR language files live, so mounting it means your eng+spa+fra OCR jobs keep working after an update.
Lock it down before you expose it
Out of the box the UI has no login. That is fine on a laptop, but the second you put it behind a public domain you want authentication on. Stirling-PDF has built-in login, you just have to turn it on:
environment:
DOCKER_ENABLE_SECURITY: "true"
SECURITY_ENABLELOGIN: "true"
SECURITY_INITIALLOGIN_USERNAME: "admin"
SECURITY_INITIALLOGIN_PASSWORD: "change-this-now"
The first time it boots with those set, it creates the admin account. Log in, change the password, and create per-user accounts from the settings page. On a managed Elestio deploy you get this behind HTTPS automatically, which matters because you do not want credentials traveling over plain HTTP.
The part everyone skips: the API
Here is the thing that turns Stirling-PDF from "a website I host" into actual infrastructure. Nearly every tool in the UI is also a REST endpoint. That means you can script the boring stuff.
Merging two files is a single call:
curl -X POST "https://pdf.yourdomain.com/api/v1/general/merge-pdfs" \
-H "X-API-KEY: your-api-key" \
-F "fileInput=@invoice.pdf" \
-F "fileInput=@receipt.pdf" \
-o merged.pdf
OCR a scanned document into a searchable PDF, with multiple languages:
curl -X POST "https://pdf.yourdomain.com/api/v1/misc/ocr-pdf" \
-H "X-API-KEY: your-api-key" \
-F "fileInput=@scanned.pdf" \
-F "languages=eng+fra" \
-o searchable.pdf
Grab your API key from your account settings once login is enabled, and browse the full endpoint list at /swagger-ui/index.html on your instance. Every parameter you see in the UI maps to a form field here.
Give your AI agent a PDF toolbox
This is where it gets fun. If you run an AI agent, you have probably hit the wall where it can read text but cannot actually do anything with a PDF. Point it at a self-hosted Stirling-PDF instance and that changes. There is already a community MCP server that wraps these endpoints as agent tools, so an assistant can merge, split, watermark, or OCR files on command, all against your private instance.
The privacy math is the whole point. Your agent processes a signed contract by calling your server, not by shipping the document to some public PDF API. The file never leaves infrastructure you control. For anyone handling client data, that is the difference between "convenient" and "allowed."
Troubleshooting
A few things that trip people up:
- OCR returns the same file unchanged. You are missing the language pack. OCR needs the Tesseract data for that language mounted in
tessdata. Add the language file and pass it inlanguages. - Login settings do nothing. Double-check
DOCKER_ENABLE_SECURITYistrue. If security features are not active, the login variables are simply ignored. - Office conversions fail. Those run through LibreOffice inside the container. On a tiny VM the conversion can time out or run out of memory, so give it at least 2 GB of RAM if you convert Office files often.
- Uploads rejected as too large. There is a max file size limit. Raise it with the
SYSTEM_MAXFILESIZEsetting rather than fighting your reverse proxy.
Worth it?
If you process PDFs more than a couple of times a month, yes. You stop leaking documents to anonymous web tools, you get an API you can automate against, and you can hand the whole thing to an AI agent without handing your data to a stranger. You can deploy Stirling-PDF on Elestio in a couple of minutes and point your next PDF job at a server you actually trust.
Thanks for reading ❤️ See you in the next one 👋