n8n Docker 自架完整教學:docker-compose、環境變數、資料庫、備份與升級一次講清楚

恆遠數位編輯團隊約 18 分鐘閱讀
資料中心的伺服器機櫃,n8n 自架在 Docker 容器裡的技術情境
複製引文

我們內部的生產力管理系統(排班、工時推送、報表自動彙整)後面就是一組自架的 n8n。這套在恆遠跑了快兩年,期間試過雲端版、自架 SQLite 版、現在穩定在自架 PostgreSQL 版,前後踩過的雷大概可以寫成兩篇文章。

這篇把自架 n8n 的完整路徑寫清楚:docker-compose 範本直接拿去跑、環境變數到底哪些必填、為什麼生產環境一定要上 PostgreSQL、備份要備哪三樣、升級流程怎麼走不會掉 workflow,順便講清楚什麼時候該從雲端版切回自架。想先搞懂 n8n 是什麼可以回看 n8n 是什麼,想比成本可以看 n8n 費用怎麼算。

資料中心的伺服器機櫃,n8n 自架在 Docker 容器裡的技術情境
資料中心的伺服器機櫃,n8n 自架在 Docker 容器裡的技術情境

為什麼要用 Docker 自架 n8n,不是直接下 npm install

n8n 官方同時支援 npm 全域安裝與 Docker 兩種部署,但生產環境我們一律推 Docker,原因很直接:npm 版本綁死 Node.js、全域依賴容易被系統更新汙染,升級一次就得人工 reinstall。Docker 版本把 n8n、Node runtime、相依工具全部打包在 image 裡,升級就是換 tag、重啟容器,環境永遠一致。

另外一個現實面:n8n 的 workflow 執行會呼叫外部 API、跑 Code node 的 JavaScript、處理 webhook payload。這些動作如果直接跑在主機上,一個 workflow 的 bug 就可以吃光系統資源。Docker 的 cgroup 限制可以把 CPU / 記憶體圈起來,壞了只影響 container,不會拖垮同台機器的其他服務。

ℹ️我們做過這件事

恆遠內部的 生產力管理系統 跑在自架的 n8n 上面,從員工打卡、工時彙整到週報自動產出,整條鏈路靠一個 docker-compose 把 n8n、PostgreSQL、Caddy 綁在一起。想直接找人把這套搬到你們公司,可以看 客製化系統開發 或先聊聊你們的流程適不適合。

先給一張對照表,三種部署方式的差異:

部署方式

適合誰

優點

致命缺點

npm 全域安裝

想在本機試一下

最快,一行指令

升級手動、環境髒、生產不堪用

Docker 自架

正式上線、資料主權

環境一致、可備份、可擴展

要會寫 docker-compose、要自己顧主機

n8n Cloud

完全不想碰維運

開箱即用、官方升級

每月 20 美金起跳、資料出境、workflow 數有限

docker-compose.yml 完整範本:n8n + PostgreSQL + Caddy 反向代理

這份是我們實際在用的簡化版本,三個 service 各司其職:n8n 跑 workflow、PostgreSQL 存 workflow 定義與執行紀錄、Caddy 做 HTTPS 反向代理(自動處理 Let's Encrypt 憑證)。先把它存成 docker-compose.yml,底下會解釋每一塊:

YAML
version: '3.8'

services:
  postgres:
    image: postgres:16-alpine
    restart: always
    environment:
      POSTGRES_DB: n8n
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: ${DB_POSTGRESDB_PASSWORD}
      POSTGRES_NON_ROOT_USER: n8n_app
      POSTGRES_NON_ROOT_PASSWORD: ${DB_POSTGRESDB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -h localhost -U n8n -d n8n']
      interval: 5s
      timeout: 5s
      retries: 10

  n8n:
    image: docker.n8n.io/n8nio/n8n:latest
    restart: always
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${DB_POSTGRESDB_PASSWORD}
      - N8N_HOST=${N8N_HOST}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://${N8N_HOST}/
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}
      - N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}
      - GENERIC_TIMEZONE=Asia/Taipei
      - TZ=Asia/Taipei
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=720
    ports:
      - 127.0.0.1:5678:5678
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      postgres:
        condition: service_healthy

  caddy:
    image: caddy:2-alpine
    restart: always
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - n8n

