Encryption Key Not Persisting

My original issue was that the encryption key for credentials was not persisting even though I had it stored in the .env file where docker-compose.yml lives. A similar docker-compose.yml/.env setup on my personal dev instance works fine. I chatted briefly with Jon and he asked that I post here. I’m still experiencing the issue, but we suspect the larger issue is my volume configuration using /root/.n8n. I’m happy to change, but the concern is that this could result in a breaking change. docker-compose.yml file is below.

version: "3"

services:

  postgres:
    image: postgres:11
    restart: always
    environment:
      - POSTGRES_USER=dbroot
      - POSTGRES_PASSWORD=NOTFORYOUPUNK
      - POSTGRES_DB=n8n
      - POSTGRES_NON_ROOT_USER=n8n
      - POSTGRES_NON_ROOT_PASSWORD=NOTFORYOUPUNK
    volumes:
      - ./init-data.sh:/docker-entrypoint-initdb.d/init-data.sh
      - /root/n8n/postgres-data:/var/lib/postgresql/data

  traefik:
    image: "traefik"
    restart: always
    command:
      - "--api=true"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.websecure.address=:443"
      - "--providers.file.filename=/traefik_conf.yaml"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ${DATA_FOLDER}/letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik_conf.yaml:/traefik_conf.yaml
      - ./certs:/certs

  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "127.0.0.1:5678:5678"
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
      - traefik.http.routers.n8n.tls=true
      - traefik.http.routers.n8n.entrypoints=web,websecure
      - traefik.http.routers.n8n.tls.certresolver=mytlschallenge
      - traefik.http.middlewares.n8n.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n.headers.STSPreload=true
    environment:
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=168
      - N8N_BASIC_AUTH_ACTIVE=false
      - N8N_BASIC_AUTH_USER
      - N8N_BASIC_AUTH_PASSWORD
      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
      - DB_POSTGRESDB_USER=${POSTGRES_NON_ROOT_USER}
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_NON_ROOT_PASSWORD}
      - N8N_BLOCK_ENV_ACCESS_IN_NODE=false
      - EXECUTIONS_PROCESS=main
      - N8N_ENCRYPTION_KEY:${N8N_ENCRYPTION_KEY}
    links:
      - postgres
    volumes:
      - ${DATA_FOLDER}/.n8n:/root/.n8n
    command: "start"

Hey @cleveradmin,

Is this compose file the one before or after the environment change? The below contains the changes you will need and updates the compose to remove older options.

You may not need the encryption key option as well as it should be set in your data folder unless that volume is being removed for some reason on every update.

version: "3"

services:

  postgres:
    image: postgres:11
    restart: always
    environment:
      - POSTGRES_USER=dbroot
      - POSTGRES_PASSWORD=NOTFORYOUPUNK
      - POSTGRES_DB=n8n
      - POSTGRES_NON_ROOT_USER=n8n
      - POSTGRES_NON_ROOT_PASSWORD=NOTFORYOUPUNK
    volumes:
      - ./init-data.sh:/docker-entrypoint-initdb.d/init-data.sh
      - /root/n8n/postgres-data:/var/lib/postgresql/data

  traefik:
    image: "traefik"
    restart: always
    command:
      - "--api=true"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.websecure.address=:443"
      - "--providers.file.filename=/traefik_conf.yaml"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ${DATA_FOLDER}/letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik_conf.yaml:/traefik_conf.yaml
      - ./certs:/certs

  n8n:
    image: n8nio/n8n
    restart: always
    ports:
      - "127.0.0.1:5678:5678"
    labels:
      - traefik.enable=true
      - traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
      - traefik.http.routers.n8n.tls=true
      - traefik.http.routers.n8n.entrypoints=web,websecure
      - traefik.http.routers.n8n.tls.certresolver=mytlschallenge
      - traefik.http.middlewares.n8n.headers.SSLRedirect=true
      - traefik.http.middlewares.n8n.headers.STSSeconds=315360000
      - traefik.http.middlewares.n8n.headers.browserXSSFilter=true
      - traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
      - traefik.http.middlewares.n8n.headers.forceSTSHeader=true
      - traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
      - traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
      - traefik.http.middlewares.n8n.headers.STSPreload=true
    environment:
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=168
      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
      - DB_POSTGRESDB_USER=${POSTGRES_NON_ROOT_USER}
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_NON_ROOT_PASSWORD}
      - N8N_BLOCK_ENV_ACCESS_IN_NODE=false
      - N8N_ENCRYPTION_KEY:${N8N_ENCRYPTION_KEY}
    links:
      - postgres
    volumes:
      - ${DATA_FOLDER}/.n8n:/home/node/.n8n

If you see a permission issue on startup you will need to run the command below to sort that and you should be good to go.

docker run --rm -it --user root -v ~/.n8n:/home/node/.n8n --entrypoint chown n8nio/base:16 -R node:node /home/node/.n8n

