n8n 搬家不丢数据:Windows 和 macOS 如何迁移 Docker 数据卷

适用场景:你原本在 Windows 或 macOS 本地部署了 n8n,后来发现新闻检索、汇率监控、每日热点整理、Webhook 接收等任务需要机器长时间运行,于是准备把 n8n 搬到另一台长期在线的电脑、NAS、Linux 服务器或云主机。本文也适用于换电脑、重装 Docker、从本地迁移到服务器,以及把一套已经运行稳定的 n8n 环境完整复制到新设备。
n8n 从旧设备迁移到新设备的整体路线示意图

先说结论:真正要搬的不是容器,而是数据卷

很多人第一次迁移 n8n,会把注意力放在“怎么把容器复制过去”。但容器更像是临时搭好的办公室,里面的桌椅可以随时重新摆;真正重要的是办公室里的文件柜。n8n 的工作流、凭据、执行记录、加密密钥和部分实例设置,都保存在持久化数据目录里,而不是保存在容器本身。

官方 Docker 示例会把 Docker 卷 n8n_data 挂载到容器内的 /home/node/.n8n。只要这个目录里的内容完整,并且新设备用正确的方式挂载回来,工作流就能继续出现。[1] 如果只复制镜像或只重新创建一个叫 n8n 的容器,通常只能得到一个“全新的 n8n”,原来的工作流和凭据不会自动回来。

容器、镜像和数据卷关系示意图

你需要迁移哪些东西

最稳妥的迁移包通常包含四部分:n8n 数据卷、Docker Compose 文件或原始启动命令、.env 环境变量文件,以及你自己挂载的本地文件目录。如果你使用 PostgreSQL,还要额外迁移 PostgreSQL 数据库卷或执行数据库备份;如果只使用 n8n 默认的 SQLite,通常重点就是 /home/node/.n8n 对应的数据卷。

需要特别注意的是,凭据数据往往经过加密。如果新设备只恢复了数据库,却没有保留原来的 N8N_ENCRYPTION_KEY,可能会出现“工作流还在,但凭据无法使用”的情况。因此迁移时不要只看工作流数量,还要确认原来的加密密钥和环境变量也一并保留。[2]

迁移内容 是否建议迁移 作用
n8n 数据卷 必须 保存工作流、凭据、数据库、密钥和实例数据
compose.yaml 强烈建议 记录容器、端口、卷和环境变量配置
.env 强烈建议 保存域名、时区、数据库等运行参数;注意保护密码
local-files 视情况 保存工作流读写的本地文件
PostgreSQL 数据 使用 PostgreSQL 时必须 保存工作流和凭据等数据库内容
Docker 镜像 不一定 新设备可以重新拉取相同版本镜像
迁移清单示意图

第一步:先让旧设备处于安全状态

迁移前不要让 n8n 一边运行一边打包数据。你可以把它想象成搬家时不能让家人继续在房间里写文件,否则刚刚装箱的文件又会被改动,最后会出现新旧两份内容不一致。先停止 n8n 容器,再进行导出。

如果你使用 Docker Compose,在旧设备的项目目录执行:

# Windows PowerShell 或 macOS Terminal 都可以使用
cd 你的-n8n-compose-目录

docker compose stop n8n

如果你不是用 Compose,而是直接 docker run 启动,可以先找出容器:

docker ps -a --filter "name=n8n"

然后停止它:

docker stop n8n

如果你的容器名字不是 n8n,就把命令里的 n8n 换成实际容器名。注意:容器名和数据卷名不是一回事。容器名可能叫 n8n-main,数据卷可能叫 n8n-compose_n8n_data,不能想当然地直接输入。

停止 n8n 容器准备搬家

Windows:先找到 n8n 容器叫什么

在 Windows 上打开 PowerShell。不要使用普通 CMD 也可以,但本文命令默认使用 PowerShell 语法。先列出所有容器:

docker ps -a

如果容器很多,可以筛选名称中包含 n8n 的容器:

docker ps -a --filter "name=n8n"

你会看到类似这样的结果:

CONTAINER ID   IMAGE                    COMMAND                  CREATED       STATUS       PORTS                    NAMES
a1b2c3d4e5f6   docker.n8n.io/n8nio/n8n  "tini -- /docker-ent…"   8 days ago     Up 2 hours   0.0.0.0:5678->5678/tcp   n8n

