LUNAROPS · OPERATIONAL UPLINK 100% UPTIME 1,247d POSTS 893 JEFF.MOON@LUNAROPS.DEV UTC --:--:--

Stirling PDF: Self-Hosted PDF Swiss Army Knife

homelabself-hostingdockerpdfocrprivacyopen-source

If you’ve ever pasted a sensitive contract into a cloud PDF tool, you’ve probably had a moment of mild dread immediately after clicking “Convert.” Stirling-PDF fixes that. It’s an open-source, self-hosted web application that brings 50+ PDF operations — merge, split, OCR, compress, convert, sign, redact, watermark — under one roof, running entirely within your own infrastructure.

With 76,000+ GitHub stars, it’s currently the most-starred PDF application on the platform. The project is mature, actively maintained, and ships official Docker images for both amd64 and arm64. Whether you’re running it on a Raspberry Pi or a beefy homelab server, there’s an image tier to match.


What Stirling-PDF Can Do

The feature list is long enough that it’s easier to organize by category than to enumerate every item.

Merge and Split

  • Merge multiple PDFs into one, in any order
  • Split by page range, individual pages, or page count
  • Extract specific pages into a new document

Compression and Optimization

  • Reduce file size with configurable quality settings
  • Optimize for web (fast linear load) or print

Format Conversion

  • Office to PDF: DOCX, XLSX, PPTX → PDF (requires LibreOffice)
  • PDF to Office: PDF → DOCX, XLSX, PPTX (requires LibreOffice)
  • PDF to image: PNG, JPG, TIFF
  • Image to PDF: PNG, JPG, BMP, GIF
  • PDF to text, CSV, or HTML
  • PDF/A conversion for long-term archival
  • EPUB ↔ PDF (when the optional book conversion feature is enabled)

OCR (Optical Character Recognition)

  • Makes scanned, image-based PDFs fully searchable
  • Powered by Tesseract with an OCRMyPDF wrapper
  • Supports 40+ languages via environment variable configuration

Page Manipulation

  • Rotate, reorder, delete, or insert blank pages
  • Add bookmarks and table of contents entries

Watermarks and Stamps

  • Text or image watermarks with configurable position, opacity, and rotation
  • Add stamps or overlays to entire documents

Digital Signatures

  • Sign PDFs with digital certificates
  • Verify and remove existing signatures

Forms and Metadata

  • Extract form data to CSV or XLSX
  • Add, edit, or strip PDF metadata
  • Programmatic form filling via API

Security

  • Password-protect or remove password protection
  • Text redaction (removes content, not just visually covers it)

What It Can’t Do

Worth being honest about the limitations: Stirling-PDF cannot edit existing text in a PDF (you can add new text, but the existing text is not editable). There’s no annotation or collaborative markup system like Adobe Acrobat’s comment tools. And PDF-to-Word conversion quality, while functional, varies depending on the original document’s layout complexity.


The Three Image Tiers

Stirling-PDF ships three Docker image variants. Picking the right one is the first decision to make.

Tier Tag Size Includes
Ultra-Lite latest-ultra-lite ~350 MB Core PDF operations only
Standard latest ~600 MB + Tesseract OCR, LibreOffice
Fat latest-fat ~1.5 GB + All fonts, extra tools, extended language packs

Ultra-Lite is the right choice for resource-constrained hardware (Raspberry Pi, low-end VPS) when you only need merge, split, rotate, compress, and basic conversion. It excludes LibreOffice and Tesseract entirely, so Office conversions and OCR are unavailable.

Standard (latest) is the recommended choice for most deployments. It includes Tesseract OCR with base language packs (English, German, French, Portuguese, Simplified Chinese) and LibreOffice for Office document conversion.

Fat includes everything in Standard plus additional fonts, language packs, and edge-case conversion tools. Use it when disk space is not a concern and you need maximum format compatibility.

All three variants are published to Docker Hub under stirlingtools/stirling-pdf and support both linux/amd64 and linux/arm64/v8.


Deploying with Docker Compose

Basic Deployment

For an internal network where you trust all users, security can stay disabled:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest
    container_name: stirling-pdf
    ports:
      - "8080:8080"
    volumes:
      - ./configs:/configs
      - ./logs:/logs
      - ./customFiles:/customFiles
    restart: unless-stopped

