Paperless-ngx Migration
This is the step-by-step guide I used to migrate my Paperless-ngx data, maintaining version v2.12.1, from an old container to a new one, without using Docker.
Entering and exiting containers
pct enter <ct_id>Step 1: Checking disk space on the old container
Enter the old container and run the following commands.
Before starting the export, I checked the space used by the main folders:
du -sh /opt/paperless/media /opt/paperless/dataAnd also how much free space was available:
df -h /Since there was enough space, I proceeded without increasing the disk size.
Step 2: Exporting the data
I entered the project folder and ran the document_exporter, pointing to a directory as required in version v2.12.1:
mkdir /opt/paperless/src/export
python3 manage.py document_exporter /opt/paperless/src/exportThe command generated files directly inside the export/ folder, including manifest.json and all .pdf and .webp files at the same level.
Step 3: Compressing the exported files
To make the transfer easier, I compressed the contents of the folder (not the folder itself):
cd /opt/paperless/src/export
tar -czf /tmp/paperless-export.tar.gz *Step 4: Transferring the export to the Proxmox host
On the Proxmox host, I copied the .tar.gz file from the old container to the host:
pct pull <old_ct_id> /tmp/paperless-export.tar.gz /root/paperless-export.tar.gzStep 5: Creating the new container with updated Paperless
On the Proxmox shell, I used the official script to install a new container:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/paperless-ngx.sh)"Step 6: Transferring the export to the new container
Still on the host, I pushed the export file to the new container:
pct push <new_ct_id> /root/paperless-export.tar.gz /tmp/paperless-export.tar.gzStep 7: Checking or setting the database password
Enter the new container and run the following commands.
In the new container, I checked the auto-generated password from:
cat /opt/paperless/paperless.confIf needed, I could have changed the password directly in PostgreSQL and updated this same file:
sudo -u postgres psql -c "ALTER USER paperless WITH PASSWORD 'new_password';"
nano /opt/paperless/paperless.confStep 8: Resetting the database in the new container
Since the new database already had data (default user created automatically), I dropped and recreated it to ensure a clean import:
sudo -u postgres dropdb paperlessdb
sudo -u postgres createdb paperlessdb
sudo -u postgres psql -c "ALTER USER paperless WITH PASSWORD 'new_password';"Step 9: Fixing database permissions
Inside psql:
\c paperlessdb
ALTER SCHEMA public OWNER TO paperless;
GRANT USAGE, CREATE ON SCHEMA public TO paperless;
GRANT ALL PRIVILEGES ON DATABASE paperlessdb TO paperless;
\qStep 10: Applying migrations
I exported the environment variables before running the migrations:
export PAPERLESS_DBUSER=paperless
export PAPERLESS_DBPASS=new_password
export PAPERLESS_DBNAME=paperlessdb
export PAPERLESS_DBHOST=127.0.0.1
cd /opt/paperless-ngx/src
python3 manage.py migrateStep 11: Importing the data
I imported the data from the .tar.gz file:
python3 manage.py document_importer /tmp/paperless-export.tar.gzStep 12: Indexing documents
To rebuild the search index and OCR:
python3 manage.py document_indexerStep 14: Starting the services
Since I’m using systemd, I enabled and started the services:
systemctl daemon-reexec
systemctl daemon-reload
systemctl start paperless-webserver
systemctl start paperless-consumer
systemctl start paperless-scheduler
systemctl enable paperless-webserver
systemctl enable paperless-consumer
systemctl enable paperless-schedulerResult
Paperless-ngx was successfully migrated to a new container with all data intact and a functional structure, maintaining compatibility with version 2.12.1 and ready for future upgrades.