Self-Hosted Services and ProductivityDocs and File WorkflowsIntermediate2-4 hoursLab

Create a Paperless-ngx Document Workflow with OCR and Restore Validation

Deploy a small Paperless-ngx Lab from the project's maintained Docker Compose files, ingest and OCR a test document, then use the supported document exporter/importer workflow to...

Last reviewed8/19/2026
Paperless document workflowsOCRbackup validation
Docker Compose v2Paperless-ngxOCRSQLite LabLinux

Expected Outcome

A working Paperless-ngx Lab with a searchable test document, a version-matched full export, and a documented restore rehearsal using the supported document importer.

Assumptions

  • A Linux host with Docker Engine and the Docker Compose v2 plugin.

  • At least 2 GB of free RAM and sufficient storage for documents plus exports.

  • A scanner or test PDF/image to place in the consumption directory.

  • A backup destination outside the live Paperless Docker volumes.

  • This Lab uses the project's SQLite Compose file to keep the recovery exercise small; Paperless-ngx recommends PostgreSQL for new durable installations.

Bill of Materials

  • Paperless-ngx maintained Compose files from the official repository.

  • One disposable test document with recognizable text.

  • A location where the generated `export` directory can be copied off-host.

Build Steps

  1. Verify Docker Compose and create the Lab directory

    Use Compose v2. Do not install the retired standalone docker-compose executable just for this Lab.

    Changes system state: review before running

    docker --version
    docker compose version
    mkdir -p ~/paperless-lab && cd ~/paperless-lab
  2. Download the maintained Paperless-ngx Compose files

    Download the official SQLite Compose definition, Docker environment template, and project .env as files for review. This avoids executing the project's convenience installer through a remote shell and keeps the exact configuration used by the Lab visible.

    Read-only command: verify target and scope

    curl -fLo docker-compose.yml https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.sqlite.yml
    curl -fLo docker-compose.env https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/docker-compose.env
    curl -fLo .env https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/docker/compose/.env
    sed -n '1,220p' docker-compose.yml
    sed -n '1,220p' docker-compose.env
  3. Set the required application secret and local identity mapping

    The current Docker environment template requires a unique PAPERLESS_SECRET_KEY. Generate one locally and set UID/GID values so the host user and container can work with the consumption/export directories. Preserve the reviewed configuration as part of your recovery evidence.

    Security-sensitive: review before running

    SECRET=$(python3 -c 'import secrets; print(secrets.token_urlsafe(64))')
    sed -i "s|^PAPERLESS_SECRET_KEY=.*|PAPERLESS_SECRET_KEY=$SECRET|" docker-compose.env
    printf '\nUSERMAP_UID=%s\nUSERMAP_GID=%s\n' "$(id -u)" "$(id -g)" >> docker-compose.env
    chmod 600 docker-compose.env
    docker compose config --quiet
  4. Pull and start Paperless-ngx

    Use the maintained Compose definition. The container image already includes the OCR tooling needed by Paperless-ngx; installing a second Tesseract package on the host does not configure OCR inside the container.

    Changes system state: review before running

    docker compose pull
    docker compose up -d
    docker compose ps
    docker compose logs webserver --tail=80
  5. Create the first user and ingest one test document

    Open the local Paperless-ngx web interface and create the first account when prompted. Copy one disposable PDF or image into the host consume directory that the official Compose file mounts into the container, then watch the task complete.

    Changes system state: review before running

    cp '<test-document>' ./consume/
    docker compose logs webserver --since=5m
  6. Validate OCR and document retrieval

    In the Paperless UI, confirm the test document appears, its extracted text contains a known phrase from the source, and searching for that phrase returns the document. This is the functional boundary for OCR; container health alone is not enough.

  7. Create a supported full export

    Paperless-ngx documents the document_exporter as a backup/migration path that includes documents, thumbnails, metadata, and database contents. Avoid replacing this with a blind rsync --delete of live application directories. Make sure Paperless is not actively consuming documents while the export runs.

    Read-only command: verify target and scope

    docker compose exec -T webserver document_exporter ../export --compare-checksums --no-progress-bar

    Manual or UI step

    • find ./export -maxdepth 2 -type f | head -50

    • test -f ./export/manifest.json && echo 'Manifest present'

  8. Record the running Paperless version with the export

    Capture the image/container version evidence beside the export so a future restore can use a compatible application version.

    Read-only command: verify target and scope

    docker compose images > ./export/container-images.txt
    docker compose exec -T webserver document_exporter --help | head -20 > ./export/exporter-help.txt

    Manual or UI step

    • tar -C . -czf paperless-export-$(date +%Y%m%d-%H%M%S).tar.gz export

  9. Rehearse the importer in an isolated copy

    A true restore test should not overwrite the live Lab. Create a second disposable Paperless environment at the same application version, place a copy of the export into its mounted export directory, and run document_importer ../export. Confirm the restored account metadata and test document appear. The exact isolated Compose paths depend on where you choose to stage the second instance, so keep this as a deliberate recovery exercise rather than running an importer against the live database.

Validation

  • The Paperless-ngx containers are healthy under `docker compose ps`.

  • The test document is consumed, OCR text is searchable, and the original document remains retrievable.

  • The export contains `manifest.json` plus document/metadata artifacts and is copied or archived outside the live application volumes.

  • The Paperless container/image version used to create the export is recorded with the backup.

  • A disposable matching-version instance can import the export with `document_importer` and recover the test document.

Troubleshooting

  • If documents remain in `consume`, inspect webserver logs and verify host UID/GID mapping, file permissions, and whether the consumption directory supports the filesystem notification behavior Paperless expects.

    Read-only command: verify target and scope

    ls -la ./consume
    docker compose logs webserver --tail=150
  • If OCR results are poor, check the configured OCR language inside Paperless before installing host-side Tesseract packages. Additional OCR languages are configured through `docker-compose.env` and installed in the container environment.

  • If an import fails after an application upgrade, verify the restore instance matches the version that created the export before attempting ad hoc database manipulation.

Cleanup or Rollback

  • Keep the exported recovery artifact before removing the Lab if you intend to retain its documents.

  • Stop a disposable Lab with `docker compose down`; do not add `-v` unless you have explicitly decided to destroy the Paperless data/media volumes.

  • Remove test documents and any isolated restore instance only after the recovery evidence has been recorded.

Next Improvements

  • Use the current PostgreSQL Compose path for a longer-lived installation, as recommended by Paperless-ngx for new deployments.

  • Schedule `document_exporter` during a quiet period and replicate the export to independent storage with retention.

  • Repeat a version-matched restore rehearsal after meaningful upgrades or backup-process changes.

References

Keep Moving

Build on what you just completed

Continue with a related Lab or return to this build path for a different implementation.