这里最右侧的 NAMES 才是容器名。后面检查挂载关系时,可以使用这个名字:

docker inspect n8n

为了只查看挂载信息,可以使用 PowerShell 过滤:

docker inspect n8n --format '{{json .Mounts}}'

如果想让结果更容易阅读:

docker inspect n8n --format '{{range .Mounts}}{{println "类型:" .Type "名称:" .Name "宿主路径:" .Source "容器路径:" .Destination}}{{end}}'

你需要重点寻找这一行:

类型: volume 名称: n8n_data 宿主路径: /var/lib/docker/volumes/n8n_data/_data 容器路径: /home/node/.n8n

在 Windows Docker Desktop 中,宿主路径有时显示的是 Docker 的 Linux 虚拟环境路径,不一定能直接在资源管理器里打开。这是正常现象,因为 Docker Desktop 的 Linux 容器运行在内部虚拟机或 WSL2 环境中。不要直接去猜 C:\ProgramData\Docker 下哪个文件夹是 n8n,最可靠的方式是通过 Docker 命令导出卷内容。

Windows PowerShell 查询容器名称和挂载关系

Windows:忘记数据卷名字时怎么查询

先列出所有 Docker 数据卷:

docker volume ls

如果卷很多,可以筛选名称中包含 n8n 的卷:

docker volume ls --filter "name=n8n"

你可能看到几种不同的结果:

DRIVER    VOLUME NAME
local     n8n_data
local     n8n-compose_n8n_data
local     someproject_n8n_data

如果你使用 Docker Compose,Docker 往往会自动给卷名前面加项目名,所以你在 Compose 里写的是 n8n_data,实际名称可能变成 n8n-compose_n8n_data。此时不要凭感觉选择,而是逐个检查:

docker volume inspect n8n_data
docker volume inspect n8n-compose_n8n_data

更好的方式是反过来从容器挂载关系中确认:

docker inspect n8n --format '{{range .Mounts}}{{println .Type .Name .Destination}}{{end}}'

只要看到目标路径是 /home/node/.n8n,它对应的 Name 就是 n8n 的核心数据卷。

Windows Docker Desktop 中查询数据卷名称

Windows:直接查看数据卷里面有没有 n8n 数据

不要直接进入 Docker Desktop 的内部磁盘文件夹查看。我们可以临时启动一个轻量容器,把目标数据卷挂载进去,然后列出文件。这个临时容器不会修改你的 n8n 数据:

docker run --rm -it `
  -v n8n_data:/data `
  alpine:latest `
  sh -c "find /data -maxdepth 2 -type f | sort | head -80"

如果你的实际卷名是 n8n-compose_n8n_data,请换成:

docker run --rm -it `
  -v n8n-compose_n8n_data:/data `
  alpine:latest `
  sh -c "find /data -maxdepth 2 -type f | sort | head -80"

正常情况下,里面会看到类似 .n8n 目录中的数据库、配置或密钥文件。不同 n8n 版本的文件数量会不同,不要只依赖某一个文件名判断;更重要的是确认卷确实挂载到了 /home/node/.n8n。

临时容器检查 n8n 数据卷内容

推荐方案:用临时容器把 Docker 卷打包成 tar.gz

这是跨 Windows、macOS、Linux 最稳妥的迁移方法。它不要求你知道 Docker Desktop 内部卷的真实磁盘路径,也不依赖你能否直接访问 WSL2 或 Docker Desktop 虚拟机。Docker 官方也提供了通过临时容器挂载卷并使用归档工具备份、恢复卷的思路。[3]

先在旧设备准备一个存放备份的目录。Windows 例如:

New-Item -ItemType Directory -Force -Path "$HOME\n8n-migration"

macOS 例如:

mkdir -p ~/n8n-migration

Windows 下执行导出。注意 PowerShell 的路径写法:

docker run --rm `
  -v n8n_data:/volume `
  -v "$HOME\n8n-migration:/backup" `
  alpine:latest `
  sh -c "cd /volume && tar czf /backup/n8n_data_backup.tar.gz ."

macOS 下执行导出:

docker run --rm \
  -v n8n_data:/volume \
  -v "$HOME/n8n-migration:/backup" \
  alpine:latest \
  sh -c 'cd /volume && tar czf /backup/n8n_data_backup.tar.gz .'

如果你的卷名不是 n8n_data,把命令中的 n8n_data 替换成实际名称。导出结束后检查文件是否存在以及大小是否合理:

Get-Item "$HOME\n8n-migration\n8n_data_backup.tar.gz"

macOS:

ls -lh ~/n8n-migration/n8n_data_backup.tar.gz

如果文件只有几 KB,而你的 n8n 已经运行很久,建议先不要迁移,重新确认卷名和挂载路径。一个空卷或选错卷,是迁移失败最常见的原因之一。

Docker 临时容器把数据卷打包为 tar.gz

不要忘记保存 Compose 文件和环境变量

数据卷只保存数据,不一定保存你启动 n8n 时使用的所有运行参数。请把旧设备上的 compose.yaml、docker-compose.yml、.env 和自定义的 local-files 目录一起复制到迁移包中。

可以先在项目目录执行:

dir

确认至少有类似这些文件:

compose.yaml
.env
local-files\

如果使用的是 PowerShell,可以把 Compose 配置复制到备份目录:

Copy-Item .\compose.yaml "$HOME\n8n-migration\" -Force
Copy-Item .\.env "$HOME\n8n-migration\" -Force
Copy-Item .\local-files "$HOME\n8n-migration\local-files" -Recurse -Force

macOS:

cp compose.yaml .env ~/n8n-migration/
cp -R local-files ~/n8n-migration/

.env 里可能包含数据库密码、Webhook 密钥或加密密钥,不能公开上传到 GitHub,也不要发给别人。迁移完成后,如果你怀疑文件曾经泄露,应及时更换相关凭据。

保存 Compose、环境变量和本地文件目录

把备份包传到新设备

你可以使用移动硬盘、局域网共享、SCP、SFTP、pCloud、WebDAV 或其他可靠方式传输。对于包含 n8n 凭据的数据包,建议使用加密压缩包或加密磁盘,不要把它放在公开链接上。

如果新设备是 Linux 云服务器,可以在旧设备上使用 SCP:

scp "$HOME\n8n-migration\n8n_data_backup.tar.gz" username@你的服务器IP:/home/username/n8n-migration/
scp "$HOME\n8n-migration\compose.yaml" username@你的服务器IP:/home/username/n8n-migration/
scp "$HOME\n8n-migration\.env" username@你的服务器IP:/home/username/n8n-migration/

如果新设备也是 Windows 或 macOS,直接复制整个 n8n-migration 文件夹即可。传输完成后,最好在两台设备上分别计算哈希值:

Windows:

Get-FileHash "$HOME\n8n-migration\n8n_data_backup.tar.gz" -Algorithm SHA256

macOS 或 Linux:

shasum -a 256 ~/n8n-migration/n8n_data_backup.tar.gz

两边结果一致,说明传输过程中文件内容没有变化。

把迁移包从旧电脑传输到新设备

新设备:先创建同名的空数据卷

到新设备后,不要马上启动 n8n。先创建目标卷:

docker volume create n8n_data

确认它存在:

docker volume ls --filter "name=n8n_data"

如果 Compose 项目会自动加前缀,也可以让 Compose 创建卷,但建议在导入前明确知道真实卷名。对于本文的命令,统一使用 n8n_data,这样最不容易混乱。

新设备创建空的 n8n 数据卷

新设备:把 tar.gz 恢复到数据卷

假设迁移包放在新设备的 n8n-migration 目录中。Windows PowerShell 使用下面的命令:

docker run --rm `
  -v n8n_data:/volume `
  -v "$HOME\n8n-migration:/backup" `
  alpine:latest `
  sh -c "cd /volume && tar xzf /backup/n8n_data_backup.tar.gz"

macOS 或 Linux 使用:

docker run --rm \
  -v n8n_data:/volume \
  -v "$HOME/n8n-migration:/backup" \
  alpine:latest \
  sh -c 'cd /volume && tar xzf /backup/n8n_data_backup.tar.gz'

恢复完成后,检查卷里是否已经有文件:

docker run --rm -it `
  -v n8n_data:/data `
  alpine:latest `
  sh -c "find /data -maxdepth 2 -type f | sort | head -80"

如果恢复命令没有报错,但检查出来是空的,通常是备份包路径写错、挂载到了错误卷,或打包时使用了错误的数据卷。

把 tar.gz 备份恢复到新 Docker 数据卷

新设备:让 n8n 使用恢复后的卷

如果你使用 Docker Compose,确认 compose.yaml 中的挂载关系仍然是:

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    volumes:
      - n8n_data:/home/node/.n8n

volumes:
  n8n_data:
    external: true

external: true 的意思是:这个卷已经由你手动创建和恢复,Compose 不要再创建一份同名但内容为空的新卷。如果你的 Compose 项目使用自动生成的项目卷名,就必须按实际名称调整配置,否则 n8n 可能启动成功,但看到的是空白新实例。

启动前先检查配置:

docker compose config

确认没有错误后启动:

docker compose up -d

然后查看日志:

docker compose logs -f n8n

macOS 和 Linux 使用相同的 Docker Compose 命令。看到 n8n 正常启动后,再打开浏览器登录。

新设备通过 Compose 挂载恢复后的 n8n 数据卷

恢复后如何判断迁移成功

不要只看“网页能打开”,要做一套完整检查。首先确认原来的工作流数量和名称是否存在;其次打开一个使用凭据的节点,确认凭据仍然能正常选择;然后手动执行一个不会产生副作用的测试工作流;最后检查定时任务、Webhook 地址、时区和本地文件路径。

如果工作流都出现,但凭据全部报错,优先检查 N8N_ENCRYPTION_KEY 是否和旧设备一致。若你使用的是 PostgreSQL,要确认新设备连接的是恢复后的 PostgreSQL,而不是新建的空数据库。若工作流能运行但文件节点报错,检查 local-files 是否一起迁移,并且容器内路径仍然是 /files。

# 查看 n8n 容器实际挂载关系
docker inspect n8n --format '{{range .Mounts}}{{println .Type .Name .Source .Destination}}{{end}}'

# 查看容器环境变量中是否配置了时区和加密密钥名称
# 不要把实际密钥值复制到公开地方
docker inspect n8n --format '{{range .Config.Env}}{{println .}}{{end}}' | Select-String 'N8N_|TZ|DB_'
恢复后检查工作流、凭据和执行记录

Windows 和 macOS 的差异到底在哪里

迁移逻辑其实是一样的:停止 n8n、确认容器和卷、导出卷、传输、创建新卷、导入、重新挂载、验证。差异主要在 Docker Desktop 的底层实现和命令行路径写法。

Windows Docker Desktop 的 Linux 容器数据通常位于 Docker Desktop 管理的 WSL2 或虚拟磁盘中,不建议手工钻进内部磁盘复制某个目录。Docker 官方提供的完整 Docker Desktop 备份路径包括 %LOCALAPPDATA%\Docker\wsl\data\docker_data.vhdx,但这适合备份整个 Docker Desktop 环境;如果你只迁移 n8n,本文的“临时容器 + tar.gz”方法更轻、更容易跨设备恢复。[3]

macOS Docker Desktop 同样把 Linux 容器数据放在 Docker 管理的虚拟磁盘中。官方完整备份路径是 ~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw,但这适合整体迁移 Docker Desktop。只迁移 n8n 时,仍然建议导出 named volume,而不是直接复制 Docker.raw。[3]

Windows 与 macOS Docker Desktop 迁移方式对比

如果你使用的是绑定目录,而不是 named volume

有些人安装 n8n 时不是写 n8n_data:/home/node/.n8n,而是写了类似下面的绑定目录:

volumes:
  - ./n8n-data:/home/node/.n8n

这时 docker inspect 显示的类型会是 bind,而不是 volume。数据就在 Compose 文件旁边的 n8n-data 文件夹里,迁移时直接复制这个文件夹即可:

Copy-Item .\n8n-data "$HOME\n8n-migration\n8n-data" -Recurse -Force

macOS:

cp -R ./n8n-data ~/n8n-migration/

在新设备上把同一个目录放回 Compose 文件对应的位置,再执行 docker compose up -d。不要把 named volume 的命令和 bind mount 的命令混用;一个是 Docker 管理的卷,一个是宿主机上的真实文件夹。

named volume 与 bind mount 的区别

常见问题一:迁移后工作流还在,但凭据不能用

这通常不是卷没有恢复,而是加密密钥不一致。n8n 的凭据不会以明文形式简单存储;如果新容器使用了不同的加密密钥,它无法正确解密旧凭据。解决方法是恢复旧的 N8N_ENCRYPTION_KEY 环境变量,或者使用旧 Compose 和 .env 配置启动。

不要在文章、截图或公开仓库中展示真实密钥。如果旧密钥已经泄露,应该先评估影响并轮换所有相关 API Key,然后在新环境中重新配置 n8n 凭据。

n8n 加密密钥保持一致的示意图

常见问题二:迁移后出现全新的空白 n8n

最常见原因是 n8n 挂载到了另一个空卷。你可以检查:

docker inspect n8n --format '{{range .Mounts}}{{println "卷名:" .Name "容器路径:" .Destination}}{{end}}'

如果 /home/node/.n8n 对应的卷名不是你刚刚恢复的 n8n_data,就说明 Compose 使用了另一份卷。检查 Compose 项目名前缀、卷名和 external: true 配置,确保容器挂载的是恢复后的卷。

错误卷名导致 n8n 启动成空白实例

常见问题三:容器能启动,但网页打不开

数据卷恢复和网络访问是两件事。先看容器是否运行:

docker ps

再看端口映射:

docker port n8n

如果你想在本机直接访问,通常需要看到类似 5678/tcp -> 0.0.0.0:5678 的映射。如果你使用反向代理,n8n 可能只绑定到 127.0.0.1:5678,这时需要从域名和 HTTPS 入口访问,而不是直接访问服务器 IP。

docker compose logs --tail=100 n8n
检查 n8n 端口、反向代理和容器日志

常见问题四:定时任务时间不对

迁移后定时任务提前或延迟,通常是时区环境变量不同。检查旧设备和新设备的 TZ、GENERIC_TIMEZONE,例如:

environment:
  - TZ=Asia/Shanghai
  - GENERIC_TIMEZONE=Asia/Shanghai

TZ 影响系统时间相关行为,GENERIC_TIMEZONE 会影响 Schedule Trigger 等时间调度节点。n8n 官方 Docker 示例也建议显式设置这两个时区变量。[2]

检查 n8n 时区设置

常见问题五:Webhook 地址变了

如果 n8n 从本地迁移到服务器,Webhook 地址通常会发生变化。工作流里的 Webhook 节点本身可能仍然存在,但第三方服务保存的回调地址需要重新更新。迁移到域名后,要检查 N8N_HOST、N8N_PROTOCOL、WEBHOOK_URL 和反向代理配置。

本地测试可以使用 http://localhost:5678 ,生产环境则应该使用 HTTPS 域名,例如:

WEBHOOK_URL=https://n8n.example.com/
N8N_PROTOCOL=https
N8N_HOST=n8n.example.com

n8n 官方 Compose 示例也使用域名、HTTPS 和反向代理来提供生产访问 。[4]

Webhook 地址从本地迁移到云端域名

一套可以反复使用的迁移脚本思路

如果你以后经常迁移,可以把步骤固定成“停机—确认—导出—校验—传输—恢复—验证”七个动作。不要把所有命令写成一个没有检查的长脚本,因为一旦卷名写错,脚本仍然可能成功执行,但打包出来的是空数据。

最重要的判断点是:导出前确认挂载路径;导出后确认压缩包大小;传输后确认 SHA-256;恢复后确认卷内文件;启动后确认容器挂载关系。每一步都检查,迁移就不会变成“启动了一个全新的 n8n”。

七步迁移流程检查图

最后总结:什么时候应该迁移 n8n

当你只是在本地学习 n8n,电脑开机时间不长,本地部署非常方便;但当你开始做每日新闻检索、汇率监控、内容汇总、Webhook 接收或夜间自动运行,长期让个人电脑保持开机就会变得不稳定。此时可以把 n8n 迁移到一台长期在线的设备,例如 NAS、Linux 小主机、云服务器或 Oracle Cloud 主机。

迁移的核心不是“把 n8n 重新安装一遍”,而是把原来的持久化数据卷完整搬到新设备,再用相同的挂载路径、环境变量和加密密钥启动。只要记住这句话:容器可以重建,数据卷不能丢;镜像可以重新拉取,加密密钥不能忘记。

迁移完成后在新设备长期运行 n8n

参考资料

[1]: https://docs.docker.com/engine/storage/volumes/ Docker 官方:Volumes[2]: https://docs.n8n.io/deploy/host-n8n/install-options/install-with-docker n8n 官方:Install with Docker[3]: https://docs.docker.com/desktop/settings-and-maintenance/backup-and-restore/ Docker 官方:How to back up and restore your Docker Desktop data[4]: https://docs.n8n.io/deploy/host-n8n/install-options/use-a-cloud-provider/use-docker-compose n8n 官方:Use Docker Compose