Browse to http://your-server:8080 and you’re running. No authentication required — every user gets full access to all tools.

With Login and Security Enabled

For any internet-facing deployment or shared team environment, enable the built-in login system:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest
    container_name: stirling-pdf
    ports:
      - "8080:8080"
    environment:
      - DOCKER_ENABLE_SECURITY=true
      - SECURITY_ENABLELOGIN=true
      - SECURITY_INITIALLOGIN_USERNAME=admin
      - SECURITY_INITIALLOGIN_PASSWORD=changeme123
      - TESSERACT_LANGS=eng,fra,deu,spa
      - PUID=1000
      - PGID=1000
      - UI_APP_NAME=LunarOps PDF
    volumes:
      - ./configs:/configs
      - ./logs:/logs
      - ./customFiles:/customFiles
    restart: unless-stopped

Change the initial admin password immediately after first login — it’s used only for bootstrapping, then managed through the UI.

Environment Variable Reference

Variable Purpose Default
DOCKER_ENABLE_SECURITY Enable login system and security features false
SECURITY_ENABLELOGIN Require authentication for all endpoints false
SECURITY_INITIALLOGIN_USERNAME Initial admin username admin
SECURITY_INITIALLOGIN_PASSWORD Initial admin password (bootstrap only) (none)
TESSERACT_LANGS OCR language packs to install on startup eng
LANGS UI display language en_GB
PUID UID for file ownership 1000
PGID GID for file ownership 1000
UI_APP_NAME Custom app name shown in the browser tab Stirling-PDF
DISABLE_ADDITIONAL_FEATURES Disable proprietary security module to save RAM false
INSTALL_BOOK_AND_ADVANCED_HTML_CONVERSION Enable EPUB/book conversion tools false

Volume mounts:

  • /configs — Stores configuration, user database, and custom settings. This is where the user database persists across container restarts — back this up.
  • /logs — Application logs.
  • /customFiles — Optional directory for custom fonts, scripts, and templates.

File upload limits: If you’re running Stirling-PDF behind nginx, the default client_max_body_size of 1 MB will block most real-world PDFs. Set it to at least 100m. Traefik handles large uploads without extra configuration.


Behind Traefik

For homelab setups where Traefik handles HTTPS termination:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
networks:
  traefik:
    external: true

services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest
    container_name: stirling-pdf
    environment:
      - DOCKER_ENABLE_SECURITY=true
      - SECURITY_ENABLELOGIN=true
      - SECURITY_INITIALLOGIN_USERNAME=admin
      - SECURITY_INITIALLOGIN_PASSWORD=changeme123
      - TESSERACT_LANGS=eng,fra,deu
      - PUID=1000
      - PGID=1000
    volumes:
      - ./configs:/configs
      - ./logs:/logs
    networks:
      - traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.stirlingpdf.rule=Host(`pdf.yourdomain.com`)"
      - "traefik.http.routers.stirlingpdf.entrypoints=websecure"
      - "traefik.http.routers.stirlingpdf.tls.certresolver=letsencrypt"
      - "traefik.http.services.stirlingpdf.loadbalancer.server.port=8080"
    restart: unless-stopped

No ports: block needed — Traefik routes traffic directly to the container on port 8080. Let’s Encrypt provisions the certificate automatically.


OCR: Adding Language Support

Stirling-PDF’s OCR is powered by Tesseract through the OCRMyPDF wrapper. The standard image ships with English, German, French, Portuguese, and Simplified Chinese base packs.

To add additional languages, set TESSERACT_LANGS to a comma-separated list of ISO 639-3 language codes:

1
2
environment:
  - TESSERACT_LANGS=eng,fra,deu,spa,ita,jpn,rus,ara,chi-sim,chi-tra

The container’s init script processes this variable on startup, copying the requested language data from the bundled pack into the active Tesseract directory. First startup is slower as a result — allow 2–5 minutes depending on how many languages you add.

Common language codes:

Language Code
English eng
French fra
German deu
Spanish spa
Italian ita
Japanese jpn
Russian rus
Arabic ara
Simplified Chinese chi-sim
Traditional Chinese chi-tra
Korean kor
Portuguese por

The full Tesseract language list covers 40+ languages and regional variants.


REST API

