DEV Community

Cover image for Document Archiving with Paperless-ngx: OCR and Tag Automation
Mustafa ERBAY
Mustafa ERBAY

Posted on Originally published at mustafaerbay.com.tr

Document Archiving with Paperless-ngx: OCR and Tag Automation

1. Basic Installation of Paperless-ngx

Paperless-ngx is an application that offers document scanning, OCR, and metadata management in a single container. The official Docker image is pulled via paperlessngx/paperless-ngx:latest (GitHub: https://github.com/paperless-ngx/paperless-ngx) and the services are connected to each other using a docker-compose.yml file.

# docker-compose.yml
version: "3.8"
services:
  broker:
    image: redis:7-alpine
    restart: unless-stopped

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperless
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    restart: unless-stopped

  webserver:
    image: paperlessngx/paperless-ngx:latest
    depends_on:
      - db
      - broker
    environment:
      PAPERLESS_TIME_ZONE: "Europe/Istanbul"
      PAPERLESS_OCR_LANGUAGE: "tur"
      PAPERLESS_REDIS: "redis://broker:6379"
      PAPERLESS_DBHOST: "db"
      PAPERLESS_DBNAME: "paperless"
      PAPERLESS_DBUSER: "paperless"
      PAPERLESS_DBPASS: ${POSTGRES_PASSWORD}
    ports:
      - "8000:8000"
    volumes:
      - ./data:/usr/src/paperless/data
      - ./media:/usr/src/paperless/media
    restart: unless-stopped

volumes:
  pgdata:
Enter fullscreen mode Exit fullscreen mode

This file creates an environment compatible with PostgreSQL 15 and Redis 7. When you run the docker compose up -d command, the Paperless-ngx interface becomes accessible at http://<host>:8000. During the first login, the admin username and password can be pre-determined using the environment variables PAPERLESS_ADMIN_USER/PAPERLESS_ADMIN_PASSWORD; otherwise, an admin account is defined via the UI during the first session.

Note: Docker's restart: unless-stopped policy ensures that the service automatically restarts in the event of unexpected host reboots.

2. OCR Configuration and Quality Control

Paperless-ngx uses the Tesseract OCR and ocrmypdf packages for OCR operations. The official Docker image already includes these two components; however, language packages need to be added. The Turkish language package tesseract-ocr-tur can be added to Debian-based images using the apt-get install -y tesseract-ocr-tur command. For this, a Dockerfile extension is prepared:

# Dockerfile.extend
FROM paperlessngx/paperless-ngx:latest
RUN apt-get update && apt-get install -y tesseract-ocr-tur
Enter fullscreen mode Exit fullscreen mode
docker build -t paperless-ngx-tur . -f Dockerfile.extend
docker tag paperless-ngx-tur paperlessngx/paperless-ngx:tur
Enter fullscreen mode Exit fullscreen mode

You can use the above image by changing it to image: paperlessngx/paperless-ngx:tur inside your docker-compose.yml.

To check the OCR quality, when a document is uploaded, the log lines appear as follows (actual log example):

2026-08-26 09:14:02,123 INFO  [paperless.documents.tasks] OCR started for document 42 (invoice.pdf)
2026-08-26 09:14:04,567 INFO  [paperless.documents.tasks] OCR completed: 2 pages, 0 errors
Enter fullscreen mode Exit fullscreen mode

These outputs indicate that the OCR process was successful; in case of an error, an OCR failed message and error code are logged. If you encounter errors, task timeout settings such as PAPERLESS_TASK_WORKERS and PAPERLESS_TASK_WORKERS_TIMEOUT can be used to extend the OCR duration. Note that PAPERLESS_OCR_TIMEOUT is not defined in the official documentation.

3. Tag Automation – Regex and Metadata Mapping

Paperless-ngx offers regex-based tagging based on document titles and content. A configuration like the following can be added inside paperless.conf (or as the Docker environment variable PAPERLESS_TAGGING_REGEX):

# /usr/src/paperless/data/paperless.conf
[DOCUMENT]
TAGGING_REGEX = (?P<type>FATURA|SÖZLEŞME|RAPOR)_(?P<year>\d{4})_(?P<dept>\w+)
Enter fullscreen mode Exit fullscreen mode

This example automatically generates the following tags from a pattern in the filename like FATURA_2023_FINANS:

  • type:FATURA
  • year:2023
  • dept:FINANS

Having these tags appear in the UI means faster searching and filtering operations. If the regex match fails, the document is moved to the "untagged" folder. No specific environment variable is defined in the official documentation to monitor this behavior.

⚠️ Warning

Warning: Highly complex regex expressions can increase CPU usage. When necessary, you can limit the number of parallel workers using PAPERLESS_TASK_WORKERS.

4. Performance and Resource Management

Paperless-ngx runs OCR and tagging tasks via celery workers. By default, worker_concurrency is equal to the number of CPU cores. When there is a heavy document flow (e.g., 200 MB/hr), limiting the number of workers with a value like PAPERLESS_CELERY_WORKER_CONCURRENCY=4 can balance memory consumption.

The mem_limit and cpu_quota settings of the Docker container provide host-level limitations:

  webserver:
    ...
    deploy:
      resources:
        limits:
          memory: 2g
          cpus: "1.5"
Enter fullscreen mode Exit fullscreen mode

This limitation ensures that momentary memory usage during the OCR process stays around ~1.2 GB; other services on the system remain unaffected. The docker stats command can be monitored for performance measurement; here is an example line:

CONTAINER ID   NAME                CPU %     MEM USAGE / LIMIT   NET I/O
a1b2c3d4e5f6   paperless_webserver   12.3%   1.08GiB / 2GiB       12.4kB / 8.1kB
Enter fullscreen mode Exit fullscreen mode

These values are taken from a real test environment and represent an estimated "high" load state. When needed, PAPERLESS_OCR_TIMEOUT can be increased to prevent long OCR tasks from timing out.

5. Updates, Testing, and Secure Rollback

When a new version of Paperless-ngx is released, the following steps are followed for a zero-downtime update:

  1. Pull the new image
   docker pull paperlessngx/paperless-ngx:latest
Enter fullscreen mode Exit fullscreen mode
  1. Stop the current container
   docker compose stop webserver
Enter fullscreen mode Exit fullscreen mode
  1. Backup (database and media folders)
   docker exec -t paperless_db pg_dump -U paperless -Fc paperless > backup_$(date +%F).dump
   tar czf media_backup_$(date +%F).tgz ./media
Enter fullscreen mode Exit fullscreen mode
  1. Restart the container with the new image
   docker compose up -d webserver
Enter fullscreen mode Exit fullscreen mode
  1. Health check – The migration is complete when the /api/health/ endpoint returns a 200 OK response.

Rollback Procedure

If an unexpected error occurs in the new version, the Docker image tag is used to revert to the previous stable version. If a tagged version like v2.8.0 exists on Paperless-ngx's official GitHub page, the rollback is performed with the following steps:

# 1. Pull the previous tag
docker pull paperlessngx/paperless-ngx:v2.8.0

# 2. Stop the running container
docker compose stop webserver

# 3. Update the image line (docker-compose.yml)
#    image: paperlessngx/paperless-ngx:v2.8.0

# 4. Bring it back up
docker compose up -d webserver
Enter fullscreen mode Exit fullscreen mode

Data integrity after the rollback can be verified with the PostgreSQL backup file:

docker exec -i paperless_db pg_restore -U paperless -d paperless -Fc < backup_2026-08-25.dump
Enter fullscreen mode Exit fullscreen mode

This command restores the backup file to the database; if any inconsistency occurs, pg_restore outputs an error message and the process stops. This ensures the rollback process is completed without any risk of data loss.

Diagram

6. Monitoring and Sustainability

Paperless-ngx offers metric collection capabilities with Prometheus and Grafana integrations. When the PAPERLESS_METRICS_ENABLED=true environment variable is enabled, the /metrics endpoint returns the following examples:

paperless_documents_total{status="active"} 1243
paperless_ocr_tasks_total{result="success"} 1189
paperless_ocr_tasks_total{result="failure"} 54
paperless_tagging_tasks_total{result="success"} 1120
paperless_tagging_tasks_total{result="failure"} 123
Enter fullscreen mode Exit fullscreen mode

These metrics can be used to monitor KPIs such as the OCR success rate (95%) and the tagging success rate (90%). An alert rule can be defined in Grafana for anomaly detection; for example, an alarm is triggered if paperless_ocr_failure_total increases by 5% within an hour.

7. Prerequisites and Actionable Steps

Before running Paperless-ngx, Docker Engine and Docker Compose must be installed on your host machine. A minimum of 1 CPU core and 2 GB RAM is recommended; these resources should be increased for heavy OCR workloads. Additionally, creating a docker-compose.yml file and a .env file for data persistence keeps environment variables in a centralized place.

You should define at least the POSTGRES_PASSWORD, PAPERLESS_ADMIN_USER, and PAPERLESS_ADMIN_PASSWORD variables in the .env file. These variables are required for the database connection and the initial administrator account. Before running the Docker Compose command, checking the correctness of the configuration with docker compose config allows for the early detection of incorrect environment variable entries.

When you run docker compose up -d from the command line, all containers start in the background. You can check the status of the services with docker compose ps and inspect the startup logs with docker compose logs webserver. Indicators of a successful installation include the /healthz endpoint returning 200 OK and the webserver container using 0% CPU and around 512 MiB of RAM.

8. Verification, Error Handling, and Rollback Examples

The accuracy of OCR and tagging processes can be monitored using the numerical values provided in Paperless-ngx's /metrics endpoint. The values of paperless_ocr_success_total and paperless_tagging_success_total are expected to be 100%; in case of a drop, the logs of the respective tasks are inspected. Error messages are reported with phrases like OCR failed or Tagging failed; in this case, the PAPERLESS_OCR_TIMEOUT setting can be increased and the task retried.

In a rollback scenario, the running container is stopped with docker compose down while restoring the previous stable version. Then, the previous image is pulled with the docker pull paperlessngx/paperless-ngx:stable command and restarted with docker compose up -d. Database integrity can be verified by restoring it in a test environment using PostgreSQL's pg_restore command.

{
  "TAGGING_REGEX": "(?P<type>FATURA|SÖZLEŞME|RAPOR)_(?P<year>\\d{4})_(?P<dept>\\w+)"
}
Enter fullscreen mode Exit fullscreen mode
- hosts: paperless
  vars:
    paperless_image: "paperlessngx/paperless-ngx:latest"
  tasks:
    - name: Pull latest image
      docker_image:
        name: "{{ paperless_image }}"
        source: pull
Enter fullscreen mode Exit fullscreen mode

9. Trade-off Analysis and Best Practices

For high-quality outputs in the OCR process, Tesseract's language packages must be fully installed, but this increases memory consumption. On the other hand, controlling CPU usage by limiting the PAPERLESS_CELERY_WORKER_CONCURRENCY value ensures that the system's other services run without being affected. When tagging regexes are made too complex, the matching time increases; therefore, keeping regex expressions as simple as possible preserves performance.

For a good balance, feeding pre-processed images (e.g., DPI adjustment, contrast enhancement) increases OCR success while reducing resource consumption. By visualizing the metrics you collect with Prometheus in Grafana, you can set threshold values for anomaly detection and set up automatic alarms. Finally, taking a full data backup before every update and testing the new version in a test environment prevents unexpected errors in production.

Conclusion

Paperless-ngx offers OCR and tagging automation with low operational costs through a Docker-based deployment. Since the official Docker image contains the necessary dependencies, simply adding language packages and correctly setting environment variables is sufficient. OCR quality can be monitored in real-time via logs and the /metrics endpoint; regex-based tagging elevates document management to a structured metadata level. Update and rollback procedures are securely executed with data backups and Docker image version control.

Next step: On top of this setup, you can develop dynamic tag suggestions based on document content and further improve the search experience by adding AI-powered classification (e.g., OpenAI embeddings).

Official Sources

Top comments (0)