n8n Docker 自動化 AI Agent

n8n Docker 部署完整教學:從零到正式環境,繞過新手最常踩的三個坑

n8n Docker Compose 部署實戰教學,涵蓋 PostgreSQL 資料庫、N8N_ENCRYPTION_KEY 備份、Nginx 反向代理與 webhook URL 設定,避開 OAuth 整合失敗、資料遺失、憑證無法解密等常見陷阱。

n8n 這兩年在台灣開發者圈子爆紅有幾個原因:AI 自動化的浪潮讓 workflow 工具重新洗牌、它開源且自架免費、介面比 Zapier 直覺很多,而且有完整的 AI Agent 節點。想把它架在自己的 VPS 上跑很合理。

但網路上多數 n8n Docker 部署教學的問題是:它們教你怎麼「跑起來」,沒教你怎麼「活得久」。照著官方快速開始的指令敲一敲,確實 5 分鐘就能看到 n8n 介面,但三個月後你會陸續遇到:OAuth 憑證整合失敗、webhook URL 顯示成 localhost、資料庫鎖死、或是某天重啟容器後所有憑證全部解不開。

這篇 n8n Docker 部署教學要做的,是把一個能撐住正式環境的架構一次講清楚,同時標記出新手最容易踩的三個坑。

為什麼要自架 n8n?成本算給你聽

先處理一個根本問題:n8n Cloud 每月起跳 20 歐元,自架成本有多少?

一台規格適中的台灣 VPS(2 vCPU / 4GB RAM / 40GB NVMe)大約 NT$400–600/月。考量到:

  • 資料不出境:工作流經手的資料(客戶名單、API 金鑰、內部文件)完全在你自己的機器上
  • 執行次數無上限:n8n Cloud 的計費是以工作流執行次數計算,自架只要硬體撐得住就沒限制
  • 延遲可控:台灣到台灣 VPS 的延遲 5ms 左右,比連到歐洲的 n8n Cloud 快很多

缺點是你要自己負責維運。這也是這篇文章存在的理由。

環境需求與前置準備

以 Ubuntu 24.04 LTS 為例(其他發行版流程相似):

  • 2 vCPU / 4GB RAM 是舒適下限。1GB 跑得起來但容易 OOM,特別是跑 AI Agent 節點時
  • 一個指向你 VPS 的網域(例如 n8n.example.com),用於 HTTPS 與 webhook
  • Docker 與 Docker Compose v2 已安裝

快速安裝 Docker:

1
2
3
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
# 需重新登入才會生效

第一個坑:不要用預設的 SQLite

多數 n8n Docker 部署教學會直接 docker run n8nio/n8n,這會用預設的 SQLite 資料庫,存放在容器內。看起來很方便,但正式環境不該這樣做,原因有三:

  1. SQLite 併發寫入差:當工作流量一大,你會遇到 database is locked 錯誤,工作流執行失敗
  2. 備份困難:SQLite 是單一檔案,熱備份容易損壞,冷備份要停服務
  3. 升級風險高:n8n 幾乎每週釋出 minor 版本,schema 變動時 SQLite 的 migration 比 PostgreSQL 更容易出狀況

正確做法是從一開始就用 PostgreSQL。下面的 docker-compose.yml 是我實際在 production 用的基礎版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
services:
postgres:
image: postgres:16
restart: unless-stopped
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- ./postgres_data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
interval: 10s
timeout: 5s
retries: 5

n8n:
image: docker.n8n.io/n8nio/n8n:latest
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}
- N8N_HOST=${N8N_HOST}
- N8N_PROTOCOL=https
- N8N_PORT=5678
- WEBHOOK_URL=https://${N8N_HOST}/
- N8N_PROXY_HOPS=1
- GENERIC_TIMEZONE=Asia/Taipei
- TZ=Asia/Taipei
volumes:
- ./n8n_data:/home/node/.n8n
depends_on:
postgres:
condition: service_healthy

注意 ports 綁定到 127.0.0.1:5678,這代表 n8n 只接受本機連線,外部流量一定要經過反向代理進來。這是必要的,絕對不要把 5678 port 直接暴露到公網。

搭配 .env 檔:

1
2
3
4
5
POSTGRES_USER=n8n
POSTGRES_PASSWORD=<生成一個 24 字以上的隨機密碼>
POSTGRES_DB=n8n
N8N_ENCRYPTION_KEY=<繼續往下看這是什麼,產生方式見下節>
N8N_HOST=n8n.example.com

第二個坑:N8N_ENCRYPTION_KEY 遺失等於憑證全毀

這是我看過最多人血淚交織的地雷。

n8n 把所有存在系統裡的憑證(OAuth token、API key、資料庫密碼等)都用 N8N_ENCRYPTION_KEY 加密後存到資料庫。如果你遺失了這把 key,所有憑證會變成無法解密的亂碼,即使資料庫還在,也沒辦法救回任何已存的憑證

幾個關鍵行為:

  • 第一次啟動時如果沒設定 N8N_ENCRYPTION_KEY,n8n 會自動產生一把,存在容器內的 ~/.n8n/config 檔案
  • 如果容器重建、volume 不在,那把 key 就消失了
  • 之後你把 N8N_ENCRYPTION_KEY 環境變數補上,但如果不是原來那把,舊憑證全部解不開

正確做法在第一次啟動前,自己產生並明確設定:

1
openssl rand -hex 32

把輸出結果放到 .envN8N_ENCRYPTION_KEY= 後面。然後——這步超級重要——把這把 key 備份到獨立於伺服器的地方。密碼管理器、加密筆記、離線檔案都可以,但不要只存在這台 VPS 上,否則 VPS 掛掉你就全毀了。

