Docker Compose:让 n8n命令变成菜单。

你有没有过这种经历?

第一次部署 n8n 时,照着教程在终端里敲了一大串命令。里面有端口、密码、挂载路径、网络、重启策略。最后它确实跑起来了。

过了两周,电脑重启。你想重新启动 n8n,却发现自己完全忘记当时写过什么。

你开始翻聊天记录、翻浏览器历史、翻收藏夹。终于找到那条命令,又不确定自己有没有改过端口、有没有挂过数据卷、密码是不是同一个。

这不是你记性不好。是因为“把一套应用的所有规则,塞进一条很长的命令”,本来就不适合长期使用。

Docker Compose 就是为了解决这件事。

它让你把 n8n、数据库、端口、数据、网络和启动规则,统一写进一份清单。以后启动不靠回忆,只需要一句命令。

今天我们不追求一口气背完 YAML。我们只做一件事:像给一栋小楼写物业清单那样,把 n8n 和它需要的数据库安排清楚。


先看你最终会得到什么

完成后,你会拥有一个文件夹。里面最重要的是两份文件:

n8n-docker/
├── compose.yaml
└── .env
  • compose.yaml:公开的物业清单,写着“有哪些房间、怎么连接、数据放哪”。
  • .env:私密的小信封,写着密码和加密密钥。

以后你只要进入这个文件夹,运行:

docker compose up -d

n8n 和 PostgreSQL 数据库会一起启动。

它们各住一间房、各有自己的数据柜、通过内部电话线通信;浏览器只能打开 n8n,不能直接敲数据库的门。

这就是一个对小白来说很重要的“安全边界”:你能用 n8n,但不需要把数据库暴露到外面。


Docker Compose 到底是什么?别把它想复杂

把 Docker Compose 想成一张写得很清楚的物业清单。

假设你要管理两间房:

  1. 一间叫 n8n,负责自动化。
  2. 一间叫 PostgreSQL,负责保存数据。

你需要告诉物业:

  • 每间房用什么装修模板。
  • 谁先开门,谁后开门。
  • 哪间房可以对外接待。
  • 哪些资料需要放进独立储物柜。
  • 两间房如何在楼内打电话。

Docker Compose 就是把这些事写下来。Docker 官方对它的说明是:用一份 YAML 文件来定义、配置和运行多个容器服务。Docker 官方指南

你不需要把 YAML 当成编程语言。它更像“有严格缩进的清单”。只要层级对齐,它就能读懂你的安排。


第 1 步:创建一个专门的文件夹

先在电脑上找一个你方便管理的位置,例如桌面或文稿目录。

新建文件夹:

n8n-docker

接下来所有和 n8n 有关的文件都放在这里。不要今天把 Compose 文件放桌面,明天把密码放下载目录,后天又不知道数据卷从哪来的。

把这个文件夹想成“这栋 n8n 小楼的物业办公室”。


第 2 步:先做 .env,把敏感内容放进小信封

在 n8n-docker 文件夹中,新建一个文件,文件名必须是:

.env

注意两点:前面有英文句点;后面没有 .txt。

把下面内容复制进去:

POSTGRES_USER=n8n
POSTGRES_PASSWORD=请替换成一个你自己设置的强密码
POSTGRES_DB=n8n
N8N_ENCRYPTION_KEY=请替换成一长串随机字符并安全保存

每一行都不要急着跳过。

这一行 它在生活中像什么 它实际决定什么
POSTGRES_USER=n8n 数据库房间的工作人员名字 n8n 连接 PostgreSQL 时使用的账号。
POSTGRES_PASSWORD=... 数据库房间的门禁密码 防止其他人随意进入数据库。
POSTGRES_DB=n8n 这个资料室的名称 PostgreSQL 启动时创建的数据库名。
N8N_ENCRYPTION_KEY=... 保险柜主钥匙 n8n 用它保护凭据等敏感信息;以后不要随便换。

你现在只要知道一件事:这个文件不应该公开。

