生产环境中备份和更新n8n(Docker Compose + PostgreSQL)

3 分钟阅读·Matthieu·n8ndocker-composepostgresqlbackupdisaster-recovery|

自托管n8n的日常运维指南:自动化PostgreSQL备份、加密密钥保护、使用rclone进行异地备份、从全新VPS进行灾难恢复、安全的Docker Compose更新、回滚以及1.x到2.x的迁移路径。

你已经在VPS上用Docker Compose和PostgreSQL跑起了n8n。这是第一天的事。第二天要做的是让它持续运行:自动化备份、经过测试的恢复流程和安全的更新操作。

本指南涵盖保护生产环境n8n实例所需的一切。我们会构建一个备份脚本,用cron自动化执行,将备份复制到服务器外,在全新VPS上完成灾难恢复,并安全更新n8n(支持回滚)。我们还会介绍1.x到2.x的迁移路径。

本指南假设你已按照我们的n8n Docker Compose安装指南完成了n8n的部署。你的技术栈使用Docker Compose搭配PostgreSQL,有一个非root的deploy用户和反向代理。

n8n存储了哪些需要备份的数据?

n8n存储五个组件,必须一起备份。缺少任何一个都可能导致恢复不完整或无法恢复。PostgreSQL数据库保存你的工作流、凭据(加密的)、执行历史和用户账户。加密密钥(encryption key)用于解密这些凭据。Docker卷存储自定义节点和二进制数据。.envdocker-compose.yml文件定义运行时配置。

