跳至主要內容
n8n Docker Cloudflare Tunnel Deployment Architecture

完整教學:Docker + Cloudflare Tunnel 部署 n8n

4 分

這篇文章記錄 SuperPortia 把 n8n v2.13.2 部署到 MacBook Air M3 的完整過程。最終架構:Docker 容器本機跑、Cloudflare Tunnel 穿透到公網、CF Access 做 Email 認證、MCP Server 對 Claude Code 開放。全程沒有額外費用,資料不出本機。

如果你想先理解為什麼要 self-host 而非用 Make.com / Zapier,先看上一篇:n8n Self-Hosted:為什麼我們選擇自建而非 SaaS

最終架構圖

graph TB
    Browser["🌐 瀏覽器\nn8n.superportia.dev"] -->|HTTPS| CFA["Cloudflare Access\nEmail 認證閘道"]
    CFA -->|通過驗證| CFT["Cloudflare Tunnel\nubi-mcp tunnel"]
    CFT -->|內部連線| LH["localhost:5678"]
    Claude["🤖 Claude Code\n(本機)"] -->|MCP / HTTP| LH
    LH --> Docker["Docker Container\nn8nio/n8n:2.13.2"]
    Docker --> Data["~/Documents/n8n-data\nSQLite + workflows"]
    Docker --> Bind["127.0.0.1:5678\n(不對外)"]

關鍵設計:Docker 只綁 127.0.0.1,5678 port 從不直接對外暴露。外部存取全部走 Cloudflare Tunnel,本機 AI 工具(Claude Code)走 localhost 直連。

前置條件

需要用途
Docker Desktop(Mac)或 Docker Engine(Linux)跑 n8n 容器
Cloudflare 帳號 + 你管理的域名Tunnel + Access + DNS
cloudflared CLI設定和跑 Tunnel
一個 Email 帳號CF Access 認證用
這篇假設 Mac + Docker Desktop 環境

Linux VPS 的流程幾乎相同,差別在 Docker 安裝方式和 launchd 換成 systemd。Windows 也可行,但路徑格式和 volume 掛載方式不同,本文不另外說明。


Step 1:建立資料目錄

n8n 把所有資料(workflows、credentials、execution log、SQLite DB)都存在 ~/.n8n 或你掛載的路徑。我們用獨立目錄方便備份和管理:

mkdir -p ~/Documents/n8n-data
chmod 700 ~/Documents/n8n-data

chmod 700 確保只有你的用戶可以讀寫這個目錄,防止其他本機用戶或程式意外存取。


Step 2:啟動 Docker 容器

完整的 docker run 指令:

docker run -d \
  --name n8n \
  --restart unless-stopped \
  -p 127.0.0.1:5678:5678 \
  -e N8N_HOST=n8n.superportia.dev \
  -e N8N_PORT=5678 \
  -e N8N_PROTOCOL=https \
  -e NODE_ENV=production \
  -e WEBHOOK_URL=https://n8n.superportia.dev/ \
  -e N8N_ENCRYPTION_KEY=<your-32-char-random-key> \
  -e N8N_MCP_ENABLED=true \
  -e N8N_RUNNERS_ENABLED=true \
  -v ~/Documents/n8n-data:/home/node/.n8n \
  n8nio/n8n:2.13.2

環境變數詳解

變數說明
N8N_HOSTn8n.superportia.devn8n 認為自己跑在哪個域名,影響 OAuth redirect 和 webhook URL
N8N_PORT5678容器內部 port
N8N_PROTOCOLhttps告訴 n8n 外部是 HTTPS(透過 Tunnel),避免 HTTP/HTTPS 混合問題
NODE_ENVproduction關閉除錯輸出,效能更好
WEBHOOK_URLhttps://n8n.superportia.dev/Webhook 觸發器的完整 base URL,含結尾斜線
N8N_ENCRYPTION_KEY32 字元亂數字串加密儲存在 DB 裡的 credentials(API keys 等)。絕對不能遺失,否則所有憑證作廢
N8N_MCP_ENABLEDtrue啟用 Instance-level MCP Server(v2.13+ 新功能)
N8N_RUNNERS_ENABLEDtrue啟用 Task Runners(execution 效能優化)
Warning

產生方式:openssl rand -hex 16(32 字元 hex string)

-p 127.0.0.1:5678:5678 是核心安全設定