volumes:
  postgres_data:
  n8n_data:
  caddy_data:
  caddy_config:

搭配一份極簡的 Caddyfile(放在同資料夾):

Text
n8n.example.com {
    reverse_proxy n8n:5678 {
        flush_interval -1
    }
}

⚠️為什麼 n8n 的 port 綁在 127.0.0.1

`ports: - 127.0.0.1:5678:5678` 這一行很關鍵,表示 n8n 只對本機開放,外網進不來。所有流量必須經過 Caddy,Caddy 才會處理 HTTPS、憑證、HTTP 轉 HTTPS。寫成 `- 5678:5678` 等於把後台直接丟到公網上,就算你有 basic auth 也不要這樣做。

把金鑰與密碼寫在同一個資料夾的 .env 檔,不要寫死在 compose 檔裡(commit 進 git 的話整個團隊都看得到):

Bash
# .env  (chmod 600, add to .gitignore)
DB_POSTGRESDB_PASSWORD=請用 openssl rand -base64 32 產生
N8N_ENCRYPTION_KEY=請用 openssl rand -base64 32 產生 (這組很重要,掉了救不回來)
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=請用 openssl rand -base64 24 產生
N8N_HOST=n8n.example.com

第一次啟動:

Bash
# 1. 產生三組隨機密鑰
openssl rand -base64 32  # DB_POSTGRESDB_PASSWORD
openssl rand -base64 32  # N8N_ENCRYPTION_KEY (另外抄一份放保險箱)
openssl rand -base64 24  # N8N_BASIC_AUTH_PASSWORD

# 2. 把密鑰填進 .env
nano .env

# 3. 啟動(第一次會抓 image,大概 1-2 分鐘)
docker compose up -d

# 4. 看 n8n 是否起來
docker compose logs -f n8n
# 看到 "Editor is now accessible via" 就成功了

環境變數清單怎麼填:WEBHOOK_URL、encryption key、basic auth、資料庫連線

官方文件列的環境變數有一百多個,但真正會影響「跑不跑得起來」的只有下面這幾組。整理成一張表方便直接對照:

環境變數

必填?

典型值

填錯會怎樣

N8N_ENCRYPTION_KEY

是

openssl rand -base64 32

掉了之後所有儲存的 credentials 全部解不開,workflow 等於廢掉

WEBHOOK_URL

是

https://n8n.example.com/

webhook 節點產生的網址會錯,第三方 callback 全部失敗

DB_TYPE

是

postgresdb

預設是 sqlite,生產環境會慢到想砸鍵盤

DB_POSTGRESDB_HOST / PORT / DATABASE / USER / PASSWORD

是

見上方 compose

連不上 DB 就直接 crash

N8N_BASIC_AUTH_ACTIVE + USER + PASSWORD

是

true + 自訂帳密

後台裸奔,任何人都能進

N8N_HOST

是

n8n.example.com

editor 內部連結會錯

GENERIC_TIMEZONE + TZ

強烈建議

Asia/Taipei

cron 排程會按 UTC 跑,台灣時間差 8 小時

EXECUTIONS_DATA_PRUNE + MAX_AGE

強烈建議

true + 720(30 天)

執行紀錄會一直長,一年後 DB 爆到幾十 GB

N8N_PAYLOAD_SIZE_MAX

依需求

16(MB)

預設 16MB,處理大檔會被截斷

🚨N8N_ENCRYPTION_KEY 不是密碼,是整個系統的根鑰匙

n8n 把你所有的 Google OAuth token、資料庫密碼、API key 用這把金鑰加密後存進 DB。這組掉了之後,就算 workflow 本體還在、DB 完整備份,credentials 一個都解不開,等於每個節點都要重新連。產生之後抄一份放 1Password / Bitwarden / 保險箱,備份策略要包含它(下面會講)。

為什麼生產環境不要用 SQLite,一定要配 PostgreSQL

