Safe n8n Migration: Upgrading Traefik to 3.3 and Postgres to 16 Without Data Loss
Migrating n8n from outdated versions of Traefik and Postgres to a modern stack requires addressing critical compatibility issues. This article provides a technical guide to preserving data and credentials when upgrading from Traefik 1.x and Postgres 11 to the latest versions.
Preparation: Backup and Encryption Key
The key stage of migration is properly exporting data and preserving the encryption key. Without it, credentials will become inaccessible after the transfer. For n8n, this is critical: the system uses symmetric encryption to store tokens and passwords.
Perform these two mandatory actions:
- Create a database dump in
customformat for proper restoration:
docker exec -t postgres_db pg_dump -U root -d n8n -Fc > /tmp/n8n_backup.dump
docker cp postgres_db:/tmp/n8n_backup.dump ./n8n_backup.dump
- Extract the current encryption key from the configuration. The source may be in two places:
- Variable N8N_ENCRYPTION_KEY in docker-compose.yml
- Parameter encryptionKey in file ~/.n8n/config
Ignoring this step will lead to a Needs first setup error after startup. The system will recognize the database but won't be able to decrypt the stored credentials.
Deploying the Stack: Traefik 3.3 Pitfalls
When deploying Traefik 3.3, a critical incompatibility issue with the Docker API arises. The router defaults to an outdated API version (1.24), while modern Docker daemons require version 1.41 or higher. This results in 404 errors when trying to discover containers.
Solution — force the API version in environment variables:
environment:
- DOCKER_API_VERSION=1.41
This change makes Traefik interact correctly with Docker Engine. Without it, the router can't see the n8n and Postgres containers, making automatic route setup via Docker Provider impossible.
Note the network isolation: all services must be in the same custom network (n8n_net). This ensures stable interaction between containers without routing conflicts. Example of correct configuration:
networks:
n8n_net:
name: n8n_net
services:
traefik:
networks:
- n8n_net
n8n:
networks:
- n8n_net
postgres_db:
networks:
- n8n_net
Restoring the Database in Postgres 16: Fixing Permissions Issues
Postgres 16 introduces changes to the default security policy. The public schema now has restricted permissions, causing a permission denied for schema public error when starting n8n.
After restoring the dump, run:
docker cp n8n_backup.dump postgres_db:/tmp/
docker exec -i postgres_db pg_restore -U root -d n8n -1 /tmp/n8n_backup.dump
Then grant full permissions on the schema to the database owner:
docker exec -it postgres_db psql -U root -d n8n -c "GRANT ALL ON SCHEMA public TO root;"
This is necessary because n8n actively uses the public schema for storing metadata. Skipping this step will cause the n8n container to crash repeatedly.
Fixing Credentials: Avoiding the "Needs first setup" Error
Even when correctly passing N8N_ENCRYPTION_KEY via environment variables, n8n may ignore it. The reason is a conflict between the environment variable and the local config file. On first startup, the system generates a new ~/.n8n/config file that overrides the key from variables.
Solution:
- Delete the config file inside the container:
docker exec -it n8n rm /home/node/.n8n/config
- Restart the service:
docker compose restart n8n
This forces n8n to use the key from environment variables instead of the local file. Make sure the original N8N_ENCRYPTION_KEY variable is specified in docker-compose.yml.
Additional Nuances: Background Processes and SQLite
During migration, issues may arise with background tasks using SQLite (e.g., Telegram parsers based on Telethon). After transfer, you'll see sqlite3.OperationalError: database is locked.
Cause — residual journaling files (.session-journal, .session-wal) that lock the database. Solution:
- Install the
psmiscutility:
apt install psmisc -y
- Force-kill processes holding the lock:
fuser -k -v /root/parser_folder/session_name.session
- Delete temporary files:
rm -f /root/parser_folder/session_name.session-journal
rm -f /root/parser_folder/session_name.session-wal
- Restart the service:
systemctl restart service_name.service
Important: Deleting journals doesn't affect the main session file. Telegram authorization remains intact.
Key Points
- Encryption key is mandatory — without the original
N8N_ENCRYPTION_KEY, all Credentials will become inaccessible. - Traefik requires explicit API specification — the
DOCKER_API_VERSION=1.41parameter is critical for container discovery. - Postgres 16 restricts permissions — manually issue
GRANT ALL ON SCHEMA public. - n8n local config conflicts — deleting
~/.n8n/configresolves the encryption key issue. - SQLite locks require cleanup — removing
.journaland.walfiles restores background processes.
After completing all steps, n8n will start up with all workflows, webhooks, and credentials preserved. Migration between major software versions always carries risks, but following these procedures minimizes downtime and data loss.
— Editorial Team
No comments yet.