這行把 port 5678 綁定到 loopback interface(127.0.0.1),不是 0.0.0.0。效果:

  • ✅ 本機 Claude Code 可以直連 localhost:5678
  • ✅ Cloudflare Tunnel 可以透過 loopback 連到容器
  • ❌ 外網無法直接連 5678(即使你的防火牆有漏洞)

如果寫成 -p 5678:5678,n8n 就直接暴露在所有 interface 上,任何人都能存取。永遠不要這樣做

驗證容器跑起來了

docker ps | grep n8n
# 應該看到:n8n   n8nio/n8n:2.13.2   ... 127.0.0.1:5678->5678/tcp ...

curl -s http://localhost:5678/healthz
# 應該回傳:{"status":"ok"}

Step 3:Cloudflare Tunnel 設定

Cloudflare Tunnel(前身 Argo Tunnel)讓你的本機服務可以透過 Cloudflare 網路暴露到公網,不需要開 port 或設 NAT。

SuperPortia 使用 ubi-mcp tunnel,這個 tunnel 已經服務 api.superportia.devllm.superportia.devnote.superportia.dev——n8n 加進同一個 tunnel 就行,不需要建新的。

安裝 cloudflared

# Mac with Homebrew
brew install cloudflared

# Linux (Debian/Ubuntu)
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb
sudo dpkg -i cloudflared.deb

建立新 Tunnel(如果你還沒有)

cloudflared tunnel login          # 開瀏覽器授權
cloudflared tunnel create ubi-mcp # 建立 tunnel,名稱自訂

執行後會在 ~/.cloudflared/ 產生 credentials JSON 和 cert.pem。

設定 ingress(加入 n8n)

編輯 ~/.cloudflared/config.yml

tunnel: <your-tunnel-id>
credentials-file: /Users/<username>/.cloudflared/<tunnel-id>.json

ingress:
  # 既有服務(範例)
  - hostname: api.superportia.dev
    service: http://localhost:8788

  # n8n — 新增這段
  - hostname: n8n.superportia.dev
    service: http://localhost:5678
    originRequest:
      noTLSVerify: false

  # 必須有 catch-all
  - service: http_status:404

設定 DNS 記錄

cloudflared tunnel route dns ubi-mcp n8n.superportia.dev

這會在 Cloudflare DNS 自動建立一條 CNAME 指向你的 tunnel。

啟動 Tunnel(背景服務)

Mac launchd 方式(推薦,開機自動啟動):

sudo cloudflared service install
sudo launchctl start com.cloudflare.cloudflared

臨時測試方式

cloudflared tunnel run ubi-mcp

驗證 Tunnel 連通

# 從外部(或用手機)測試
curl -s https://n8n.superportia.dev/healthz
# 如果 CF Access 已開,會收到 403(正常,代表 Tunnel 通了,Access 在守門)
# 沒有 CF Access 時應該回傳 {"status":"ok"}

Step 4:Cloudflare Access 認證閘道

Cloudflare Access 在 n8n 前加一道身份驗證。未登入的請求直接被擋下,n8n 內建的用戶認證系統(email + 密碼)作為第二道防線。

