Working with PDF Files

Host your own PDF toolkits with Stirling-PDF or BentoPDF. Find out when either is good choice.
Server
PDF Management
Stirling PDF
BentoPDF
Author

Daniel Gerdesmann

Published

January 5, 2025

Modified

June 7, 2026

Changelog

2025/06/08: Included a quick look; updated the compose file for better Docker networking; updated the UI screenshot.

2026/06/07: Added BentoPDF as an option, updated the Stirling-PDF compose config, used a more informative header image.

Header image showing graphical user interfaces of Stirling-PDF and BentoPDF with their respective logos next to each other.

What

Host your own PDF toolkit with Stirling-PDF or BentoPDF. Both allow you to merge, convert, compress, edit, and clean PDFs, but they operate differently:

  • Stirling-PDF:s A server-based solution. Upload a PDF, the server processes your edits, and you download the result.

  • BentoPDF: The server delivers JavaScript, and all processing happens locally in your browser. Your data never leaves your device.

📦 App Info

  • Logo:
  • Purpose: A self-hosted or Desktop PDF processing platform for merging, splitting, compressing, converting, and editing PDFs
  • Deployment: Docker Compose (preferred), Standalone Binary, (Desktop App available)

🔍 Tech & Usage

  • Stack: Java (backend), HTML & JavaScript (frontend)
  • Memory: ~550 MB in idle
  • Disk: ~810 MB (Docker image size)
  • CPU: ~0.3 % of 4 vCPUs (idle, spikes while processing PDFs)

📜 License & Community

  • License: Open Core (core feature under MIT)
  • Pricing: Free; paid enterprise edition
  • Type: Commercial (Stirling PDF Inc.), with community backing
  • User Base: Large, number one open core PDF software

🌐 Homepage · 💻 GitHub

📦 App Info

  • Logo:
  • Purpose: Browser-based PDF processing app
  • Deployment: Docker Compose (preferred), offline/binary deployments

🔍 Tech & Usage

  • Stack: JavaScript, Fluent, TypeScript
  • Memory: minimal
  • Disk: ~130 MB (Docker image size)
  • CPU: minimal

📜 License & Community

  • License: Open source (AGPL 3.0)
  • Pricing: Free
  • Type: Personal project with community-backing
  • User Base: Growing, popular among self-hosters

🌐 Homepage · 💻 GitHub

Which one suits you? Stirling is good if you prefer centralized server processing and a mature, extensive feature set. BentoPDF excels in privacy (no data leaves your device), speed (no uploads or downloads), and minimal server load. For typical self-hosting setups I recommend BentoPDF. I see Stirling-PDF strengths in enterprise settings. Both offer a comprehensive feature set that covers typical needs. For specialized requirements, compare Stirling-PDF’s features with BentoPDF’s features (scroll down, you can even just use their instance).

Why

Friends don’t let friends upload sensitive PDFs to random websites. Share your instance with family and friends. A PDF toolkit has good change of adoption, because people are used to similar services and recognize their value.

The How of Option 1: Stirling-PDF

Step 1: Register a Subdomain

Log in to your domain registrar and add an A-record pointing to your server’s IP address (e.g., pdf.yourdomain.com). If you’re unfamiliar with this process, check out this guide.

Step 2: Create a New Directory

On your Linux server, create a directory for Stirling-PDF:

mkdir stirling-pdf
cd stirling-pdf

Step 3: Create the Docker Compose File

First, create the Docker Compose file:

sudo nano docker-compose.yml

Then, populate the file with the following content. Look at the annotations for things you might want to change.

services:
  stirling-pdf:
    image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest
    container_name: stirling-pdf
    restart: unless-stopped
    expose
      - '8080'
    volumes:
      - ./stirling-data/tessdata:/usr/share/tessdata
      - ./stirling-data/configs:/configs
      - ./stirling-data/logs:/logs
      - ./stirling-data/pipeline:/pipeline
    environment:
      - UI_APP_NAME=Stirling PDF
      - UI_HOME_DESCRIPTION=Your locally hosted one-stop-shop for all your PDF needs.
      - UI_APP_NAVBAR_NAME=Stirling PDF
      - LANGS=en_GB
      - SYSTEM_DEFAULTLOCALE=en-GB
      - DOCKER_ENABLE_SECURITY=true
      - SECURITY_ENABLELOGIN=true
      - SECURITY_CSRFDISABLED=false
      - SECURITY_LOGINATTEMPTCOUNT=5
      - SECURITY_LOGINRESETTIMEMINUTES=120
      - SYSTEM_GOOGLEVISIBILITY=false
      - SYSTEM_ENABLESCARF=false
    networks:
      - npmnet
      
networks:
  npmnet:
    external: true
