Stirling-PDF is an open-source, web-based PDF toolkit that you host yourself. It covers the everyday jobs people usually upload to random websites: merging, splitting, rotating, compressing, converting (PDF ↔ images, Office, HTML, Markdown), OCR, watermarks, signatures, redaction, page reordering and metadata editing. Files are processed on your server and not stored afterwards, so sensitive documents never touch a third-party service.

What it can do

Category Examples
Organise Merge, split, reorder, rotate, remove pages, multi-page layout
Convert PDF ↔ images, Office ↔ PDF (via LibreOffice), HTML/URL/Markdown → PDF, PDF → PDF/A
Optimise Compress, repair, remove blank pages
Security Add/remove passwords, permissions, redaction, sanitise (remove scripts, metadata)
Text OCR (Tesseract/OCRmyPDF) to make scans searchable, extract images
Sign Draw, type or certificate-based signatures, stamps, watermarks
Automate Pipelines (multi-step jobs) and a REST API

Requirements

  • 1–2 vCPU and 2 GB RAM for occasional use.
  • OCR and Office conversions are CPU-heavy. Give it more cores for large scanned documents, or for several users.
  • The “fat” image (with LibreOffice, OCR languages and fonts) is a few GB, so plan disk space.

Install with Docker

# /opt/stirling-pdf/compose.yaml
services:
  stirling-pdf:
    image: stirlingtools/stirling-pdf:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      DOCKER_ENABLE_SECURITY: "true"        # enables the login system
      SECURITY_ENABLELOGIN: "true"
      LANGS: en_GB
      SYSTEM_MAXFILESIZE: 200               # MB
    volumes:
      - ./tessdata:/usr/share/tessdata      # OCR language data
      - ./configs:/configs                  # settings.yml, database
      - ./logs:/logs
cd /opt/stirling-pdf && docker compose up -d

Image tags vary by edition (full, standard, ultra-lite). Pick the full image if you need Office conversion and OCR, and check the docs for current tag names and variables.

OCR languages: the image includes English. Add others by placing Tesseract .traineddata files (for example chi_sim, jpn, deu) in ./tessdata.

Login and users

With security enabled, the first start creates a default admin account (shown in the docs, typically admin / stirling). You’re asked to change the password on first login. Add users in the admin settings. Optional SSO via OAuth2/OIDC is available.

Without login, anyone who can reach the site can use your CPU. Only run it without authentication on a private network or VPN.

Nginx with HTTPS

server {
    server_name pdf.example.com;
    client_max_body_size 200M;             # match SYSTEM_MAXFILESIZE
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 600s;            # long OCR/conversion jobs
    }
    # listen 443 ssl; certbot --nginx -d pdf.example.com
}

See Nginx reverse proxy and Let’s Encrypt. If you get “413 Request Entity Too Large”, see fix 413 errors.

OCR scanned documents

Choose OCR / Cleanup scans, and select the language. Options include deskew, cleaning, and “skip text pages”. The result is a searchable PDF with a hidden text layer, ideal before archiving to Paperless-ngx or Nextcloud.

API and pipelines

Every tool is also an API endpoint (Swagger docs at /swagger-ui/index.html):

curl -X POST https://pdf.example.com/api/v1/general/merge-pdfs \
  -H "X-API-KEY: $KEY" \
  -F "[email protected]" -F "[email protected]" -o merged.pdf

Pipelines chain operations (for example OCR → compress → add watermark) and can watch a folder for automatic processing.

Privacy and resources

  • Uploaded files are processed in temporary storage and deleted. They aren’t kept in a library.
  • Limit file size, and watch CPU during OCR. See htop.
  • Keep the container updated. It bundles many document-parsing libraries, and those get security fixes. See updating self-hosted apps.

Quick reference

Item Value
Port 8080
Enable login DOCKER_ENABLE_SECURITY=true
Upload size SYSTEM_MAXFILESIZE + Nginx client_max_body_size
OCR languages .traineddata files in /usr/share/tessdata
API docs /swagger-ui/index.html

Related: OnlyOffice Docs and Nextcloud.

  • Self-Hosting
  • Docker
  • Productivity