Paperless-NGX Maintenance: Routine Updates and Major Stack Upgrades

This article documents the process for updating and upgrading the Paperless-NGX stack. This covers everything from simple container image updates to complex major version upgrades of backend services like PostgreSQL.

Part I: Routine Maintenance

Updating Paperless-NGX itself and its stateless dependencies is simple. I installed it to /opt/paperless, so I always execute the following commands under the dedicated unprivileged user.

Stopping, Pulling, and Restarting

The process involves stopping all containers, pulling new images, and bringing the stack back up.

# 1. Stop all containers
~:/opt/paperless/paperless-ngx# sudo -Hu paperless docker compose down
[+] Running 6/6
 ✔ Container paperless-webserver-1  Removed                              6.2s 
 ✔ Container paperless-db-1         Removed                              0.3s 
... (remaining container removal output)
 ✔ Network paperless_default        Removed                              0.2s 

# 2. Update/Pull latest images
~:/opt/paperless/paperless-ngx# sudo -Hu paperless docker compose pull   
[+] Pulling 15/15
 ✔ db Pulled                                                             1.0s 
... (Detailed output confirming image downloads)
 ✔ gotenberg 10 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿]      0B/0B      Pulled          48.6s 
...

# 3. Starting the stack (The -d detaches the process)
~:/opt/paperless/paperless-ngx# sudo -Hu paperless docker compose up -d
[+] Running 5/5
 ✔ Container paperless-db-1         Started                              0.5s 
... (Output confirming all services started)

Part II: Major Version Upgrades

Upgrading major services (e.g., PostgreSQL or Gotenberg) requires changing the container image tag in docker-compose.yml and executing a specific data migration procedure.

Database Upgrade Strategy

For PostgreSQL (e.g., v15 to v16), I identified three primary variants for handling the underlying database file format change:

  1. Variant 1 (Dumps): Dump the old database, upgrade the image, and import the dump.
  2. Variant 2 (App Export/Import): Use Paperless-NGX’s built-in exporter/importer. (My preferred clean strategy).
  3. Variant 3 (pg_upgrade): Use the official PostgreSQL tool. (Complex, but efficient for very massive databases).

Recommendation: Before proceeding with any major version upgrade, check if the new versions are officially supported by Paperless-NGX, and create a full snapshot or backup.

Variant 2: Application Export/Import

This variant is often the cleanest way to upgrade, as the application handles the data transfer logic.

1. Create Backup and Export Documents

# Export documents via the webserver container
~:/opt/paperless/paperless-ngx# sudo -Hu paperless docker compose exec -T webserver document_exporter ../export 
100%|██████████| 1004/1004 [00:07<00:00, 126.43it/s]

root@paperless:/opt/paperless/paperless-ngx# du -sh export 
986M    export

2. Modify Stack Versions

I update the image: tags in docker-compose.yml to the desired new versions:

# Example modifications in docker-compose.yml
image: docker.io/library/postgres:16
image: docker.io/gotenberg/gotenberg:8

3. CRITICAL STEP: Volume Isolation

To ensure the new PostgreSQL container initializes a clean, compatible database, the old volume data must be isolated. This is the manual, atomic volume management step.

# Manually rename the old volumes for a clean start:
cd /var/lib/docker/volumes
mv paperless_media paperless_media_backup
mkdir -p paperless_media/_data
mv paperless_pgdata paperless_pgdata_backup
mkdir -p paperless_pgdata/_data

4. Start and Import Data

The new environment starts up with the fresh PostgreSQL 16 database.

# Start the new environment
~:/opt/paperless/paperless-ngx# sudo -Hu paperless docker compose up -d
... (Success output)

# Import the data into the clean database
~:/opt/paperless/paperless-ngx# sudo -Hu paperless docker compose exec -T webserver document_importer ../export
Checking the manifest
Installed 1278 object(s) from 1 fixture(s)
Copy files into paperless...
100%|██████████| 1004/1004 [00:16<00:00, 62.37it/s]
Updating search index...
100%|██████████| 1004/1004 [00:24<00:00, 41.64it/s]

Part III: Automation and Operational Considerations

Automation Script (Example Cronjob)

For simple minor version updates (where latest tags are used and volumes are untouched), this script provides basic automation.

#!/bin/bash

set -e 

# Simple script to stop, pull, and restart the stack
PDIR=/opt/paperless/paperless-ngx
LOG=/opt/paperless/docker-compose-cron.log

# Stop all containers and pull if successful
/usr/bin/docker compose down >> $LOG 2>&1 && /usr/bin/docker compose pull >> $LOG 2>&1

# Start all containers
/usr/bin/docker compose up --wait -d >> $LOG 2>&1

Note: Automating major version upgrades (requiring volume management) must always be performed manually.

Operational Pitfalls

It is crucial to verify the integrity of the stack after any upgrade. Issues like compatibility problems between new versions of supporting services (e.g., Gotenberg) and Paperless-NGX confirm that manual verification after a major upgrade is mandatory.

Sources / See Also

  1. Paperless-NGX Documentation. Upgrade Guide. https://docs.paperless-ngx.com/upgrade/
  2. Docker Documentation. Docker Compose Upgrade and Maintenance. https://docs.docker.com/compose/compose-file/08-upgrade/
  3. PostgreSQL Documentation. Major PostgreSQL Version Upgrades. https://www.postgresql.org/docs/current/upgrading.html
  4. GitHub Repository paperless-ngx/paperless-ngx. Discussions on Gotenberg Compatibility and Database Schema. https://github.com/paperless-ngx/paperless-ngx/

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.