n8n 預設用 SQLite,開箱可用,但「開箱可用」不等於「可以上生產」。SQLite 的限制在同時執行多個 workflow 時會非常明顯:單一寫入 lock 讓 workflow 排隊、execution 紀錄一多查詢就慢、備份只能冷備(服務停掉才能複製檔案)。

比較項目

SQLite(預設)

PostgreSQL(建議)

併發寫入

整個檔案一把鎖

row-level lock,多 workflow 同時跑不卡

執行紀錄查詢

超過 10 萬筆就明顯慢

有 index 幾百萬筆仍秒回

線上備份

必須停服務複製檔案

pg_dump 熱備,服務照跑

擴展性

只能單機

可以切 read replica、分表

搬家

一個檔案帶走,簡單

pg_dump + pg_restore,稍微麻煩但穩

何時可以用

本機試玩、單人開發

任何正式上線的場景

實務上我們看過最極端的案例:某客戶在雲端主機跑了半年的 SQLite 版 n8n,執行紀錄累積到 1.2GB,開啟 workflow 列表要等 15 秒。切換到 PostgreSQL 之後第一個反應是「怎麼變那麼快」。遷移本身不難,n8n 支援 sqlite → postgres 的匯出匯入腳本,但停機時間要抓好。

如果 workflow 裡面要串自家 ERP、報價系統、CRM,PostgreSQL 的好處會更明顯:同一台 DB server 可以同時跑 n8n 自己的 schema 和業務資料。相關的實戰可以看 n8n 串 ERP 實戰。

資料備份:volume、資料庫、encryption key 三件一起才算備份

n8n 的「完整備份」實際上是三個獨立物件,少一個就救不回來:

  • PostgreSQL 資料庫:workflow 定義、執行紀錄、credentials(已加密的密文)、tags、使用者
  • n8n Docker volume(/home/node/.n8n):node 自訂設定、session 檔、少量 cache,資料量不大但有必要
  • N8N_ENCRYPTION_KEY:解開 credentials 的根鑰匙,前兩個都備份了但這個掉了等於白備

實際備份腳本範例(每天凌晨 2 點跑一次,backup 上傳到 S3 / R2):

Bash
#!/bin/bash
# backup-n8n.sh
set -e

BACKUP_DIR="/opt/n8n-backups"
DATE=$(date +%Y%m%d-%H%M%S)
mkdir -p "$BACKUP_DIR"

# 1. PostgreSQL dump (熱備,不用停服務)
docker compose exec -T postgres pg_dump -U n8n -d n8n --clean --if-exists \
  | gzip > "$BACKUP_DIR/n8n-db-$DATE.sql.gz"

# 2. n8n volume (包起來)
docker run --rm \
  -v $(pwd | sed 's|/|_|g')_n8n_data:/data \
  -v "$BACKUP_DIR":/backup \
  alpine tar -czf "/backup/n8n-volume-$DATE.tar.gz" -C /data .

# 3. .env 檔 (含 encryption key)
# 注意: 這份要加密後再傳到遠端, 直接明文不行
gpg --symmetric --cipher-algo AES256 \
  --output "$BACKUP_DIR/n8n-env-$DATE.env.gpg" .env

# 4. 清掉 30 天前的本地備份
find "$BACKUP_DIR" -mtime +30 -delete

# 5. 推到遠端 (R2 / S3 / Backblaze 都行)
aws s3 sync "$BACKUP_DIR" s3://your-backup-bucket/n8n/

# 6. 回報 (可以接到 n8n 的 webhook, 讓它自己報自己備份狀態)
curl -X POST https://n8n.example.com/webhook/backup-status \
  -H 'Content-Type: application/json' \
  -d "{\"status\":\"ok\",\"date\":\"$DATE\",\"size\":\"$(du -sh $BACKUP_DIR | cut -f1)\"}"

備份驗證:每個月挑一天跑一次還原演練

備份最常見的失敗是「以為有備」,實際上 restore 的時候才發現 DB 版本不對、volume 權限不對、encryption key 不是最新那組。每個月挑一台測試機,從頭把 PostgreSQL dump 還原、volume 復原、.env 解密,看 workflow 能不能跑。這一步省不掉。

