Stirling-PDF is a self-hosted web app that does the boring PDF jobs: merge, split, rotate, compress, watermark, convert between PDF and image or Office formats, OCR a scan into a searchable PDF, and add or remove a password. It replaces the tab you keep open at an online PDF site.
What it is
40-odd tools in one interface, all running locally. Files can be processed in the browser, uploaded to the server, or dropped into a watched folder for unattended batch jobs. The API is stable enough to call from scripts, which is the genuinely useful part.
Before you start
- Anonymous usage means anyone who finds the URL can use your CPU. Either put it behind auth at the reverse proxy or accept it's an open service on your server.
- LibreOffice is bundled for the Office conversions, which is most of the image's size. If you don't need those, the
*-noofficetag is far smaller. - It needs a fair amount of RAM for large files. A 300-page scanned PDF through OCR is a multi-hundred-megabyte spike.
1 — Write the compose file
services:
stirling:
image: docker.io/stirlingtools/stirling-pdf:latest
container_name: stirling-pdf
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
environment:
DISABLE_ADDITIONAL_FEATURES: "false"
SECURITY_ENABLELOGIN: "true"
SECURITY_ENABLEUSER: "false"
SECURITY_CREDENTIALS_ADMINUSER: admin
SECURITY_CREDENTIALS_ADMINPASSWORD: CHANGE_ME
SECURITY_INITIALAPIKEY_ENABLED: "true"
SYSTEM_DEFAULTLOCALE: en-US
LANG: en_US.UTF-8
volumes:
- ./config:/config
- ./custom-files:/custom-files
- ./logs:/logs
- ./prefix:/prefix
- ./profiles:/profiles
healthcheck:
test: ["CMD", "curl", "-fs", "http://localhost:8080/api/v1/info"]
interval: 30s
timeout: 5s
retries: 3
2 — Start it
mkdir -p ~/services/stirling-pdf/{config,custom-files,logs,prefix,profiles}
cd ~/services/stirling-pdf
docker compose up -d
docker compose logs -f stirling | grep -i "started\|error"
3 — First-run setup
- Open
http://yourhost:8080and log in asadmin.SECURITY_ENABLEUSER=falsekeeps it single-user, which is the sensible default for a home server. - Under Settings → General, set Enable login on and confirm it actually blocks anonymous access. A Stirling instance left fully open gets found by scanners within days.
- Create an API key under Settings → API and save it. Every tool has a documented HTTP endpoint, so this is how you script a merge or a batch OCR.
- Try the OCR tool on a scan. It uses Tesseract and works well on clean 300 DPI greyscale; a bad phone photo of a page will need deskewing first, which the same app can do.
4 — Script it
# merge two PDFs via the API
curl -s -H "Authorization: Bearer CHANGE_ME" \
-F "file1=@part1.pdf" -F "file2=@part2.pdf" \
http://127.0.0.1:8080/api/v1/general/merge \
-o merged.pdf
# OCR a scan into a searchable PDF
curl -s -H "Authorization: Bearer CHANGE_ME" \
-F "fileInput=@scan.pdf" \
"http://127.0.0.1:8080/api/v1/ocr/ocr" \
-o searchable.pdf
./watch and Stirling converts it automatically. Pair that with a scan-to-SMB or a phone upload folder and you've built yourself a zero-touch document pipeline for a fraction of a managed service.