Paperless-ngx turns a pile of paper (and a downloads folder full of PDFs) into a searchable archive. Drop in a scan and it reads the text with OCR, guesses the correspondent, date and document type, and files it with tags. A year later, finding "that insurance letter from March" takes three seconds.
Prerequisites
- Docker Engine and the Compose plugin
- Nginx Proxy Manager running from
/opt/npmif you want HTTPS access - About 2 GB of RAM free. OCR is the hungry part, mostly while documents are being processed.
1. Download the official Compose files
Paperless publishes ready-made Compose files. I use the PostgreSQL variant:
sudo mkdir -p /opt/paperless
cd /opt/paperless
BASE=https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose
sudo curl -fsSL $BASE/docker-compose.postgres.yml -o docker-compose.yml
sudo curl -fsSL $BASE/docker-compose.env -o docker-compose.env
sudo curl -fsSL $BASE/.env -o .env
That gives you three services: a Redis broker, a Postgres database and the Paperless web server, with named volumes for their data and two folders next to the file. consume is the inbox, where anything you drop in gets imported. export is where backups go.
2. Make two edits to the Compose file
Open docker-compose.yml. Under the webserver service, change the published port so it's localhost-only:
ports:
- "127.0.0.1:8000:8000"
And add Paperless to NPM's network so the proxy can reach it, under webserver:
networks:
- default
- npm
plus, at the very bottom of the file:
networks:
npm:
external: true
name: npm_default
3. Set the important options
Edit docker-compose.env and set (uncommenting where needed):
PAPERLESS_URL=https://docs.example.com
PAPERLESS_SECRET_KEY=paste-a-long-random-string-here
PAPERLESS_TIME_ZONE=America/Denver
PAPERLESS_OCR_LANGUAGE=eng
USERMAP_UID=1000
USERMAP_GID=1000
Generate the secret key with openssl rand -base64 48. USERMAP_UID/GID should match your own user (id tells you), so files in consume and export are owned by you rather than root.
4. Start it and create the admin account
sudo docker compose pull
sudo docker compose up -d
On your own computer:
ssh -L 8000:localhost:8000 your-user@your-server-ip
# then open http://localhost:8000
The first visit asks you to create the superuser (admin) account. Then upload a test PDF with the upload button and watch it appear with its text recognized, usually within a minute.
5. HTTPS and a good first setup
In NPM, add a proxy host for docs.example.com → http · webserver · 8000 (that's the service name in the official file) with an SSL certificate and Force SSL. Make sure it matches the PAPERLESS_URL you set.
Before importing hundreds of documents, create a few correspondents (your bank, your insurer, your employer) and tags (taxes, house, car). Paperless learns from how you file the first batch and starts auto-assigning them, so ten minutes of tidy filing up front pays off for years.
6. Updates and backups
cd /opt/paperless
sudo docker compose pull && sudo docker compose up -d
Backups: use the built-in document exporter, which the project recommends. It writes every document, plus all your tags, correspondents and settings, into the export folder in a format that can be imported into a fresh install:
cd /opt/paperless
sudo docker compose exec -T webserver document_exporter ../export
Schedule that nightly with cron, then copy export off the server, ideally encrypted, because this folder is your tax returns and contracts. My Google Drive backup setup encrypts before upload for exactly this reason.
Troubleshooting
- Documents sit in
consumeand never import: usually permissions.USERMAP_UID/GIDmust be able to read the files. Checksudo docker compose logs webserver. - "CSRF verification failed" when logging in through the domain:
PAPERLESS_URLdoesn't exactly match the address in your browser. - OCR text is gibberish: the wrong
PAPERLESS_OCR_LANGUAGE, or a low-resolution scan. Scan at 300 DPI.
Official documentation: Paperless-ngx docs · Repository: paperless-ngx/paperless-ngx