在 CF Dashboard 建立 Access Application

  1. 前往 Cloudflare DashboardZero TrustAccessApplications
  2. Add an application → 選 Self-hosted
  3. 填入:
    • Application name:n8n Automation
    • Session Duration:24 hours(根據需求調整)
    • Application domain:n8n.superportia.dev
  4. 建立 Policy
    • Policy name:Email Allowlist
    • Action:Allow
    • 在 Include 加入 Emails → 輸入你的 email(如 [email protected]
  5. 儲存
可以加多個 Email

Access Policy 支援多個 email 或整個 email domain(例如@superportia.dev)。如果你要讓多人存取,在同一個 policy 裡加入所有授權 email,或用 Emails ending in 規則。

測試 Access

在一個未登入的瀏覽器(無痕模式)開啟 https://n8n.superportia.dev,應該跳到 Cloudflare Access 的 email 驗證頁面,輸入授權 email 後會收到 one-time code。驗證通過後才能看到 n8n。


Step 5:安全加固檢查清單

部署完成後,過一遍這個清單:

☑ Docker 只綁 127.0.0.1(-p 127.0.0.1:5678:5678)
☑ N8N_ENCRYPTION_KEY 已備份到密碼管理器
☑ n8n-data 目錄權限 700(chmod 700 ~/Documents/n8n-data)
☑ Cloudflare Access 設定 Email 白名單
☑ n8n 內建用戶認證系統已設定(第一次登入建立 owner 帳號,email + 密碼)
☑ CF Tunnel 設為開機自動啟動
☑ Docker restart policy = unless-stopped
☑ 測試過從外部(手機/其他網路)存取需要 CF Access 驗證
Warning

如果你只有 CF Access 而 n8n 沒有設帳號,未來如果 CF 設定出問題,n8n 等於完全無保護。


實戰:Codex 安全加固筆記

審查時間:2026-03-22 02:00–04:00(Taipei)
範圍:Codex read-only sandbox,filesystem + web search,無 Docker daemon 存取
性質:這不是正式滲透測試,而是 AI 輔助的安全加固過程(hardening review)——找設定漏洞並立即修復,不包含攻擊模擬或漏洞利用

我們在部署完成後,立即派 OpenAI Codex(GPT-5.4, read-only sandbox)做了兩輪安全加固審查。以下是真實的發現和修復過程,不是事後編寫的理想狀態。

第一輪審查(部署後立即,222K tokens)

嚴重度發現修復
HIGHJWT token 明文存在 ~/.claude.json,檔案權限 0644(任何人可讀)chmod 600 ~/.claude.json
HIGHDocker 預設綁定 0.0.0.0:5678,macOS firewall 關閉,LAN 內任何裝置可直接存取 n8n重建容器改為 -p 127.0.0.1:5678:5678
HIGHCF Tunnel 直接轉發,沒有 Cloudflare Access 保護,n8n 登入頁暴露在公網新增 CF Access Application + Email policy
MEDIUMn8n-data/database.sqlite 權限 0644,含加密金鑰和用戶資料chmod 700 目錄 + chmod 600 所有 DB/log 檔案
MEDIUM只有一個 owner 帳號,沒有 MFA已加 CF Access 作為外層保護,MFA 待後續啟用
MEDIUMVault note 記載了 owner 密碼明文已從 vault note 移除明文密碼
教訓:預設配置不等於安全配置

Docker 的-p 5678:5678 預設綁定所有網路介面,這代表你的 n8n 在同一個 Wi-Fi 網路下,任何人只要知道你的區網 IP 就能存取。務必明確寫 127.0.0.1:

第二輪審查(安全修復後,133K tokens)

第一輪修復完成後,瀏覽器地址欄仍顯示「不安全」。再派 Codex 排查:

發現原因修復
n8n 生成 http:// 內部 URL缺少 N8N_HOSTN8N_PROTOCOL 環境變數加入 N8N_HOST=n8n.superportia.dev + N8N_PROTOCOL=https
Cookie 不帶 Secure flagN8N_SECURE_COOKIE=false改為 true(因為走 CF Tunnel 全程 HTTPS)
缺少 SameSite cookie 設定未設定 N8N_SAMESITE_COOKIE加入 N8N_SAMESITE_COOKIE=lax
執行記錄無限增長未設定 prune加入 EXECUTIONS_DATA_PRUNE=true + EXECUTIONS_DATA_MAX_AGE=168

修復後的完整環境變數

docker run -d \
  --name n8n \
  --restart unless-stopped \
  -p 127.0.0.1:5678:5678 \
  -v ~/Documents/n8n-data:/home/node/.n8n \
  -e GENERIC_TIMEZONE=Asia/Taipei \
  -e N8N_HOST=n8n.superportia.dev \
  -e N8N_PROTOCOL=https \
  -e N8N_EDITOR_BASE_URL=https://n8n.superportia.dev \
  -e WEBHOOK_URL=https://n8n.superportia.dev/ \
  -e N8N_PROXY_HOPS=1 \
  -e N8N_SECURE_COOKIE=true \
  -e N8N_SAMESITE_COOKIE=lax \
  -e EXECUTIONS_DATA_PRUNE=true \
  -e EXECUTIONS_DATA_MAX_AGE=168 \
  docker.n8n.io/n8nio/n8n:2.13.2
AI 輔助安全加固的成效

我們的做法是:部署 → 立即派 AI 加固審查 → 修復 → 再審查。兩輪共消耗 355K tokens(222K + 133K,Codex),找出 6 個 HIGH/MEDIUM 設定問題。這不是滲透測試,而是系統化地把預設配置轉換成安全配置。成本:幾美金。價值:避免一次因為「不知道」導致的安全事件。


Step 6:MCP Server 設定(選用)

如果你要讓 Claude Code 透過 MCP 控制 n8n(這是本系列第三篇的主題),先在 n8n UI 啟用 Instance-level MCP:Settings → Instance-level MCP → Enable。啟用後會生成一組 JWT Access Token。

接著在 Claude Code 端加入 MCP server:

claude mcp add --transport http --scope user n8n \
  http://localhost:5678/mcp-server/http \
  --header "Authorization: Bearer <你的 JWT token>"

或手動編輯 ~/.claude.json

{
  "mcpServers": {
    "n8n": {
      "type": "http",
      "url": "http://localhost:5678/mcp-server/http",
      "headers": {
        "Authorization": "Bearer <JWT token from n8n Settings>"
      }
    }
  }
}
MCP 走 localhost,不走外部 URL

Claude Code 和 n8n 在同一台機器上,MCP 直接走localhost:5678,不需要過 CF Tunnel。外部 URL (https://n8n.superportia.dev) 留給人類用瀏覽器登入 — 有 CF Access 保護。

完整的 MCP 整合說明在下一篇:n8n MCP Server × Claude Code:AI 直接操控工作流


常見問題排除

n8n 起不來,docker logs 顯示 permission denied

# 問題:n8n 容器的 user 是 node(uid 1000),無法寫入 n8n-data
# 解法:確認 volume 掛載路徑存在且 n8n 可以寫入
ls -la ~/Documents/n8n-data
# 如果是空目錄但 Docker volume 有問題,嘗試:
docker run --rm -v ~/Documents/n8n-data:/home/node/.n8n n8nio/n8n:2.13.2 n8n --version

Tunnel 連得到但 n8n 回傳 502

# 確認 n8n 容器真的在跑
docker ps | grep n8n

# 確認 healthz 在本機可以回應
curl localhost:5678/healthz

# 確認 tunnel config 的 service URL 正確
cat ~/.cloudflared/config.yml | grep -A 2 "n8n.superportia"

CF Access 一直跳出認證,無法通過

原因通常是 session cookie 設定問題。確認:

  1. Access Application 的 domain 設定是 n8n.superportia.dev(不含萬用字元)
  2. 如果你的域名有 WAF 規則,確認沒有阻擋 CF Access 的 token cookie

重新開機後 n8n 沒有自動啟動

# 確認 Docker Desktop 的「Start at login」有開
# 確認 container restart policy
docker inspect n8n | grep -A 2 RestartPolicy
# 應該看到 "Name": "unless-stopped"

# cloudflared 的啟動確認
sudo launchctl list | grep cloudflared

遷移:把 n8n 從舊機器搬到新機器

# 舊機器:備份整個 n8n-data 目錄
tar -czf n8n-backup-$(date +%Y%m%d).tar.gz ~/Documents/n8n-data

# 新機器:解壓縮到同樣路徑
tar -xzf n8n-backup-20260322.tar.gz -C ~/Documents/

# 用完全相同的 docker run 指令啟動(尤其是 N8N_ENCRYPTION_KEY 必須一致)
定期備份 n8n-data

n8n 的所有狀態都在這個目錄:workflows、credentials、execution history、SQLite DB。建議設定 cron 定期備份到 R2 或本地 NAS。一個簡單的做法:0 2 * * * tar -czf /backup/n8n-$(date +\%Y\%m\%d).tar.gz ~/Documents/n8n-data


部署後的下一步

基礎設施跑起來之後,有兩個方向可以繼續:

  1. 接上 Claude Code MCP:讓 AI 直接建立和管理工作流 → 詳見 n8n MCP Server × Claude Code:AI 直接操控工作流

  2. 開始規劃實際工作流:SuperPortia 規劃中的 5 個自動化場景 → 詳見 n8n 實戰應用:5 個我們正在規劃的自動化場景

...lare Tunnel 作為唯一入口、Cloudflare Access 的 Email 認證閘道、檔案權限 700。這套設定比大多數人的 SaaS 帳號安全設定還嚴格。完整安全設定詳見本系列第二篇:[[完整教學:Docker + Cloudflare Tunnel 部署 n8n]]。 4. AI-native...

在此文章中被引用