Every operation available in the web UI is also exposed as a REST API endpoint. This makes Stirling-PDF a useful building block in automation pipelines — n8n workflows, shell scripts, or any language that can make HTTP requests.

Swagger UI (interactive documentation) is available at http://localhost:8080/swagger-ui/index.html. If you’re unsure what parameters a particular endpoint takes, this is the fastest way to explore it.

Base URL: http://localhost:8080/api/v1/

Authentication: When security is disabled, endpoints require no auth. When login is enabled, pass an API key in the X-API-Key header (generated in the admin UI) or obtain a JWT via /api/v1/auth/login.

Merge PDFs

1
2
3
4
5
6
curl -X POST "http://localhost:8080/api/v1/general/merge-pdfs" \
  -H "X-API-Key: your-api-key" \
  -F "file=@report1.pdf" \
  -F "file=@report2.pdf" \
  -F "file=@appendix.pdf" \
  -o merged.pdf

OCR a Scanned Document

1
2
3
4
5
curl -X POST "http://localhost:8080/api/v1/general/ocr" \
  -H "X-API-Key: your-api-key" \
  -F "fileInput=@scanned_invoice.pdf" \
  -F "language=fra" \
  -o searchable_invoice.pdf

Compress a PDF

1
2
3
4
curl -X POST "http://localhost:8080/api/v1/general/compress-pdf" \
  -H "X-API-Key: your-api-key" \
  -F "fileInput=@large_document.pdf" \
  -o compressed.pdf

Split at Page 10

1
2
3
4
5
curl -X POST "http://localhost:8080/api/v1/general/split-pdf-by-page" \
  -H "X-API-Key: your-api-key" \
  -F "fileInput=@document.pdf" \
  -F "pageNumber=10" \
  -o split.pdf

Remove Password

1
2
3
4
5
curl -X POST "http://localhost:8080/api/v1/security/remove-password" \
  -H "X-API-Key: your-api-key" \
  -F "fileInput=@protected.pdf" \
  -F "password=secretpassword" \
  -o unlocked.pdf

Batch Compression Script

Compress every PDF in a directory:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/bin/bash
API_URL="http://localhost:8080/api/v1"
API_KEY="your-api-key"
INPUT_DIR="./pdfs"
OUTPUT_DIR="./compressed"

mkdir -p "$OUTPUT_DIR"

