How to Deploy Stirling-PDF on a VPS
Updated Sep 2026
verified on Ubuntu 26.04 · Sep 2026Self-host Stirling-PDF on a VPS with Docker — merge, split, OCR, compress and redact PDFs on your own server, with the default admin password changed and HTTPS in front.
- A VPS with 2 GB RAM (the ultra-lite image runs on less)
- A fresh Ubuntu 24.04 or 26.04 server with root/sudo SSH access
- A domain you can point at the server
- Docker Engine + Compose installed (see the base guide below)
What Stirling-PDF is
Stirling-PDF is a web app and REST API with more than 50 PDF tools: merge, split, rotate, convert to and from other formats, OCR, compress, redact, sign, add watermarks, and chain several of those into a pipeline. The point of running your own copy is where the files go. Online PDF tools upload your contracts and bank statements to someone else's server; Stirling-PDF processes them on yours.
It is a Java / Spring Boot application with a TypeScript front end. The licensing is open core: the MIT-licensed core runs without a licence key, while SSO, auditing and some other enterprise features are paid. Everything in this guide uses the free core.
One thing surprises people coming from older tutorials: login is on by
default. A fresh container creates an admin account with a known password,
which you change on first sign-in. That default is the reason this guide exists
as more than one docker run line.
Server sizing
The catalog lists 2 GB of RAM as the minimum for the standard image. It is a Java application that also calls out to tools such as LibreOffice and an OCR engine for some operations, so memory use depends heavily on what you ask it to do: compressing a small PDF is cheap, converting a large office document or OCR'ing a long scan is not.
Upstream publishes three image variants, all from
docker.stirlingpdf.com/stirlingtools/stirling-pdf:
| Tag | What it includes | When to use it |
|---|---|---|
latest |
All PDF features | Most installs |
latest-fat |
Everything plus extra fonts and conversion tools | Best conversion fidelity, more disk |
latest-ultra-lite |
Core features only | Small VPS, fastest start, basic operations |
On a 1 GB box, use latest-ultra-lite. Disk is modest: 10–20 GB covers the OS,
the image and the settings volume, since processed files aren't kept.
Prepare the server
This guide assumes Docker Engine and the Compose plugin are installed, with a
ufw firewall. If not, start with
Docker & Compose on Ubuntu.
Open SSH and the proxy ports only; port 8080 stays on loopback:
sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw --force enable
sudo ufw status verbose
Paid link — we earn a commission if you shop through it.
Install Stirling-PDF (Docker Compose)
The upstream Docker guide documents four bind mounts: /configs for settings
and the user database, /logs, /pipeline for saved automations, and
/usr/share/tessdata for extra OCR languages. This guide keeps the first three
and leaves tessdata to the image, so the bundled OCR data stays in place; add
that mount later only if you need more languages.
mkdir -p ~/stirling-pdf/stirling-data/{configs,logs,pipeline}
cd ~/stirling-pdf
cat > docker-compose.yml <<'YAML'
services:
stirling-pdf:
image: docker.stirlingpdf.com/stirlingtools/stirling-pdf:latest
container_name: stirling-pdf
restart: unless-stopped
ports:
# Loopback only: Caddy is the only way in from outside.
- "127.0.0.1:8080:8080"
volumes:
- ./stirling-data/configs:/configs
- ./stirling-data/logs:/logs
- ./stirling-data/pipeline:/pipeline
environment:
SYSTEM_DEFAULTLOCALE: en-US
YAML
docker compose up -d
Java takes a little while to start. Wait until the web UI answers — with login enabled, the root URL either serves the app or redirects to the login page:
for i in $(seq 1 60); do
code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8080/)
case "$code" in 200|302) echo "Stirling-PDF is up ($code)"; break ;; esac
sleep 5
done
case "$code" in 200|302) true ;; *) docker compose logs --tail 50; false ;; esac
First login: change the default password
Per the upstream docs, a fresh container starts with login enabled and a default admin account:
- Username:
admin - Password:
stirling
Change this password immediately after first login. Anyone who can reach the instance before you do can sign in with those credentials, which is another reason to keep port 8080 on loopback and only expose the app through HTTPS once you're ready to log in straight away.
From the admin account you can add more users under the account settings. If
you truly want a single-user tool with no authentication — for example, reachable
only over a VPN — upstream lets you opt out with SECURITY_ENABLELOGIN=false.
Don't do that on an instance with a public hostname.
HTTPS + domain
Point an A record such as pdf.example.com at the server and terminate TLS
in front of 127.0.0.1:8080, following
Automatic HTTPS with Caddy:
pdf.example.com {
request_body {
max_size 200MB
}
reverse_proxy 127.0.0.1:8080
}
The request_body block keeps Caddy from rejecting large uploads; pick a limit
that matches the files you work with. Stirling-PDF has its own upload limit too:
SYSTEM_MAXFILESIZE (in MB) appears in the upstream example Compose files. If
Caddy runs as a container rather than on the host, 127.0.0.1 is the proxy's own
loopback — put both services in one Compose project and use
reverse_proxy stirling-pdf:8080.
Using it
The web UI lists the tools by category; files are processed and handed back to you, not stored. A few features worth knowing:
- Pipelines (the "Automate" feature) chain operations — for example OCR, then
compress, then add a watermark — and save them for reuse. Saved pipelines live
in the
/pipelinemount. - The REST API exposes the same operations, so scripts and other services can call it. The API documentation is linked from the project's README.
- Language:
SYSTEM_DEFAULTLOCALEsets the default UI language (for examplede-DEorfr-FR); unset, it follows the browser.
Stirling-PDF pairs well with a document archive: clean up, merge or redact a file here, then file it in Paperless-ngx.
Securing it
- Change
admin/stirlingon first login — this is the only mandatory step. - Keep login enabled on anything with a public hostname, and create individual accounts rather than sharing the admin login.
- Keep the port on loopback.
ss -ltnp | grep 8080should show127.0.0.1:8080. - Patch it. Upstream's update procedure is simply pulling the image again; do it on a schedule (see Upgrades).
Backups
Processed files aren't kept, so the only state is stirling-data: settings,
the user database and an encryption key in configs, plus your saved pipelines.
On start the container takes ownership of the mounted folders for its own user,
and some files (the credential encryption key among them) are readable only by
that user — so archive with sudo, or the backup silently misses them. Stop the
container for a consistent copy, archive the directory, and start it again:
cd ~/stirling-pdf
docker compose stop
sudo tar czf stirling-pdf-$(date +%F).tar.gz docker-compose.yml stirling-data
docker compose start
sudo tar tzf stirling-pdf-$(date +%F).tar.gz | grep credential-encryption.key
Copy the archive off the server. Restoring is the reverse: extract it into
~/stirling-pdf on a new box and run docker compose up -d.
Upgrades
cd ~/stirling-pdf
docker compose pull
docker compose up -d
The latest tag moves with each release; your settings and accounts survive
because they live in the bind mounts. Back up stirling-data first and read the
release notes before a major version — upstream publishes a migration guide for
the v1-to-v2 change, where several settings were renamed.
Troubleshooting
The page doesn't load right after starting. Give Java a minute; watch
docker compose logs -f stirling-pdf for the startup message.
The container keeps restarting. Upstream's advice: check the logs, check free
RAM and disk, and try the latest-ultra-lite image on limited hardware.
Permission errors on the mounted folders. The directories must exist and be
writable by the container's user. Creating them before the first start, as
above, avoids root-owned folders. Afterwards they belong to the container's user,
so use sudo to read or copy them from the host.
Uploads fail on big files. Raise Caddy's request_body limit and, if needed,
SYSTEM_MAXFILESIZE.
Verification + next steps
You're done when you can load https://pdf.example.com over a valid
certificate, log in with your new admin password (the old one no longer
works), merge two PDFs and download the result, and you have a copy of
stirling-data off the box.
Next, save a pipeline for the operation you repeat most, and create accounts for anyone else who will use it. For hosts, see Best VPS for Self-Hosting.