Paperless-ngx is an open-source document management system that converts scans and PDFs into a fully searchable archive using Tesseract OCR, with tags, custom fields, and automated processing rules. This guide deploys Paperless-ngx using Docker Compose with PostgreSQL, Redis, and Traefik handling automatic HTTPS, then uploads a document and verifies OCR extraction. By the end, you'll have Paperless-ngx serving an OCR-indexed document archive securely at your domain.
Set Up the Directory Structure
1. Create the project directories:
$ mkdir -p ~/paperless-ngx/{data,media,export,consume,pgdata}
$ cd ~/paperless-ngx
2. Create the environment file:
$ nano .env
DOMAIN=paperless.example.com
LETSENCRYPT_EMAIL=admin@example.com
PAPERLESS_SECRET_KEY=CHANGE_TO_RANDOM_STRING
PAPERLESS_URL=https://paperless.example.com
PAPERLESS_TIME_ZONE=UTC
PAPERLESS_OCR_LANGUAGE=eng
PAPERLESS_DBPASS=STRONG_PASSWORD_HERE
POSTGRES_DB=paperless
POSTGRES_USER=paperless
POSTGRES_PASSWORD=STRONG_PASSWORD_HERE
Use the same value for PAPERLESS_DBPASS and POSTGRES_PASSWORD. PAPERLESS_SECRET_KEY should be a 32+ character random string.
Deploy with Docker Compose
1. Create the Compose manifest:
$ nano docker-compose.yaml
services:
traefik:
image: traefik:v3.6
container_name: traefik
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
restart: unless-stopped
db:
image: postgres:16
container_name: paperless-db
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- "./pgdata:/var/lib/postgresql/data"
healthcheck:
test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}", "-d", "${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:7
container_name: paperless-redis
restart: unless-stopped
paperless:
image: ghcr.io/paperless-ngx/paperless-ngx:2.20.6
container_name: paperless
depends_on:
db:
condition: service_healthy
environment:
PAPERLESS_REDIS: redis://redis:6379
PAPERLESS_DBHOST: db
PAPERLESS_SECRET_KEY: ${PAPERLESS_SECRET_KEY}
PAPERLESS_URL: ${PAPERLESS_URL}
PAPERLESS_TIME_ZONE: ${PAPERLESS_TIME_ZONE}
PAPERLESS_OCR_LANGUAGE: ${PAPERLESS_OCR_LANGUAGE}
PAPERLESS_DBPASS: ${PAPERLESS_DBPASS}
volumes:
- "./data:/usr/src/paperless/data"
- "./media:/usr/src/paperless/media"
- "./export:/usr/src/paperless/export"
- "./consume:/usr/src/paperless/consume"
expose:
- "8000"
labels:
- "traefik.enable=true"
- "traefik.http.routers.paperless.rule=Host(`${DOMAIN}`)"
- "traefik.http.routers.paperless.entrypoints=websecure"
- "traefik.http.routers.paperless.tls.certresolver=letsencrypt"
- "traefik.http.services.paperless.loadbalancer.server.port=8000"
restart: unless-stopped
2. Start the services:
$ docker compose up -d
$ docker compose ps
$ docker compose logs
3. Create a superuser inside the Paperless container:
$ docker compose exec -it paperless python3 manage.py createsuperuser
Follow the prompts for username, email, and password.
Upload a Document and Verify OCR
- Open
https://paperless.example.comand sign in with the superuser. - Click Upload documents at the top right and pick a PDF or image.
- Wait 5–30 seconds for Paperless to OCR the document.
- Click the thumbnail, then the Content tab — the extracted text appears alongside the document preview.
Next Steps
Paperless-ngx is running with PostgreSQL persistence and Tesseract OCR. From here you can:
- Set up the Consume folder for automatic ingestion of scans dropped via SFTP or a scanner watch folder
- Add tags, correspondents, document types, and storage paths for auto-classification
- Enable additional OCR languages by adding ISO codes to
PAPERLESS_OCR_LANGUAGE(e.g.eng+deu+fra)
For the full guide with additional tips, visit the original article on Vultr Docs.
Top comments (0)