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.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
📦 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
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-pdfStep 3: Create the Docker Compose File
First, create the Docker Compose file:
sudo nano docker-compose.ymlThen, 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 -dOptional 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.traineddataRepeat this process for as many files as you need.
Restart the app:
docker compose down
docker compose up -dStep 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:
adminPassword:
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:
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:
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 bentopdfStep 3: Create the Docker Compose File
First, create the Docker Compose file:
sudo nano docker-compose.ymlThen, 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 -dStep 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:
Scrolling down, many more tools greet you:
Clicking on the merge tool, you see a straight-forward interface:
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.