如果未来你把 compose.yaml 放到 GitHub,.env 不要一起上传。就像物业清单可以让合作伙伴看,主钥匙不能贴在门口。


第 3 步:复制这一份完整配置,不要先自己拼

在同一个 n8n-docker 文件夹中,新建:

compose.yaml

然后完整复制下面的内容:

services:
  postgres:
    image: postgres:16
    container_name: n8n-postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - automation-net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 10

  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    ports:
      - "127.0.0.1:5678:5678"
    environment:
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres
      DB_POSTGRESDB_PORT: 5432
      DB_POSTGRESDB_DATABASE: ${POSTGRES_DB}
      DB_POSTGRESDB_USER: ${POSTGRES_USER}
      DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD}
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      GENERIC_TIMEZONE: Asia/Shanghai
      TZ: Asia/Shanghai
    volumes:
      - n8n_data:/home/node/.n8n
    networks:
      - automation-net
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  n8n_data:
  postgres_data:

networks:
  automation-net:
    driver: bridge

现在先别被这么多行吓到。你不需要一次性理解全部。下面我会像带你参观楼层一样,一段一段讲。


第 4 步:先认识最外层的 services

配置开头是:

services:

它的意思是:这栋楼里有哪些正在营业的房间。

在它下面,你看到了两个名字:

postgres:
n8n:

一个是数据库房间,一个是自动化房间。

这里的名字很重要。以后 n8n 想找数据库,不是去找 localhost,而是直接拨打内部电话簿里的 postgres。

你可以理解成:

n8n 房间 —— 内部电话线 —— postgres 房间

第 5 步:先看 PostgreSQL 房间,它负责“记住”

这一段:

postgres:
  image: postgres:16

意思很简单:请 Docker 用 PostgreSQL 16 的标准装修模板,建一间叫 postgres 的数据库房间。

它的密码从哪里来?

看这里:

environment:
  POSTGRES_USER: ${POSTGRES_USER}
  POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
  POSTGRES_DB: ${POSTGRES_DB}

${POSTGRES_PASSWORD} 的意思不是把密码写在这里,而是:请去同一个文件夹的 .env 小信封里,取出这个值。

这样做的好处是,配置结构和真实密码分开。以后改密码,你只改 .env;以后分享配置给朋友,也不会不小心把真实密码一起发出去。

这行为什么不能少?

volumes:
  - postgres_data:/var/lib/postgresql/data

数据库是最不应该“住临时房”的东西。

这行的意思是:把 postgres_data 这只储物柜,接到数据库真正保存资料的位置。这样你重建 PostgreSQL 容器时,数据库内容不会一起消失。

healthcheck 又是什么?

你会看到:

healthcheck:
  test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]

你可以把它理解成物业在开门前打一通测试电话:数据库不只是房门开了,而是真的已经能接电话、能回答问题。

为什么要做这个检查?因为容器“已经启动”不等于数据库“已经准备完成”。Docker 官方也特别说明,服务启动顺序和服务真正可用是两件事;需要健康检查才能更可靠地等待服务 ready。Docker 官方说明


第 6 步:再看 n8n 房间,它负责“干活”

这部分最常让新手困惑的是:

DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432

为什么不是:

DB_POSTGRESDB_HOST: localhost

因为你现在不是在电脑浏览器里访问数据库,而是让 n8n 这个容器 去找 PostgreSQL 容器。

在 n8n 房间里,localhost 的意思是“n8n 房间自己”。n8n 如果拨 localhost:5432,其实是在问自己:你这里有没有数据库?当然通常没有。

真正正确的方式,是拨内部电话簿:

DB_POSTGRESDB_HOST: postgres

这里的 postgres 就是前面定义的服务名。它像房间名,也是内部网络里的联系电话。

5432 则是 PostgreSQL 房间内部的接待窗口号码。

记住:浏览器访问 n8n 时,看 localhost:5678;n8n 访问 PostgreSQL 时,看 postgres:5432。前者是从楼外进来,后者是楼内房间打电话。

第 7 步:为什么只有 n8n 有 ports?