Where ~/.n8n is the value of your DATA_PATH environment variable.

Thanks @Jon. I’m going to work on this today, but I’m dealing with another small (but related) issue. I don’t want to have to manually redo all my credentials and was planning to use sudo docker exec -u node -it n8n-n8n-1 n8n export:credentials --all --decrypted to grab them and make my life a little easier when I likely have to recreate them afterwards. The issue is that is giving me the error “Credentials could not be decrypted. The likely reason is that a different “encryptionKey” was used to encrypt the data.”. I’m able to run sudo docker exec -u node -it n8n-n8n-1 /bin/sh -c ‘cat ~/.n8n/config’ and see what the encryptionKey is set to. Is there a way to pass the correct encryptionKey to the command to export credentials?

Hey @cleveradmin,

There isn’t sadly but what you can do is run the command from inside n8n using the execute command node and that should do the job for you.

What would that look like? I tried this, but it failed with a generic “command failed” error.

n8n export:credentials --all --decrypted

Hey @cleveradmin,

The one you have there should work but you might want to set an output directory as well.

No luck, but it does work on my dev instance so I’m guessing it’s all tied back to that volume misconfiguration. I’ll just have to deal with it and re-create the credentials.

Ok, so I made the changes to the docker-compose.yml and restarted. Unfortunately, the issue remains. The only error I see is this, not sure if it’s related or not.

n8n-n8n-1       | Initializing n8n process
n8n-postgres-1  | 2023-11-03 15:40:19.281 UTC [34] ERROR:  permission denied to create extension "uuid-ossp"
n8n-postgres-1  | 2023-11-03 15:40:19.281 UTC [34] HINT:  Must be superuser to create this extension.
n8n-postgres-1  | 2023-11-03 15:40:19.281 UTC [34] STATEMENT:  CREATE EXTENSION IF NOT EXISTS "uuid-ossp"

Hey @cleveradmin,

Not seen that one before, It looks like Postgres is unhappy with something.

Also seeing these errors:

n8n-postgres-1  | 2023-11-03 15:45:01.205 UTC [47] ERROR:  duplicate key value violates unique constraint "pk_workflow_statistics"
n8n-postgres-1  | 2023-11-03 15:45:01.205 UTC [47] DETAIL:  Key ("workflowId", name)=(69, data_loaded) already exists.
n8n-postgres-1  | 2023-11-03 15:45:01.205 UTC [47] STATEMENT:  INSERT INTO "public"."workflow_statistics"("count", "latestEvent", "name", "workflowId") VALUES ($1, $2, $3, $4)
n8n-postgres-1  | 2023-11-03 15:50:01.392 UTC [58] ERROR:  duplicate key value violates unique constraint "pk_workflow_statistics"

Those errors have been a pain for a few months but won’t be the cause of the issues you have been seeing.

I swear I’m just unlucky. So I decided to setup a brand new instance of N8N and just start over using the docker-compose.yml from https://github.com/n8n-io/n8n/blob/master/docker/compose/withPostgres/docker-compose.yml. Got it up and running, exported/imported my workflows fine, and then went to export/import my credentials. And ran into this error when importing the credentials that were exported using --decrypted. If I import the credentials encrypted, they import fine, but of course are unusable as the encryption key on the new instance is different. Any ideas?

cleveradmin@n8n:~/n8n$ sudo docker exec -u node -it n8n-n8n-1 n8n import:credentials --separate --input=/data/workflows/
An error occurred while importing credentials. See log messages for details.
Cannot read properties of undefined (reading 'encrypt')

I think there is something wacky going on with N8N + Postgres and the encryption key. I blew away the docker I just created and started over to test a theory. I added this to docker-compose.yml:

      - N8N_ENCRYPTION_KEY:${N8N_ENCRYPTION_KEY}

And this to .env:

N8N_ENCRYPTION_KEY=Zsl+jT6Z2Ur33LAHTzaXXXXXXX

Triggered docker-compose up -d and then accessed the editor and completed the first-time setup. Then I ran sudo docker exec -u node -it n8n-n8n-1 /bin/sh -c ‘cat ~/.n8n/config’ expecting to see the encryption key I set above and I did not. It outputed something else entirely. I even directly hardcoded the encryption key in the docker-compose.yml and it didn’t do anything.

Hey @cleveradmin,

I will set up a clean n8n install next week and see if I have the same problem, I know that my 2 main instances of n8n that use that key and my 2 test instances have all been fine and they all use Postgres.

My understanding was that we don’t put the env set key in the file and will instead pick up the key from the env option instead of the file if it is set.

A way to test this would be to set an env option then create a credential, stop n8n and change the config file key then start n8n up again with the same env option and see if it can still read the credential.

Just took a quick look at the code maybe we are meant to save it :thinking:

Looks like we even have a test that runs to make sure this is still working.