n8n n8n

Workflow automation platform

The world’s most popular workflow automation platform for technical teams

References

Backup

backup.yaml defines nightly exports of n8n’s dedicated PostgreSQL database under ${DB_BACKUP_ROOT}/automation-n8n/. Restore with the paired .n8n user folder/binary data and original N8N_ENCRYPTION_KEY or saved credentials cannot be decrypted. See the backup guide for commands, retention and snapshot selection.

Recovery

  1. Recover database.dump, globals.sql and the manifest. Restore the required roles and database n8n with owner root into the compatible dedicated PostgreSQL instance before starting n8n. A lingering database.sqlite is legacy data, not the deployed PostgreSQL backend.
  2. Restore /home/node/.n8n, including config, binaryData, git, ssh and nodes, with expected ownership. Recover original encryption/JWT secrets, PostgreSQL credentials and host configuration.
  3. Start the matching app/DB images and check /healthz, saved credential decryption and binary-file access. Keep production schedules/webhooks inactive on a test restore.

The DB, user files and separate secret-config copy can have different capture times; choose nearby restore points and record the recovery pair.

Post-restore check

Use the original encryption key, restore the DB and paired user folder, then sign in and open a saved workflow/credential. Test a harmless workflow manually; keep production schedules/webhooks inactive on an isolated restore.

name: n8n
services:
  n8n-postgres-init:
    image: busybox:1.38.0@sha256:fd7dc98638c8e305f4dc34e979f1c0fdfdcaeb0fbf8fcff77ae834b6da3d7e6e
    container_name: n8n-postgres-init
    command: ["sh", "-c", "chown -R 70:70 /var/lib/postgresql/data"]
    volumes:
      - ${DOCKER_VOLUMES}/n8n/postgres-data:/var/lib/postgresql/data

  n8n-postgres:
    image: postgres:16-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea
    container_name: n8n-postgres
    networks:
      - n8n-backend
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${N8N_POSTGRES_USER}
      POSTGRES_PASSWORD: ${N8N_POSTGRES_PASSWORD}
      POSTGRES_DB: ${N8N_POSTGRES_DB}
    volumes:
      - ${DOCKER_VOLUMES}/n8n/postgres-data:/var/lib/postgresql/data
    depends_on:
      n8n-postgres-init:
        condition: service_completed_successfully
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h localhost -U ${N8N_POSTGRES_USER} -d ${N8N_POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 10

  initContainer:
    image: busybox:1.38.0@sha256:fd7dc98638c8e305f4dc34e979f1c0fdfdcaeb0fbf8fcff77ae834b6da3d7e6e
    container_name: n8n-init
    command: ["sh", "-c", "chown -R 1000:1000 /home/node/.n8n"]
    volumes:
      - ${DOCKER_VOLUMES}/n8n:/home/node/.n8n

  n8n:
    image: docker.n8n.io/n8nio/n8n:2.45.2@sha256:fd7f4dc4617e9113c499ba62a6c58f17df2dce3dd82028e357485947af383041
    container_name: n8n
    restart: unless-stopped
    environment:
      TZ: ${TIMEZONE}
      GENERIC_TIMEZONE: ${TIMEZONE}
      WEBHOOK_URL: https://n8n.${MYDOMAIN}/
      N8N_HOST: n8n.${MYDOMAIN}
      N8N_PORT: 5678
      N8N_PROTOCOL: https
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      N8N_USER_MANAGEMENT_JWT_SECRET: ${N8N_USER_MANAGEMENT_JWT_SECRET}
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: n8n-postgres
      DB_POSTGRESDB_USER: ${N8N_POSTGRES_USER}
      DB_POSTGRESDB_PASSWORD: ${N8N_POSTGRES_PASSWORD}
      NODE_ENV: production
    volumes:
      - ${DOCKER_VOLUMES}/n8n:/home/node/.n8n
    networks:
      - n8n-backend
      - proxy
    depends_on:
      initContainer:
        condition: service_completed_successfully
      n8n-postgres:
        condition: service_healthy
    labels:
      traefik.enable: true
      traefik.http.routers.n8n.middlewares: localaccess@file
      traefik.http.services.n8n.loadbalancer.server.port: 5678
      homepage.group: Automation
      homepage.name: n8n
      homepage.icon: n8n.png
      homepage.href: https://n8n.${MYDOMAIN}/
      homepage.description: Workflow automation platform

networks:
  n8n-backend:
    external: false
  proxy:
    external: true