for pdf in "$INPUT_DIR"/*.pdf; do
  filename=$(basename "$pdf")
  echo "Compressing $filename..."
  curl -s -X POST "$API_URL/general/compress-pdf" \
    -H "X-API-Key: $API_KEY" \
    -F "fileInput=@$pdf" \
    -o "$OUTPUT_DIR/$filename"
done

echo "Done. Compressed PDFs saved to $OUTPUT_DIR"

Security and Authentication

Login System

When DOCKER_ENABLE_SECURITY=true and SECURITY_ENABLELOGIN=true, Stirling-PDF requires authentication for all operations. The user database is stored in /configs and persists across container restarts.

Two roles exist:

  • Admin — Full access to all features, user management, and application settings
  • User — Access to PDF tools with limited settings access

The free self-hosted version supports up to 5 named users. If you need more users, you can use 3rd-party authentication instead of named accounts.

OIDC/OAuth2 Integration

Stirling-PDF supports SSO via OIDC/OAuth2, which integrates cleanly with self-hosted identity providers like Authentik or Keycloak. Configure it in the admin settings after deployment — no environment variable gymnastics required.

For homelabs already running Authentik as the SSO layer, this means users authenticate once and get access to Stirling-PDF alongside your other self-hosted services.

API Keys

Admin users can generate API keys in the settings UI. Pass the key as an X-API-Key header to bypass session authentication in automation workflows. Keys are persistent — generate one per integration rather than sharing credentials.


Integration with Paperless-ngx

Stirling-PDF pairs naturally with a paperless-ngx document management setup. The two tools don’t integrate directly — the paperless-ngx team intentionally keeps the document processor focused — but you can bridge them via the Stirling-PDF API.

Pre-ingestion workflow (with n8n or a shell script):

  1. Scanner drops a multi-page PDF in a watched folder
  2. Stirling-PDF API splits the scan into individual documents by page count or content
  3. Each split PDF lands in the paperless-ngx consume directory
  4. Paperless ingests, OCRs, and tags each document separately

Post-import cleanup:

  • Call the Stirling-PDF compress endpoint on documents before archival
  • Strip metadata from documents before sharing outside the organization
  • Merge monthly statements into a single archived PDF

The API-first design makes it straightforward to wire into any automation tool that can make HTTP requests.


Comparison with Cloud Alternatives

Stirling-PDF iLovePDF SmallPDF Adobe Acrobat
Hosting Your infrastructure iLovePDF servers SmallPDF servers Adobe cloud
Data leaves your network Never Yes Yes Yes
Cost Free Free tier (limited) Free tier (limited) $9.99+/mo
File size limit Server resources 50 MB (free) 10 MB (free) Subscription-dependent
Offline capable Yes No No No
REST API Full, free Limited/paid Limited/paid Paid tiers
HIPAA-ready Yes (self-hosted) Agreement required Agreement required Enterprise agreement
Setup effort 15 min (Docker) Zero (cloud account) Zero (cloud account) Zero (account)

The tradeoff is the standard self-hosting tradeoff: you trade zero-setup convenience for data sovereignty, no subscription cost, and no file size constraints beyond your own server’s capacity.


Gotchas and Operational Notes

Slow first startup. On the first run, the init script installs OCR language packs and sets up the environment. Allow 2–5 minutes before the web UI becomes available. Subsequent starts are fast.

File permissions matter. The /configs, /logs, and /customFiles directories must be owned by the UID and GID specified by PUID and PGID (default: 1000). If you see permission errors on startup, chown -R 1000:1000 ./configs ./logs fixes it.

LibreOffice conversions are CPU-intensive. Office-to-PDF and PDF-to-Office conversions spin up a LibreOffice headless process. On large files or slow hardware, these can take tens of seconds. Set appropriate timeouts in any upstream proxy.

Air-gapped environments. The fat image attempts to fetch Alpine package repositories on first startup. In a fully air-gapped environment, the standard image (which has dependencies pre-installed) is more reliable.

No text editing. This is the most common expectation mismatch. You cannot click on existing text in a PDF and change it. If that’s the primary use case, Stirling-PDF won’t satisfy it — that’s a different class of tool.

PDF-to-Word quality varies. Conversion quality depends heavily on whether the original PDF has embedded fonts, proper text encoding, and clean layout structure. Native-PDF originals convert well; scanned-and-OCR’d originals convert poorly.


Running on Raspberry Pi

The ultra-lite image runs comfortably on a Raspberry Pi 4 (4 GB RAM) for basic PDF operations:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest-ultra-lite
    container_name: stirling-pdf
    ports:
      - "8080:8080"
    volumes:
      - ./configs:/configs
      - ./logs:/logs
    environment:
      - PUID=1000
      - PGID=1000
    restart: unless-stopped

Skip the TESSERACT_LANGS and DOCKER_ENABLE_SECURITY variables — ultra-lite doesn’t include the tools they configure, and you can add authentication at the reverse proxy layer instead (basic auth in Traefik or Caddy).

For a Pi serving only your household, the resource profile is a comfortable fit: the ultra-lite image uses around 200–300 MB of RAM under load.


The Privacy Case

The pitch for self-hosting Stirling-PDF versus using a cloud service is straightforward: your documents stay on your hardware.

That matters most in regulated industries — healthcare organizations handling patient documents, legal teams processing contracts, financial services working with statements and filings. But it also matters for anyone who’d rather not have their personal tax returns or employment contracts pass through a third-party server where retention policies are opaque.

The cloud tools are faster to start (no Docker required), but Stirling-PDF’s setup time is measured in minutes, not hours. Once it’s running, it’s just a URL.


The Bottom Line

Stirling-PDF is production-ready and operationally simple. Deploy the standard image, put it behind Traefik, enable the built-in login, and you have a capable PDF workstation accessible to your whole team — with no per-seat licensing, no file size limits beyond your server’s disk, and no data leaving your network.

The REST API makes it composable with the rest of your homelab automation. The three image tiers mean you’re not forced to pay the resource cost of LibreOffice and Tesseract if you don’t need them. And the project’s maturity (76k+ stars, 172+ releases) means the rough edges have been filed down.

If you’re still uploading PDFs to cloud tools out of habit, Stirling-PDF is the most straightforward fix.

Comments