组件 内容 丢失风险 备份方法
PostgreSQL数据库 工作流、加密凭据、执行历史、用户 所有数据丢失 pg_dump(custom格式)
N8N_ENCRYPTION_KEY 用于凭据解密的AES-256密钥 所有保存的凭据永久不可恢复 .env或容器配置中复制
Docker卷(.n8n 自定义节点、二进制执行数据 自定义节点和上传文件丢失 Alpine tar容器
.env文件 数据库密码、加密密钥、域名配置 需手动重建 文件复制
docker-compose.yml 服务定义、卷映射、镜像标签 需手动重建 文件复制

如何用pg_dump备份n8n的PostgreSQL数据库?

使用pg_dump配合--format=custom创建n8n数据库的压缩可恢复转储。custom格式支持选择性恢复和并行处理。通过运行中的PostgreSQL容器执行转储。

docker exec n8n-postgres \
  pg_dump -U n8n -d n8n --format=custom \
  > /home/deploy/n8n-backups/n8n-db-$(date +%Y%m%d-%H%M%S).dump

这个命令做了什么: docker exec在PostgreSQL容器内执行pg_dump-U n8n是数据库用户。-d n8n是数据库名称。--format=custom生成压缩的二进制转储,pg_restore可以选择性恢复。输出重定向到主机上带时间戳的文件。

验证转储是否有效:

cat /home/deploy/n8n-backups/n8n-db-*.dump | docker exec -i n8n-postgres pg_restore --list | head -20

因为pg_restore在PostgreSQL容器内,所以通过管道将转储传给docker exec -i。你应该看到数据库对象列表(表、序列、数据)。如果看到错误或空输出,说明转储失败了。

备份Docker卷

n8n数据卷包含自定义节点和二进制执行数据。用临时Alpine容器备份:

docker run --rm \
  -v n8n_n8n_data:/source:ro \
  -v /home/deploy/n8n-backups:/backup \
  alpine tar czf "/backup/n8n-data-$(date +%Y%m%d-%H%M%S).tar.gz" -C /source .

卷名n8n_n8n_data由Docker Compose项目名(n8n,来自目录名)加上卷名(n8n_data,来自docker-compose.yml)组成。如果你的不同,运行docker volume ls查看。

这个命令做了什么: 将n8n数据卷以只读方式(:ro)挂载到一次性Alpine容器中。容器创建卷内容的压缩归档并写入备份目录。容器完成后自动删除(--rm)。

验证归档:

tar tzf /home/deploy/n8n-backups/n8n-data-*.tar.gz | head -10

你应该看到.n8n目录下的文件路径。

备份配置文件

BACKUP_DIR="/home/deploy/n8n-backups"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
cp /home/deploy/n8n/.env "$BACKUP_DIR/env-$TIMESTAMP.bak"
cp /home/deploy/n8n/docker-compose.yml "$BACKUP_DIR/docker-compose-$TIMESTAMP.yml.bak"
chmod 600 "$BACKUP_DIR/env-$TIMESTAMP.bak"

.env文件包含你的N8N_ENCRYPTION_KEY和数据库密码。将权限限制为600,只有备份用户可以读取。

为什么n8n加密密钥是最重要的备份?

n8n使用N8N_ENCRYPTION_KEY以AES-256加密每个保存的凭据(API密钥、OAuth令牌、数据库密码)。如果丢失这个密钥,数据库中的每个凭据都将永久不可恢复。没有重置机制,没有后门。你必须在每个工作流中手动重新输入每个凭据。

密钥要么在.env文件中显式设置,要么由n8n首次启动时自动生成并存储在容器内的/home/node/.n8n/config中。

查找你的加密密钥:

如果你在.env中设置了它:

grep N8N_ENCRYPTION_KEY /home/deploy/n8n/.env

如果n8n自动生成了它(你从未显式设置):

docker exec n8n cat /home/node/.n8n/config

在JSON输出中查找encryptionKey字段。

安全存储密钥:

  1. 将密钥值复制到密码管理器(Bitwarden、KeePass、1Password)。
  2. 确保它以N8N_ENCRYPTION_KEY=<你的密钥>的形式存在于.env文件中。
  3. 备份脚本已经会复制.env,但也要单独存储密钥。如果服务器报废且备份损坏,只要有密钥就能重新创建凭据。

如何用cron自动化n8n备份?

将数据库转储、卷备份和配置复制合并到一个脚本中。添加保留期清理和健康检查ping来捕获失败。

创建备份脚本:

nano /home/deploy/n8n/backup-n8n.sh
#!/usr/bin/env bash
set -euo pipefail

# --- Configuration ---
BACKUP_DIR="/home/deploy/n8n-backups"
N8N_DIR="/home/deploy/n8n"
COMPOSE_PROJECT="n8n"
DB_CONTAINER="n8n-postgres"  # Matches container_name in docker-compose.yml
DB_USER="n8n"
DB_NAME="n8n"
VOLUME_NAME="${COMPOSE_PROJECT}_n8n_data"  # docker compose prefixes project name
RETENTION_DAYS=7
RETENTION_WEEKS=4
HEALTHCHECK_URL=""  # Set to your healthcheck.io or uptime-kuma URL

TIMESTAMP=$(date +%Y%m%d-%H%M%S)
DAY_OF_WEEK=$(date +%u)

mkdir -p "$BACKUP_DIR/daily" "$BACKUP_DIR/weekly"

# --- PostgreSQL dump ---
echo "[$(date)] Starting PostgreSQL backup..."
docker exec "$DB_CONTAINER" \
  pg_dump -U "$DB_USER" -d "$DB_NAME" --format=custom \
  > "$BACKUP_DIR/daily/n8n-db-$TIMESTAMP.dump"

# Verify dump is not empty
if [ ! -s "$BACKUP_DIR/daily/n8n-db-$TIMESTAMP.dump" ]; then
  echo "[$(date)] ERROR: Database dump is empty!" >&2
  exit 1
fi

# --- Docker volume backup ---
echo "[$(date)] Starting volume backup..."
docker run --rm \
  -v "${VOLUME_NAME}:/source:ro" \
  -v "$BACKUP_DIR/daily:/backup" \
  alpine tar czf "/backup/n8n-data-$TIMESTAMP.tar.gz" -C /source .

# --- Config files ---
echo "[$(date)] Backing up config files..."
cp "$N8N_DIR/.env" "$BACKUP_DIR/daily/env-$TIMESTAMP.bak"
cp "$N8N_DIR/docker-compose.yml" "$BACKUP_DIR/daily/docker-compose-$TIMESTAMP.yml.bak"
chmod 600 "$BACKUP_DIR/daily/env-$TIMESTAMP.bak"

# --- Weekly copy (Sundays) ---
if [ "$DAY_OF_WEEK" -eq 7 ]; then
  echo "[$(date)] Creating weekly backup copy..."
  cp "$BACKUP_DIR/daily/n8n-db-$TIMESTAMP.dump" "$BACKUP_DIR/weekly/"
  cp "$BACKUP_DIR/daily/n8n-data-$TIMESTAMP.tar.gz" "$BACKUP_DIR/weekly/"
  cp "$BACKUP_DIR/daily/env-$TIMESTAMP.bak" "$BACKUP_DIR/weekly/"
fi

# --- Retention cleanup ---
echo "[$(date)] Cleaning old backups..."
find "$BACKUP_DIR/daily" -type f -mtime +$RETENTION_DAYS -delete
find "$BACKUP_DIR/weekly" -type f -mtime +$((RETENTION_WEEKS * 7)) -delete

# --- Health check ping ---
if [ -n "$HEALTHCHECK_URL" ]; then
  curl -fsS --retry 3 "$HEALTHCHECK_URL" > /dev/null
fi

echo "[$(date)] Backup complete."

设置权限并测试:

chmod 750 /home/deploy/n8n/backup-n8n.sh
/home/deploy/n8n/backup-n8n.sh

验证备份文件是否已创建:

ls -lh /home/deploy/n8n-backups/daily/

注意文件大小。一个典型的n8n数据库转储在500 KB到50 MB之间,取决于执行历史。如果转储为0字节,说明出了问题。

用cron调度

crontab -e

添加这一行,每天03:00运行备份:

0 3 * * * /home/deploy/n8n/backup-n8n.sh >> /home/deploy/n8n-backups/backup.log 2>&1

这个命令做了什么: 每天凌晨3点运行备份脚本。输出和错误追加到backup.log以便排查故障。

备份失败告警

脚本中的HEALTHCHECK_URL变量支持Healthchecks.io或自托管的Uptime Kuma实例等服务。这些服务期望定期收到ping。如果ping停止(因为脚本失败或cron未执行),你会收到告警。

设置一个24小时周期、1小时宽限期的检查。如果备份脚本在04:00前没有ping,你就会收到通知。

如何用rclone将n8n备份复制到服务器外?

备份在n8n同一台服务器上不算真正的备份。如果磁盘故障,两者都会丢失。使用rclone将备份复制到S3兼容的对象存储(Wasabi、Backblaze B2、MinIO或任何S3提供商)。

安装rclone:

sudo apt install rclone

配置远程存储。此示例使用任何S3兼容存储:

rclone config

按照交互提示创建名为n8n-backup的远程。选择"Amazon S3 Compliant Storage Providers"并输入你的endpoint、访问密钥和秘密密钥。

验证远程是否工作:

rclone lsd n8n-backup:

你应该看到你的bucket列表。

将同步添加到备份脚本中。在health check ping行之前插入:

# --- Off-server copy ---
echo "[$(date)] Syncing to remote storage..."
rclone sync "$BACKUP_DIR" n8n-backup:your-bucket-name/n8n \
  --transfers 4 \
  --min-age 1m \
  --log-level ERROR

--min-age 1m避免上传仍在写入的文件。--transfers 4运行四个并行上传。

如何验证n8n备份是否有效?

从未测试过的备份等于没有备份。定期运行这些检查。

数据库转储完整性:

cat /home/deploy/n8n-backups/daily/n8n-db-*.dump | docker exec -i n8n-postgres pg_restore --list > /dev/null 2>&1 && echo "OK" || echo "CORRUPT"

卷归档完整性:

tar tzf /home/deploy/n8n-backups/daily/n8n-data-*.tar.gz > /dev/null 2>&1 && echo "OK" || echo "CORRUPT"

用于远程验证的校验和:

备份后生成校验和:

sha256sum /home/deploy/n8n-backups/daily/* > /home/deploy/n8n-backups/daily/checksums.sha256

从远程存储下载后验证:

sha256sum -c checksums.sha256

每行应显示OK。任何不匹配意味着文件在传输过程中损坏了。

如何在全新VPS上从备份恢复n8n?

这是灾难恢复流程。你的服务器丢失了,你有一台全新VPS和备份文件(来自远程存储或本地副本)。以下是让n8n重新运行的步骤。

1. 配置新VPS并安装Docker

设置一台安装了Docker和Docker Compose的VPS。按照我们的n8n Docker Compose安装指南操作到Docker安装步骤,然后回到这里。

2. 创建deploy用户和项目目录

adduser --disabled-password deploy
mkdir -p /home/deploy/n8n /home/deploy/n8n-backups
chown deploy:deploy /home/deploy/n8n /home/deploy/n8n-backups

3. 下载备份

从远程存储:

su - deploy
rclone copy n8n-backup:your-bucket-name/n8n/daily /home/deploy/n8n-backups/daily --progress

或从另一台服务器通过scp

scp user@old-server:/home/deploy/n8n-backups/daily/* /home/deploy/n8n-backups/daily/

4. 恢复配置文件

cp /home/deploy/n8n-backups/daily/env-*.bak /home/deploy/n8n/.env
cp /home/deploy/n8n-backups/daily/docker-compose-*.yml.bak /home/deploy/n8n/docker-compose.yml
chmod 600 /home/deploy/n8n/.env

验证加密密钥存在:

grep N8N_ENCRYPTION_KEY /home/deploy/n8n/.env

这个命令必须返回包含你密钥的一行。如果为空或缺失,从密码管理器中找到密钥并手动添加。没有这个密钥,你的凭据就丢了。

5. 只启动PostgreSQL

cd /home/deploy/n8n
docker compose up -d postgres

等待PostgreSQL初始化:

docker compose logs -f postgres

找到database system is ready to accept connections

6. 恢复数据库

docker cp /home/deploy/n8n-backups/daily/n8n-db-*.dump n8n-postgres:/tmp/n8n.dump
docker exec n8n-postgres pg_restore -U n8n -d n8n --clean --if-exists /tmp/n8n.dump

这个命令做了什么: 将转储文件复制到容器内,然后pg_restore加载它。--clean在恢复前删除现有对象。--if-exists防止对象不存在时报错。

你可能会看到一些关于对象不存在的警告。这在全新数据库上是正常的。关于数据或约束的错误则不正常。

7. 恢复Docker卷

Docker Compose在上一步启动PostgreSQL时已创建了n8n_n8n_data卷。恢复到其中:

docker run --rm \
  -v n8n_n8n_data:/target \
  -v /home/deploy/n8n-backups/daily:/backup:ro \
  alpine sh -c "tar xzf /backup/n8n-data-*.tar.gz -C /target"

8. 启动完整技术栈

docker compose up -d

9. 验证恢复

docker compose ps

所有容器应显示running状态。

检查n8n日志:

docker compose logs -f n8n

找到Editor is now accessible via: http://localhost:5678。不应有加密密钥错误。

打开n8n Web界面并验证:

  1. 工作流存在且与之前一致。
  2. 凭据可用。 打开任意凭据确认显示存储的值(API密钥、密码)。如果看到空字段或解密错误,说明加密密钥不对。
  3. 运行一个测试工作流。 执行一个简单工作流确认数据库连接和执行引擎正常。

从服务器外部测试:

curl -s https://your-n8n-domain.com/healthz

200响应确认n8n可访问且正在运行。

如何用Docker Compose安全更新n8n?

更新n8n遵循四个步骤:备份、检查发行说明、拉取新镜像、验证。永远不要跳过备份步骤。

1. 运行备份

/home/deploy/n8n/backup-n8n.sh

这是必须的。如果更新出问题,你需要一个恢复点。

2. 检查发行说明中的破坏性变更

拉取新版本前,阅读n8n发行说明。注意:

  • 数据库迁移(启动时自动运行但可能耗时)
  • 你的工作流使用的已弃用节点
  • 变更的环境变量
  • PostgreSQL最低版本要求

3. 记录当前版本

docker compose exec n8n n8n --version

记下来。回滚时需要。

4. 拉取并重启

如果你的docker-compose.yml使用n8nio/n8n:latestn8nio/n8n:stable标签:

cd /home/deploy/n8n
docker compose pull
docker compose down
docker compose up -d

如果你锁定了特定版本(生产环境推荐),先编辑docker-compose.yml

services:
  n8n:
    image: n8nio/n8n:2.12.3  # Change to the target version

然后:

docker compose up -d

5. 验证更新

docker compose exec n8n n8n --version

确认版本与预期一致。

检查日志中的迁移错误:

docker compose logs --tail 50 n8n

找到Migrations completedEditor is now accessible via: http://localhost:5678

测试API健康端点:

curl -s https://your-n8n-domain.com/healthz

通过界面运行一个测试工作流确认执行正常。

如何在n8n更新失败后回滚?

如果更新破坏了工作流或界面不可访问,回退到前一版本。

1. 停止故障实例

cd /home/deploy/n8n
docker compose down

2. 设置之前的镜像标签

编辑docker-compose.yml,将镜像改为之前的版本:

services:
  n8n:
    image: n8nio/n8n:2.11.2  # Your previous working version

3. 如果迁移已运行则恢复数据库

如果n8n在失败的更新中运行了数据库迁移,schema可能已改变。从更新前的备份恢复:

docker compose up -d postgres
docker cp /home/deploy/n8n-backups/daily/n8n-db-*.dump n8n-postgres:/tmp/n8n.dump
docker exec n8n-postgres pg_restore -U n8n -d n8n --clean --if-exists /tmp/n8n.dump

4. 启动旧版本

docker compose up -d

验证:

docker compose exec n8n n8n --version
docker compose logs --tail 20 n8n

这就是我们每次更新前备份的原因。没有更新前的转储,迁移后就无法安全降级。

如何将n8n从1.x迁移到2.x?

n8n 2.0于2025年12月发布,包含破坏性变更。如果你还在1.x,尽快迁移。1.x版本在2.0发布后仅提供了三个月的安全修复,该窗口现已关闭。

n8n 2.0中的主要破坏性变更

变更 1.x行为 2.x行为 需要的操作
MySQL/MariaDB支持 支持 完全移除 升级前迁移到PostgreSQL
Task runners 可选 默认启用,独立Docker镜像 外部模式使用n8nio/runners镜像
Code node环境变量 可访问 默认阻止 如需要设置N8N_BLOCK_ENV_ACCESS_IN_NODE=false
Start node 可用 移除 替换为特定触发器节点
Save vs. Publish Save = deploy Save和Publish是分开的操作 更新团队工作流
Python Code node 基于Pyodide 通过task runners使用原生Python 使用外部模式task runners
ExecuteCommandLocalFileTrigger节点 启用 默认禁用 如需要则显式启用
--tunnel CLI选项 可用 移除 改用反向代理
N8N_CONFIG_FILES 支持 移除 直接使用环境变量

步骤1:运行迁移报告

迁移报告工具在n8n 1.121.0及更高版本中可用。它在升级前识别工作流级别和实例级别的问题。

在n8n界面中,进入Settings > Migration Report。此选项仅对全局管理员可见。

报告有两个标签页:

  • Workflow Issues: 列出使用已弃用节点、已移除功能或行为变更的工作流。
  • Instance Issues: 标记需要更新的环境变量和配置。

继续之前修复报告识别出的每个问题。

步骤2:先更新到最新的1.x

在跳到2.x之前,先更新到最新的1.x版本。这确保所有中间数据库迁移都能运行:

docker compose pull  # With image set to n8nio/n8n:1-latest or latest 1.x tag
docker compose down && docker compose up -d

步骤3:备份所有内容

/home/deploy/n8n/backup-n8n.sh

这是你的回滚点。如果2.x破坏了你的设置,可以恢复此备份并留在1.x。

步骤4:更新到2.x

编辑docker-compose.yml

services:
  n8n:
    image: n8nio/n8n:stable  # Or a specific 2.x version like 2.12.3
docker compose pull
docker compose down
docker compose up -d

步骤5:验证迁移

docker compose logs --tail 100 n8n

查找已完成的迁移且无错误。

测试迁移报告标记的工作流。打开凭据确认解密正常。端到端运行几个工作流。

如果有问题,使用上一节的流程用1.x备份和1.x镜像标签进行回滚。

故障排除

pg_dump: error: connection to server failed PostgreSQL容器未运行。用docker compose up -d postgres启动它,等它就绪后再运行备份。

恢复后凭据显示为空 你的N8N_ENCRYPTION_KEY与保存凭据时使用的不匹配。检查.env文件,与密码管理器中的密钥对比。

docker exec失败显示"no such container" 容器名称取决于项目目录名和compose文件。运行docker ps查找实际容器名称。调整备份脚本中的DB_CONTAINER变量。

备份脚本运行但healthcheck从未ping 检查脚本中是否设置了HEALTHCHECK_URL。手动测试URL:curl -fsS "your-healthcheck-url"。防火墙规则可能阻止了出站HTTPS。

更新后n8n无法启动并显示迁移错误docker compose logs n8n检查日志。如果错误提到特定迁移,在n8n社区论坛搜索该错误。必要时回滚。

rclone sync因认证错误失败 运行rclone config reconnect n8n-backup:刷新凭据。验证访问密钥和秘密密钥是否正确。


日志位置:

# n8n application logs
docker compose logs -f n8n

# PostgreSQL logs
docker compose logs -f postgres

# Backup script log
tail -f /home/deploy/n8n-backups/backup.log

# Cron execution log
grep CRON /var/log/syslog | tail -20

版权所有 2026 Virtua.Cloud。保留所有权利。 本内容为 Virtua.Cloud 团队原创作品。 未经书面许可,禁止复制、转载或再分发。

准备好亲自尝试了吗?

几秒内部署您自己的服务器。支持 Linux、Windows 或 FreeBSD。

查看 VPS 方案