1
The :latest tag pulls the standard version (~900 MB). For a smaller version (~270 MB) with fewer features, use :latest-ultra-lite. For a larger version (\1+ GB) with additional fonts and a pre-bundled Java libraries (security) version, use :latest-fat.
2
I added a restart-policy.
3
We use ‘expose’ to just expose the internal port to an existing docker network; no exposure to the host needed, since we use a reverse proxy.
4
Store OCR language files.
5
Store settings & database
6
Store application logs.
7
Store automation configs.
8
Customize the app name (UI_APP_NAME), navbar name (UI_APP_NAVBAR_NAME), and description (UI_HOME_DESCRIPTION) to your liking.
9
Set available languages.
10
Set the default system language. Refer to the list of supported languages. There also will be a dropdown in the UI later to set the language.
11
To disable the login feature, set DOCKER_ENABLE_SECURITY and SECURITY_ENABLELOGIN to false.
12
Define the maximum number of failed login attempts before an account is temporarily locked.
13
Set the lockout period for temporarily blocked accounts.
14
You can disable visibility (via robots.txt). There is no need for crawlers to visit private instances with login.
15
Your instance will send some metadata to the Stirling-PDF developers by default, so that they can see how the software is typically used. You can disable “scarf”, if you have privacy concerns.
16
Attach the app to an existing network. Your reverse proxy must also be on this network.
17
Specify that the network is already existing. I defined it my Nginx Proxy Manager compose file.

Stirling-PDF offers other specialized settings, such as enabling an information API.

Step 4: Start the App

docker compose up -d

Optional Step 4.1: Install Further OCR Languages

The OCR (Optical Character Recognition) feature only works for English by default. If you need other languages, you will need to download the appropriate OCR training data.

First, move to the directory (volume) you specified in the compose file to store OCR data (e.g., ./stirling-data/tessdata:/usr/share/tessdata):

cd StirlingPDF
cd tessdata/

Visit the Tesseract OCR (fast) repo. Search for the language you want. Sometimes there are different versions for the same language, e.g. ‘deu.traineddata’ (works with modern German text) and ‘deu_latf.traineddata’ (works with old German “Fraktur” text).

Decided on a file you want? Use wget + file link to download it to your trainingdata/ directory:

sudo wget https://github.com/tesseract-ocr/tessdata_fast/blob/main/deu.traineddata

Repeat this process for as many files as you need.

Restart the app:

docker compose down
docker compose up -d

Step 5: Configure the Reverse Proxy

To ensure a secure setup, you’ll need a reverse proxy to act as a gateway with SSL encryption. I recommend using Nginx Proxy Manager (NPM) for its user-friendly interface: Log into your NPM interface, add a new proxy host using the service name ‘stirling-pdf’ and port 8080. Enable websockets, exploit protection, and SSL.

Step 6: Test Your Setup

To confirm everything is working, navigate to pdf.yourdomain.com. You should see the login interface. Use the default credentials:

  • Username: admin

  • Password: stirling

After logging in, you’ll be prompted to change the password. You can also update the username in the settings and find an option to add additional users.

See how the UI looks like:

User interface displaying various PDF operations in dark mode.

If you downloaded additional OCR training data, you can verify their availability: Type “OCR” into the search bar and click on the OCR menu when it appears. Look for additional language options. For example, if you added German training data, you should see a tickbox for German alongside English:

OCR menu displaying two tickboxes for English and German. The training data download was successful.

The How of Option 2: BentoPDF

Step 1: Register a Subdomain

Log in to your domain registrar and add an A-record pointing to your server’s IP address (e.g., pdf.yourdomain.com). If you’re unfamiliar with this process, check out this guide.

Step 2: Create a New Directory

On your Linux server, create a directory for Stirling-PDF:

mkdir bentopdf
cd bentopdf

Step 3: Create the Docker Compose File

First, create the Docker Compose file:

sudo nano docker-compose.yml

Then, populate the file with the following content:

services:
  bentopdf:
    image: ghcr.io/alam00000/bentopdf-simple:latest
    container_name: bentopdf
    restart: unless-stopped
    networks:
      - npmnet
      
networks:
  npmnet:
    external: true
1
The bentopdf-simple image is the recommended version for self-hosters. It has the exact same feature set as the full bentopdf image; it just drops unnecessary GUI elements such as hero, FAQ, testimonials, and footer that are used on the official BentoPDF instance and only needed in commerical settings.
2
Attach the app to an existing network. Your reverse proxy must also be on this network.
3
Specify that the network is already existing. I defined it my Nginx Proxy Manager compose file.

Step 4: Start the App

docker compose up -d

Step 5: Configure the Reverse Proxy

To ensure a secure setup, you’ll need a reverse proxy to act as a gateway with SSL encryption. I recommend using Nginx Proxy Manager (NPM) for its user-friendly interface: Log into your NPM interface, add a new proxy host using the service name ‘bentopdf’ and port 8080. Enable websockets, exploit protection, and SSL.

Since BentoPDF does not have build-in authentication, you might want to add basic auth via an access list. Go the the “Access Lists” tab, create a new entry with a name, the option “Satisfy Any” on, and your chosen username and password. Then enable this access list in the proxy host.

Step 6: Test Your Setup

To confirm everything is working, navigate to pdf.yourdomain.com. You should see the basic auth prompt. Enter the username and password you specified. You might need to reload the page after.

See how the UI looks like:

BentoPDF user interface displaying various PDF operations in dark mode.

Scrolling down, many more tools greet you:

BentoPDF user interface displaying various PDF operations in dark mode.

Clicking on the merge tool, you see a straight-forward interface:

BentoPDF user interface showing the merge PDF menu.

That’s it - thank you for following along.

Giving Back

Two comprehensive PDF toolboxes! If you like them, consider showing your support by giving the project a ⭐ on GitHub. or get involed in fixing things, helping users, or support the project financially.