n8n 部分有:

ports:
  - "127.0.0.1:5678:5678"

它的意思是:让这台电脑的浏览器可以通过 http://localhost:5678 打开 n8n 。

而 PostgreSQL 没有 ports。

这是故意的,不是漏写。

数据库不需要给浏览器直接打开,它只需要在楼内接 n8n 的电话即可。少开一扇对外的门,就少一份不必要的暴露。

左边的 127.0.0.1 表示先只允许本机访问。对于刚开始学习 Docker 的人,这是一个稳妥的起点。


第 8 步:n8n_data 和 postgres_data,为什么要两只储物柜?

配置底部有:

volumes:
  n8n_data:
  postgres_data:

这表示两只独立储物柜。

储物柜 保存谁的资料 为什么分开更好
n8n_data n8n 自己的配置、工作流相关数据 方便独立维护、检查与迁移。
postgres_data PostgreSQL 的数据库文件 数据库有自己的保存规则,不应该和 n8n 文件混在一起。

这就像办公室和财务室各有自己的上锁柜。分开不只是“看起来整洁”,而是为了以后备份、恢复和排查时更清楚。


第 9 步:启动前,先让 Docker 帮你检查配置

不要复制完就直接启动。先在 n8n-docker 文件夹中打开终端,运行:

docker compose config

它像物业在施工前把整份清单重新念一遍。

如果 YAML 缩进错了、变量没找到、冒号写漏了,这一步通常会直接告诉你。比起启动失败后盲猜,先做这一步能省很多时间。

没有明显错误后,再运行:

docker compose up -d

-d 的意思是让它在后台运行。你关掉终端,n8n 也不会因此停止。

接着运行:

docker compose ps

你想看到的不是一大串技术文字,而是两个服务都处于 running 或 Up 状态。

如果 PostgreSQL 还在 starting,给它几十秒准备时间。n8n 设定了等待健康检查,它会在数据库真正准备好之后再继续。


第 10 步:打开 n8n,完成第一次验证

浏览器打开:

http://localhost:5678

如果看到 n8n 初始化页面 ,说明:

  • n8n 房间已经建好;
  • 大楼外的 5678 门牌已经接通;
  • 数据库房间已经准备好;
  • n8n 已经拿到内部电话簿并能连接数据库。

请先创建管理员账号,再新建一个测试工作流。然后不要急着做复杂自动化,先让这一套结构稳定运行一天。真正能跑稳的基础,比一次性堆很多节点更重要。


如果你卡住了,先只看这 4 个问题

1. docker compose up -d 直接报错

先运行:

docker compose config

最常见的问题是 YAML 缩进。YAML 对空格很敏感,请统一使用空格,不使用 Tab。

2. n8n 不断重启

运行:

docker compose logs -f n8n

从最早一条 ERROR 开始读。很多问题是 .env 变量没填、数据库地址写错、或者密钥为空。

3. n8n 显示数据库连接失败

先检查:

docker compose logs -f postgres

然后确认 n8n 配置里是否写了:

DB_POSTGRESDB_HOST: postgres

不要写 localhost。

4. 浏览器打不开 localhost:5678

运行:

docker compose ps

确认 n8n 服务是否真的在运行,以及端口是否显示为 127.0.0.1:5678->5678/tcp。如果显示端口被占用,改左边的 5678,例如改为 18080,再访问 http://localhost:18080 。


你现在不需要背住全部配置

你只需要真正记住四句话:

compose.yaml 是整套应用的物业清单。.env 是放密码和密钥的小信封。postgres 是 n8n 在楼内拨打的数据库房间名。数据卷让你重建容器时,不会丢掉成果。

只要这四句话清楚,后面不管你增加 Redis、反向代理、备份工具还是其他应用,都是在这套结构上加新的房间和规则,而不是重新学习一门完全陌生的技术。

下一篇我们解决最后一个让人最焦虑的问题:当 Docker 提示端口冲突、数据库连不上、容器一直重启、数据好像没了时,到底应该先看哪里,才能不靠重装碰运气。