Crontab 掛好:

Bash
# crontab -e
0 2 * * * /opt/n8n/backup-n8n.sh >> /var/log/n8n-backup.log 2>&1

版本升級:Docker image tag、資料庫 schema migration、回滾方案

n8n 更新頻率很高,大約每週一個 minor。升級本身是「換 tag、重啟容器」,但有幾個小心點不處理會翻車:

步驟

指令

重點

跑備份

./backup-n8n.sh

升級前這一步跳不得;回滾唯一靠它

確認版本差距

看 n8n releases

跨 major 要讀 breaking changes

Pin 版本號,別用 :latest

n8n:1.108.0

latest 會跟著官方走,升級時機不受你控制

拉新 image

docker compose pull n8n

下載不會中斷服務

重啟容器

docker compose up -d n8n

schema migration 會自動跑,看 log 確認沒錯

Smoke test

跑 1-2 個關鍵 workflow

確認 webhook、credentials、cron 都還在

回滾(有需要)

改 compose tag 回舊版 + up -d

若 DB migration 已跑過,要從備份還原 DB

⚠️跨 major 版本升級要讀 breaking changes

n8n 從 0.x 到 1.x 時 workflow JSON schema 變動過一次,直接升級會讓部分舊 workflow 跑不起來。1.x 內部也偶爾有 node 行為微調。每次升級前上 n8n GitHub releases 掃一下,特別留意 BREAKING 標籤。

compose 檔的 image 行建議這樣寫:

YAML
# ❌ 不要
image: docker.n8n.io/n8nio/n8n:latest

# ✅ 要
image: docker.n8n.io/n8nio/n8n:1.108.0

什麼時候該從雲端版切回自架:成本線、資料主權、資料量門檻

並不是每個團隊都該一開始就自架。n8n Cloud 20 美金起跳買的是「不用請人顧」。但有三條線一旦跨過,自架通常就是比較好的選擇:

觸發線

判斷標準

為什麼要切

成本線

每月 Cloud 帳單 > 50 美金(約 2.5 條 workflow),且仍在成長

一台 2 核 4GB VPS 月費 10-15 美金就能跑好幾十條 workflow,一年省到數萬台幣

資料主權

workflow 處理 PII、客戶資料、合約、報價

雲端版資料存在歐盟(n8n)或美國(整合服務),資料出境與個資法合規性要自己評估

資料量

單月 execution 數超過 5 萬 / workflow 數超過 20 條

Cloud 的計費模型對高頻小動作的 workflow 很不友善

整合深度

要串自家 PostgreSQL、內網 ERP、不想對外開放的 API

自架 n8n 跟內網服務同一個 VPC,不用額外 VPN

詳細的雲端 vs 自架成本試算在 n8n 費用怎麼算 這篇有一張 36 個月的 TCO 對照表,含維運人力的隱藏成本。要先理解 n8n、Make、Zapier 的三方差異可以看 n8n vs Make vs Zapier 完整比較,若已經在用 Make 想評估遷移成本,另有 Make.com 自動化教學完整指南 可以對照。

自架之後,實戰的案例可以看 n8n + ChatGPT 企業自動化 6 個真實案例、語音轉錄自動化(Google Speech + n8n),第一次接觸 n8n 的話建議先讀 5 分鐘學會 n8n 教學。

我們怎麼看自架 n8n

ℹ️我們怎麼看

市面上講 n8n 自架的教學幾乎都在教「怎麼跑起來」,但真正會翻船的從來跟跑不跑得起來無關,問題都出在跑三個月之後:execution 紀錄沒 prune、備份沒驗證過還原、encryption key 存在同一台 server 上。這三件事在 docker-compose 範本裡看不到,卻決定你的自架 n8n 兩年後還救不救得回來。我們內部的做法是:第一天就把備份腳本和 prune 設定寫好,等到爆炸那天再補通常已經晚了。

