How to Install Paperless-ngx on Ubuntu 24.04 — Self-Hosted Document Management
Paper stacks, receipts, contracts, and tax documents pile up faster than most people can file them. Uploading them to Evernote or Google Drive solves the mess but trades physical clutter for a privacy and subscription problem: your bank statements, medical records, and legal paperwork now live on someone else's server, indexed by someone else's algorithms, under someone else's terms of service. This guide walks you through installing Paperless-ngx on an Ubuntu 24.04 VPS — a self-hosted, open-source document management system with OCR, full-text search, tagging, and a polished web UI — from fresh SSH connection to a production-hardened deployment behind Nginx with TLS.
Prefer a managed setup? Deploy Paperless-ngx on our Starter VPS in minutes. Launch a VPS now and follow this guide end to end.
Table of Contents
What is Paperless-ngx?
Paperless-ngx is a community-driven fork of the original Paperless project that turns a pile of scanned PDFs and images into a searchable, tagged, OCR-indexed archive. Drop a document into a watched folder (or email it, or upload it from your phone), and Paperless-ngx handles the rest: it runs OCR with Tesseract, extracts text and metadata, auto-matches tags and correspondents based on rules you define, and stores the original plus a searchable archive copy.
Under the hood, Paperless-ngx is a Django web application backed by PostgreSQL for metadata, Redis as a task broker, and a small fleet of worker containers for document processing. The stack also includes Gotenberg (converts Office documents to PDF so they can be OCR'd and archived) and Apache Tika (extracts text from modern Office formats like .docx and .xlsx). The frontend is an Angular single-page app with a clean inbox-style workflow.
Typical use cases include personal paperwork (receipts, invoices, warranties, tax documents), small-business record keeping (contracts, vendor invoices, HR forms), freelancer bookkeeping (itemized receipts with auto-tagged correspondents for end-of-year expense reports), household document shelf (passports, birth certificates, insurance policies — searchable by full text or expiry date), and legal/medical archives where data must never leave premises.
Why Self-Host Document Management?
Evernote, Dropbox, Google Drive, and Microsoft OneDrive all offer document management features. On paper they look convenient. In practice, self-hosting Paperless-ngx wins on the dimensions that matter most for documents:
- Your documents stay on your server. Tax returns, medical records, legal contracts, and passports do not belong on a third-party cloud indexed by AI models and scanned by compliance systems you did not agree to. Paperless-ngx runs entirely on your VPS — the documents never leave.
- No subscription creep. Evernote Professional is $14.99/month. Google One 2 TB is $9.99/month. Dropbox Plus is $11.99/month. A Starter VPS runs Paperless-ngx plus a dozen other services for a flat monthly rate, with no per-user fees and no storage tier upgrades.
- No vendor lock-in. Paperless-ngx stores your original files on disk in a normal folder structure. If you ever want to leave, you just copy the
media/directory. Export is a file manager operation, not a CSV scrape through a web UI. - True full-text OCR search. Paperless-ngx runs Tesseract OCR on every document and indexes the extracted text. Searching for "refrigerator warranty" finds the scanned PDF of a receipt from three years ago. Google Drive's OCR is inconsistent and only applies to some file types.
- Auto-classification that actually works. Rules match correspondents, document types, and tags based on text patterns. Once trained, new scans file themselves.
- Air-gapped operation. Paperless-ngx has no cloud dependency. It runs fine on a home lab behind a VPN, on an office LAN, or on a VPS that is isolated from the internet.
- GDPR and regulatory-friendly. For EU businesses handling documents with personal data, keeping everything on a known EU-hosted VPS simplifies data processing agreements.
Cost Comparison: Self-Hosted vs. Cloud Document Management
| Scenario | Evernote Professional | Google One 2TB | Dropbox Plus | Self-Hosted Paperless-ngx |
|---|---|---|---|---|
| Monthly cost | $14.99/mo | $9.99/mo | $11.99/mo | From EUR 7.99/mo (Starter VPS) |
| Storage cap | 20 GB/mo upload | 2 TB | 2 TB | 100 GB+ (VPS disk) |
| OCR on all files | Partial | Partial | No | Yes (Tesseract, 100+ languages) |
| Full-text search | Yes | Yes | Limited | Yes |
| Auto-tagging rules | No | No | No | Yes (regex + ML) |
| Data leaves your server? | Yes | Yes | Yes | No |
| Export without reformatting | Partial | Partial | Yes | Yes (native files on disk) |
| Other services on same host | No | No | No | Nextcloud, Immich, etc. |
Prerequisites
Before you begin, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to your server
- At least 4 GB of RAM (8 GB recommended — OCR workers are memory-hungry on large PDFs)
- At least 50 GB of free disk space (documents plus PostgreSQL plus search index)
- A domain name pointed at your VPS (required for TLS in Step 12)
Recommended Plan: Starter>
For a single-household or small-team Paperless-ngx deployment, we recommend the Starter VPS plan:>
- 4 vCPU cores
- 8 GB RAM
- 100 GB NVMe SSD
- Unmetered bandwidth>
This leaves plenty of headroom for Paperless plus an Nginx reverse proxy, and the NVMe disk makes full-text search queries feel instant.
Connect to your server via SSH:
ssh root@your-server-ipStep 1: Update System Packages
Make sure the base system is fully patched before layering Docker on top.
sudo apt update && sudo apt upgrade -yIf the kernel was updated, reboot:
sudo rebootReconnect after a minute.
Step 2: Install Docker and Docker Compose
Paperless-ngx is distributed as a set of Docker images. The official docker-compose setup wires the webserver, workers, database, Redis, Gotenberg, and Tika containers together.
Install Docker using the official convenience script:
curl -fsSL https://get.docker.com | sudo shEnable and start Docker:
sudo systemctl enable --now dockerAdd your user to the docker group so you can run docker commands without sudo:
sudo usermod -aG docker $USERLog out and back in (or run newgrp docker) for the group change to take effect.
Verify the install:
docker --version
docker compose versionExpected output:
Docker version 27.3.1, build ce12230
Docker Compose version v2.29.7Step 3: Create the Paperless Directory Structure
Paperless-ngx needs a handful of persistent folders: one for the originals and archive, one for the search index, one for the consumption (drop-in) folder, and one for the PostgreSQL database.
sudo mkdir -p /opt/paperless/{data,media,export,consume,pgdata,redisdata}
sudo chown -R $USER:$USER /opt/paperless
cd /opt/paperlessQuick explanation of each folder:
data/— Paperless-ngx search index (Whoosh) and runtime statemedia/— Your original document files, archive PDFs, and thumbnails. Back this up!export/— Destination for scheduled document exportsconsume/— The watched folder. Any file dropped here is ingested automaticallypgdata/— PostgreSQL data directoryredisdata/— Redis persistence
Step 4: Write the docker-compose.yml
Create the Compose file that defines the six services Paperless-ngx needs.
nano /opt/paperless/docker-compose.ymlPaste the following:
services: broker: image: docker.io/library/redis:7 restart: unless-stopped volumes: - ./redisdata:/datadb: image: docker.io/library/postgres:16 restart: unless-stopped volumes: - ./pgdata:/var/lib/postgresql/data environment: POSTGRES_DB: paperless POSTGRES_USER: paperless POSTGRES_PASSWORD: paperless
webserver: image: ghcr.io/paperless-ngx/paperless-ngx:latest restart: unless-stopped depends_on: - db - broker - gotenberg - tika ports: - "127.0.0.1:8000:8000" volumes: - ./data:/usr/src/paperless/data - ./media:/usr/src/paperless/media - ./export:/usr/src/paperless/export - ./consume:/usr/src/paperless/consume env_file: docker-compose.env environment: PAPERLESS_REDIS: redis://broker:6379 PAPERLESS_DBHOST: db PAPERLESS_TIKA_ENABLED: 1 PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000 PAPERLESS_TIKA_ENDPOINT: http://tika:9998
gotenberg: image: docker.io/gotenberg/gotenberg:8 restart: unless-stopped command: - "gotenberg" - "--chromium-disable-javascript=true" - "--chromium-allow-list=file:///tmp/.*"
tika: image: docker.io/apache/tika:latest restart: unless-stopped
Save and exit.
A few things worth noting:
- The webserver binds to
127.0.0.1:8000only — external access will go through Nginx with TLS (Step 12). - Gotenberg has JavaScript disabled for security; it still converts Word, Excel, and HTML files fine.
- PostgreSQL 16 and Redis 7 are pinned to major versions — you control when upgrades happen.
Step 5: Configure docker-compose.env
The environment file holds the Paperless-specific settings. This is where you set the secret key, URLs, time zone, and OCR language.
nano /opt/paperless/docker-compose.envPaste the following, editing values marked CHANGE_ME:
# Generate with: openssl rand -base64 48
PAPERLESS_SECRET_KEY=CHANGE_ME_LONG_RANDOM_STRINGPublic URL (used in emails, links in the UI, etc.)
PAPERLESS_URL=https://paperless.yourdomain.comHost/domain whitelist — comma separated
PAPERLESS_ALLOWED_HOSTS=paperless.yourdomain.com,localhost
PAPERLESS_CORS_ALLOWED_HOSTS=https://paperless.yourdomain.comTime zone + OCR languages (ISO 639-2 codes; add deu, fra, spa etc. as needed)
PAPERLESS_TIME_ZONE=Europe/Berlin
PAPERLESS_OCR_LANGUAGE=engConsumption folder behaviour
PAPERLESS_CONSUMER_POLLING=0
PAPERLESS_CONSUMER_RECURSIVE=true
PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=trueTask workers (tune for CPU count)
PAPERLESS_TASK_WORKERS=2
PAPERLESS_THREADS_PER_WORKER=2Archive format
PAPERLESS_OCR_OUTPUT_TYPE=pdfaFilename format for archived originals
PAPERLESS_FILENAME_FORMAT={created_year}/{correspondent}/{title}Generate a strong secret key:
openssl rand -base64 48Copy the output into PAPERLESS_SECRET_KEY. Do not reuse a key from another install. If the secret key leaks, anyone can forge session cookies and impersonate any user.
Quick notes on the important variables:
PAPERLESS_SECRET_KEY— Django secret for signing sessions and tokens. Must be long, random, and kept private.PAPERLESS_URL— The public HTTPS URL where Paperless is reachable. Required for correct link generation inside the UI.PAPERLESS_OCR_LANGUAGE— Tesseract language packs to use.engis English; add others with+, e.g.eng+deu+fra.PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS— Iftrue, dropping a file intoconsume/invoices/2026/auto-applies theinvoicesand2026tags.PAPERLESS_FILENAME_FORMAT— Controls the on-disk layout of archived documents. The pattern above yields2026/Bank Of Example/January Statement.pdf.
Step 6: Run install-paperless-ngx.sh
At this point you could run docker compose up -d directly. For a reproducible setup, wrap it in a small installer script so you can re-run it on a new server without remembering the sequence.
nano /opt/paperless/install-paperless-ngx.shPaste:
#!/usr/bin/env bash set -euo pipefailcd "$(dirname "$0")"
if [ ! -f docker-compose.env ]; then echo "docker-compose.env not found. Copy and edit the template first." >&2 exit 1 fi
if grep -q "CHANGE_ME" docker-compose.env; then echo "docker-compose.env still contains CHANGE_ME placeholders. Edit it before installing." >&2 exit 1 fi
echo "==> Pulling images..." docker compose pull
echo "==> Starting stack..." docker compose up -d
echo "==> Waiting for webserver to become healthy..." for i in {1..60}; do if curl -fsS http://127.0.0.1:8000 >/dev/null 2>&1; then echo "Webserver is up." break fi sleep 2 done
echo echo "Install complete." echo "Next: create a superuser with ./install-paperless-ngx.sh superuser" echo
if [ "${1:-}" = "superuser" ]; then docker compose exec -it webserver python manage.py createsuperuser fi
Make it executable and run it:
chmod +x /opt/paperless/install-paperless-ngx.sh
/opt/paperless/install-paperless-ngx.shExpected output (abbreviated):
==> Pulling images...
[+] Pulling 6/6
✔ broker Pulled
✔ db Pulled
✔ gotenberg Pulled
✔ tika Pulled
✔ webserver Pulled
==> Starting stack...
✔ Container paperless-broker-1 Started
✔ Container paperless-db-1 Started
✔ Container paperless-gotenberg-1 Started
✔ Container paperless-tika-1 Started
✔ Container paperless-webserver-1 Started
==> Waiting for webserver to become healthy...
Webserver is up.
Install complete.Verify all six services are running:
docker compose psYou should see broker, db, gotenberg, tika, and webserver (the webserver itself spawns the consumer and worker processes internally).
Step 7: Create the Superuser
With the stack running, create your first admin account.
/opt/paperless/install-paperless-ngx.sh superuserOr directly:
cd /opt/paperless
docker compose exec -it webserver python manage.py createsuperuserYou will be prompted:
Username: admin
Email address: [email protected]
Password:
Password (again):
Superuser created successfully.Choose a strong password. This account has full control over every document and user in the system.
Step 8: First Login and the Consumption Folder
Paperless is listening on 127.0.0.1:8000, so from your VPS open an SSH tunnel from your workstation:
ssh -L 8000:127.0.0.1:8000 root@your-server-ipThen browse to http://localhost:8000 and log in with the superuser credentials. You'll land on the dashboard, which is empty.
The Consumption Folder
The consumption folder is the heart of the Paperless workflow. Anything dropped into /opt/paperless/consume/ (on the server) is ingested automatically — PDF, PNG, JPG, TIFF, DOCX, XLSX, HTML, and email (.eml) files are all supported.
Test it with a sample PDF:
# On your laptop
scp ~/some-invoice.pdf root@your-server-ip:/opt/paperless/consume/Within a few seconds you'll see a processing indicator in the web UI, followed by a new entry in the inbox with the extracted text indexed and searchable.
You can also use PAPERLESS_CONSUMER_SUBDIRS_AS_TAGS=true (set earlier) to pre-tag:
mkdir -p /opt/paperless/consume/invoices/2026
mv ~/january-bill.pdf /opt/paperless/consume/invoices/2026/The resulting document automatically picks up invoices and 2026 tags.
Step 9: Set Up Tags, Correspondents, and Document Types
Paperless organizes documents with three metadata layers, all accessible from the sidebar.
Correspondents — The entity a document is from or about. Your bank, your landlord, your accountant. Create one per recurring sender.
Document Types — The category of the document: Invoice, Receipt, Contract, Policy, Statement. Use a short controlled vocabulary; three to ten types covers most households.
Tags — Flexible labels. Unlike correspondents and types, a document can have many tags. Use them for status (needs-action, archived), project (home-renovation, tax-2026), or sensitivity (confidential).
Matching Rules
The real power comes from auto-matching. Every correspondent, type, and tag can carry a matching algorithm so new documents get classified automatically.
Auto for ML-style matching once you've trained on a dozen documents, or Match any word / Regex for deterministic rules.bank\sof\sexample and tick Case insensitive.From this point on, any new document containing that pattern in its OCR'd text auto-applies the correspondent. The same pattern works for document types and tags.
Pro tip: Start with regex rules (fast, predictable) and switch to Auto matching once you've classified 50+ documents manually — the classifier has enough training data to generalize.
Step 10: Configure OCR with Tesseract
OCR is already enabled by default. Paperless-ngx uses OCRmyPDF, which wraps Tesseract and produces searchable PDF/A archives.
Adding More Languages
If you deal with multilingual documents, add language packs. The image ships with English out of the box; for German, French, Spanish, and others, edit docker-compose.env:
PAPERLESS_OCR_LANGUAGE=eng+deu+fra+spaThe container auto-installs the Tesseract data files for each listed language on startup. Restart the webserver:
cd /opt/paperless
docker compose up -dOCR Quality Settings
Two variables control the quality/speed tradeoff:
# skip — do not OCR if PDF already has a text layer (fast)
redo — always re-OCR, discarding existing text (best quality, slowest)
force — OCR even image-based PDFs that have a partial text layer
PAPERLESS_OCR_MODE=skipResolution for rasterizing before OCR (higher = more accurate, slower)
PAPERLESS_OCR_IMAGE_DPI=300For receipts scanned with a phone, PAPERLESS_OCR_IMAGE_DPI=300 and PAPERLESS_OCR_MODE=skip is a good default. Bump DPI to 400 for handwritten notes.
Re-processing Existing Documents
If you change OCR settings and want to re-apply them to already-ingested documents:
docker compose exec webserver document_archiver --overwriteStep 11: Mobile Scanner Integration
The real convenience of Paperless-ngx shows up when you can scan a receipt from your phone and have it filed automatically by the time you get home.
Option A: Paperless Mobile App
The community Paperless Mobile app is available for Android and iOS. It talks directly to the Paperless REST API.
https://paperless.yourdomain.com
- Authentication: API token
From the app you can scan pages with the built-in camera (auto-crop, perspective correction), tag them, and upload — all in under 30 seconds per document.
Option B: Email-to-Paperless
Paperless can watch an IMAP mailbox and ingest attachments automatically. Add to docker-compose.env:
PAPERLESS_CONSUMER_RECURSIVE=trueThen in the web UI go to Settings > Mail and add an account:
- IMAP server:
imap.yourprovider.com - Username / password: credentials for a dedicated mailbox (create one just for this)
- Filter:
UNSEEN - Action: Mark as read
- Assign correspondent from:
From address
Option C: Sync Folder via Nextcloud or Syncthing
If you already run Nextcloud or Syncthing, point a sync folder at /opt/paperless/consume/. Scan an invoice with your phone's Nextcloud client, save it to the synced folder, and Paperless ingests it the moment it lands on the server.
Step 12: Nginx Reverse Proxy with TLS
So far Paperless is only reachable via SSH tunnel. For daily use you'll want a proper domain with HTTPS.
Install Nginx and Certbot:
sudo apt install -y nginx certbot python3-certbot-nginxCreate the site configuration:
sudo nano /etc/nginx/sites-available/paperlessPaste:
server { listen 80; server_name paperless.yourdomain.com; return 301 https://$host$request_uri; }server { listen 443 ssl http2; server_name paperless.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/paperless.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/paperless.yourdomain.com/privkey.pem;
# Security headers add_header X-Content-Type-Options nosniff; add_header X-Frame-Options SAMEORIGIN; add_header Referrer-Policy strict-origin-when-cross-origin;
# Large file uploads for document scans client_max_body_size 100m;
location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off; proxy_buffering off; proxy_read_timeout 300s; proxy_send_timeout 300s; } }
Enable the site and provision a certificate:
sudo ln -s /etc/nginx/sites-available/paperless /etc/nginx/sites-enabled/
sudo certbot --nginx -d paperless.yourdomain.com
sudo nginx -t && sudo systemctl reload nginxCertbot handles renewal automatically via a systemd timer. Verify:
sudo systemctl list-timers | grep certbotBrowse to https://paperless.yourdomain.com and log in. Mobile apps, the email connector, and team members can now reach Paperless from anywhere.
FAQ
How much disk space will Paperless-ngx use over time?
A typical household archiving 20-30 documents per month uses roughly 500 MB to 2 GB per year, depending on whether they're scanned at 300 DPI or higher and whether the originals are image-heavy PDFs. The media/ folder holds originals plus archive PDF/A versions (roughly double the original size). A 100 GB VPS disk comfortably holds decades of personal paperwork. Small businesses scanning hundreds of invoices a month should plan 10-20 GB per year and budget for block storage expansion once the VPS fills up.
Is Paperless-ngx safe for legal and medical documents?
Yes, when configured correctly — which is the point of self-hosting. Store the server in a jurisdiction you trust, put it behind TLS (Step 12), enable two-factor authentication in the UI (Settings > Users > Edit > Enable TOTP), restrict SSH to key-based auth, and run regular encrypted backups of /opt/paperless/media and the PostgreSQL volume. For regulated environments (HIPAA, GDPR with special categories), add full-disk encryption to the VPS and restrict API access to a VPN.
How do I back up Paperless-ngx?
The two irreplaceable things are the media/ folder (originals and archive PDFs) and the PostgreSQL database (metadata, tags, correspondents, user accounts). The Paperless maintainers recommend using document_exporter, which writes everything as plain files plus a manifest:
cd /opt/paperless
docker compose exec webserver document_exporter ../exportRun that on a nightly cron, then rsync /opt/paperless/export to offsite storage (S3, Backblaze B2, or a second VPS). To restore, run document_importer against the export directory on a fresh install — everything comes back.
Can I run Paperless-ngx alongside Nextcloud or Immich on the same VPS?
Yes, and it's a common setup. Nextcloud handles general file sync and office collaboration, Immich handles photos, and Paperless handles documents. On a Starter VPS (4 vCPU / 8 GB RAM) you can run all three comfortably; each lives in its own Docker Compose project and its own Nginx vhost. Point a Nextcloud external storage mount at /opt/paperless/consume and you get mobile-to-Paperless ingestion for free.
What happens if Paperless-ngx goes away or stops being maintained?
Paperless-ngx is a community fork that already replaced the original Paperless project, so continuity is baked into the model — if the current maintainers step back, another fork takes over. More importantly, your documents are not locked in. The media/ folder contains plain PDFs organized by the filename format you chose. If you ever wanted to walk away, you copy that directory to any cloud storage and you still have every document, correctly named and foldered. The metadata layer (tags, correspondents) lives in PostgreSQL and can be exported to JSON with document_exporter.
How does Paperless-ngx's OCR compare to cloud services like Google Drive?
Tesseract (Paperless's OCR engine) is the same engine that powers many commercial services under the hood. For clean, printed documents, accuracy is effectively identical to Google Drive's OCR — in the 98-99% range. For messy receipts, faded carbon copies, and handwriting, cloud services with ML-based OCR (Google Cloud Vision, AWS Textract) do pull ahead. If you rely on scanning a lot of handwritten notes, you can configure Paperless-ngx to call an external OCR service via webhook, but for the typed documents that make up 99% of most archives, Tesseract is excellent and has the benefit of running fully offline.
How do I add more workers for faster ingestion?
The two variables to tune are PAPERLESS_TASK_WORKERS and PAPERLESS_THREADS_PER_WORKER in docker-compose.env. The effective parallelism is the product. On a 4 vCPU server, 2 workers x 2 threads = 4 is a good default. OCR is the bottleneck — each OCR task pins one core for 5-30 seconds depending on page count. If you're about to ingest a large historical backlog (say, 10 years of tax returns), temporarily bump workers to match your CPU count, ingest everything, then scale back.
Next Steps
Paperless-ngx is running and serving documents over HTTPS. Here are a few ways to extend it:
- Set up Nextcloud alongside — Use Nextcloud as the "front door" sync app on your phone and point a folder at
/opt/paperless/consume/. Scan with Nextcloud, archive with Paperless. - Run Immich on the same VPS — Photos into Immich, documents into Paperless. Both are self-hosted Google Photos/Drive alternatives that work well together.
- Automate imports from email — Dedicate a mailbox (e.g.,
[email protected]), point Paperless at it, and forward every digital receipt you get. Zero manual filing. - Write custom filters and saved views — Create saved searches like "Invoices due this month" using the advanced query syntax, then pin them to your dashboard.
- Monitor the stack with Uptime Kuma — Health-check
https://paperless.yourdomain.comand alert via email or Telegram if the webserver goes down. - Read the official documentation — The full feature reference lives at docs.paperless-ngx.com. Advanced topics include LDAP auth, S3-backed media storage, and Paperless's REST API.
Deploy Paperless-ngx on a VPS Built for Self-Hosting>
Our Starter VPS comes with NVMe SSD, unmetered bandwidth, and the headroom to run Paperless-ngx plus Nextcloud, Immich, and more — all on one machine.>
- 4 vCPU / 8 GB RAM / 100 GB NVMe
- Ubuntu 24.04 LTS pre-installed
- Full root access, Docker ready in minutes
- 24/7 support from engineers who self-host too>
Launch Your Starter VPS and follow this guide end to end.