反向代理設定:讓 HTTPS 和 webhook 都正常運作

n8n 不內建 HTTPS,也不處理 Let’s Encrypt,正確做法是前面擺一個反向代理。以 Nginx 為例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
server {
listen 443 ssl http2;
server_name n8n.example.com;

ssl_certificate /etc/letsencrypt/live/n8n.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/n8n.example.com/privkey.pem;

# webhook 處理大型檔案時需要
client_max_body_size 50M;

location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;

# 這三個 header 沒設好,n8n 的 webhook URL 會顯示成 localhost
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# WebSocket 支援(n8n 編輯器介面需要)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

# workflow 執行時間可能很長,要拉大 timeout
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}

server {
listen 80;
server_name n8n.example.com;
return 301 https://$host$request_uri;
}

這裡的關鍵是四個 header:HostX-Real-IPX-Forwarded-ForX-Forwarded-Proto。少了 X-Forwarded-Proto,n8n 會以為請求是 HTTP 進來的,即使你在 docker-compose.yml 裡設定了 N8N_PROTOCOL=https,OAuth 回調還是會生成 http:// 開頭的 URL,導致 Google、Slack 等 OAuth 認證全部失敗。

WebSocket 那兩個 proxy_set_header 少寫,n8n 編輯器會一直顯示「連線中斷」的提示,執行工作流看不到即時結果。

第三個坑:webhook URL 顯示成 localhost

照著上面的設定跑起來後,你到 n8n 建立一個 webhook 節點,可能會看到 URL 顯示為 http://localhost:5678/webhook/xxx——這是最多人在 n8n 社群論壇問的問題。

原因是 n8n 預設用請求的 host header 來組 webhook URL。即使反向代理設對了,在某些情況下它還是會抓到內部的 localhost。強制解法是直接指定 WEBHOOK_URL 環境變數

1
2
3
environment:
- WEBHOOK_URL=https://n8n.example.com/
- N8N_PROXY_HOPS=1

N8N_PROXY_HOPS=1 告訴 n8n「前面有 1 層反向代理,要信任 X-Forwarded-* header」。如果你有 Cloudflare + Nginx 兩層,要設成 2。

改完後 一定要完全重啟容器docker compose down && docker compose up -d,不是 restart),環境變數才會重新載入。

啟動與驗證

第一次啟動:

1
2
docker compose up -d
docker compose logs -f n8n

看到 Editor is now accessible via 就代表啟動成功。打開瀏覽器到 https://n8n.example.com,第一次會要你建立 owner 帳號——信箱、密碼一定要記好,n8n 自架版沒有「忘記密碼」功能,要救回只能直接改資料庫。

驗證幾件事:

  1. 建一個 webhook 節點,看 URL 是不是 https://n8n.example.com/webhook-test/xxx
  2. 用外部工具(手機熱點、Postman)去打那個 URL,確認 webhook 能收到
  3. 設定一個 OAuth 憑證(Google Sheets 之類),看 redirect URL 是不是 https://n8n.example.com/rest/oauth2-credential/callback

備份策略

架好只是開始,備份才是真的考驗。你要備份的有三樣:

1. PostgreSQL 資料庫(放工作流、執行記錄、憑證):

1
2
docker compose exec -T postgres \
pg_dump -U n8n n8n | gzip > n8n_db_$(date +%Y%m%d).sql.gz

寫成 cron,每天凌晨備份並上傳到 Object Storage。

2. N8N_ENCRYPTION_KEY:前面講過了,存到密碼管理器,而且要跟資料庫備份「分開存」。如果資料庫跟 key 都丟在同一台伺服器的同一個備份檔裡,被人拿到就全毀了。

3. .n8n volume:存放 custom nodes、設定檔。直接打包:

1
tar czf n8n_data_$(date +%Y%m%d).tar.gz ./n8n_data

升級的注意事項

n8n 每週幾乎都有新版,不建議用 latest tag 在 production。改用固定版本:

1
image: docker.n8n.io/n8nio/n8n:1.72.0

升級時固定流程:備份 → 讀 release notes → 小版本直接 pull 新 image → 大版本(如 0.x → 1.x)要看 breaking changes 文件。

PostgreSQL 升級更要小心。如果你要從 16 升到 17,不是改個 tag 就好,要做 pg_dumpall 再匯入新版。直接改 image tag 會因為 data directory 版本不符而啟動失敗。

結語

n8n 自架其實不難,難的是撐過第一次遇到 OAuth 失敗、webhook 收不到、憑證解不開的那幾個凌晨兩點。這篇文章講的三個坑——用 PostgreSQL、備份 ENCRYPTION_KEY、設對反向代理——是我看過最多人被絆倒的地方,把它們處理好,後續維運會輕鬆很多。

跑 n8n 對網路穩定度要求不低,特別是有對接 LINE、Telegram 或 OAuth 服務時,任何斷線都會讓工作流執行失敗或 token 過期。NCSE Network 的 VPS 採用 Intel Xeon Gold CPU 與 NVMe SSD,搭配台灣是方電訊機房的低延遲網路,很適合跑長期運行的自動化服務。如果你正在找能穩定跑 n8n 的機器,歡迎到 NCSE Network VPS 方案頁 看看,或加入我們的 Discord 社群 跟其他開發者交流部署經驗。

需要技術開發支援?

NCSE Network 提供 Discord Bot、LINE Bot、AI Agent、爬蟲、監控系統等客製化開發服務,從規劃到上線一站式完成。

洽談專案 →