另一個常見誤區是把「自架」想得太重:以為非得買實體機、租機櫃。實務上一台 DigitalOcean / Hetzner / Vultr 的 2 核 4GB VPS(月費 10-15 美金)就能撐住一間中小企業大部分的自動化需求。n8n 本身很輕量,吃資源的通常是你串的那些 API 的回應資料。

如果你評估下來覺得自架划算、但團隊沒人有 DevOps 經驗,直接整套包給外部做會比較穩,起手包含主機規劃、docker-compose 架設、備份策略、監控告警、第一輪 workflow 導入。我們做過幾個這類案子,想了解可以直接聊:

想把 n8n 自架整套交出去?

從主機選型、docker-compose 寫起、備份策略、監控告警到第一波 workflow 導入,一次做完。客製化系統開發 的頁面有實際案例,或可以先聊聊你們的流程適不適合(通常 15 分鐘就能看出來)。

常見問題

Qn8n 自架一定要用 Docker 嗎?用 PM2 跑 Node 可以嗎?

技術上可以,但不建議。PM2 版本綁死主機的 Node runtime,n8n 升級常常順便升 Node,手動 reinstall 遇到相依衝突會卡很久。Docker image 把 Node、n8n、相依工具全部打包,升級只需要換 tag。生產環境 Docker 幾乎沒有爭議。

QN8N_ENCRYPTION_KEY 可以中途更換嗎?

可以,但要走 n8n 內建的 re-encrypt 流程,不能直接改 env 變數。改法:先用舊 key 匯出所有 credentials、換新 key、重啟 n8n、把 credentials 重新匯入(n8n 會用新 key 重新加密)。建議在初次架設就產生一個夠強的 key 存進保險箱,往後不要輕易換。

Q自架的 n8n 可以多人同時使用嗎?

1.x 版本已經支援多使用者(含角色權限),後台可以建帳號、分配 workflow 的存取權。免費授權(Community Edition)在使用者數量上沒有硬限制,但內部政策每個使用者仍受官方授權條款約束。想要 SSO、SAML、企業審計 log 這些功能要上付費版(n8n Enterprise)。

QDocker 自架版可以裝 community nodes 嗎?

可以,n8n 自架版支援從 npm 安裝社群節點,啟動時加環境變數 N8N_COMMUNITY_PACKAGES_ENABLED=true,後台 Settings → Community nodes 可以搜尋安裝。但社群節點品質參差,正式工作流用之前先看一下 GitHub star 數、最後更新時間、issue 數。

Q升級失敗 workflow 跑不了怎麼辦?

回滾分兩種情況。沒跑過 DB migration:改 compose 的 image tag 回上一個版本、docker compose up -d 就回去了。已經跑過 migration:這時 DB schema 已經是新版,用舊 image 連不上,必須從備份還原 DB。這就是為什麼升級前一定要跑備份,而且備份要包含 PostgreSQL dump 不能只備 volume。

Qn8n Cloud 要搬到自架,workflow 可以直接搬嗎?

workflow 本身可以用「匯出 JSON」帶走,但 credentials 不行(Cloud 不給你看明文密碼)。遷移步驟:Cloud 匯出 workflow JSON → 自架版匯入 → 每個 credential 重新建一次(API key、OAuth token 都要重新接)。工作量取決於你有多少 credentials,20 條以內通常半天可以搞定。

把自架 n8n 整條鏈路(compose 範本、環境變數、PostgreSQL、備份、升級)寫到可以直接複製貼上,是因為我們自己踩過的每一個坑都想幫你避開。n8n 的強大在於「願意動手就幾乎沒有做不到的自動化」,但願意動手跟做對是兩件事。如果這篇幫到你,收藏一下;想交給我們做可以直接聊,不收費評估通常 15 分鐘就能看出流程適不適合。

分享文章
恆

AUTHOR

恆遠數位編輯團隊

查看作者頁

留言(0)

尚無留言,成為第一個留言的人吧!

需要網站系統架設或軟體開發?

無論是品牌官網、客製化系統還是應用程式,我們的團隊擁有豐富經驗,歡迎聯繫我們,讓專業為您的事業加分。