Evolution API Redis 連線中斷與 YunoHost/Docker 設置上的 Iptables 錯誤

描述問題/錯誤/疑問

環境:

  • 作業系統: Debian 12(透過 YunoHost)

  • 設定: Evolution API 在 Docker 中執行,與 YunoHost 服務並行運作(n8n 等)

  • 基礎設施: 自架在 VPS 上

問題: 我透過 Docker Compose 執行 Evolution API。儘管在 docker-compose.yml 中定義了 Redis 服務,API 日誌卻充滿了:[Redis] redis disconnected

此外,當我嘗試使用 docker compose up -d 重新啟動堆疊時,偶爾會遇到此網路錯誤:Failed to Setup IP tables: Unable to enable ACCEPT OUTGOING rule: (iptables: No chain/target/match by that name)

我目前的 docker-compose.yml 片段:

  evolution_api:
    image: atendai/evolution-api:latest
    environment:
      - CACHE_REDIS_ENABLED=true
      - CACHE_REDIS_HOST=redis
      - CACHE_REDIS_PORT=6379
    depends_on:
      - redis

  redis:
    image: redis:7-alpine

我已嘗試的方法:

  1. CACHE_REDIS_HOST 變更為 redis://redis:6379

  2. 執行 yunohost firewall reload

  3. 嘗試透過將 n8n 設定為「訪客」存取權限來繞過 YunoHost SSO。

疑問:

  1. YunoHost 的原生 Redis 服務或其 iptables 管理(AFW)是否已知會與 Docker 內部網路衝突?

  2. 我該如何確保 Docker 容器繞過 YunoHost 的防火牆規則,以維持與其自身 Redis 容器的穩定連線?

  3. 我是否應該手動注入特定的 DOCKER-USER 鏈規則以阻止 ACCEPT OUTGOING 失敗?

錯誤訊息是什麼(如有的話)?

關於 n8n 設定的資訊

  • n8n 版本:2.15.1
  • 資料庫(預設值:SQLite):預設值
  • n8n EXECUTIONS_PROCESS 設定(預設值:own、main):預設值
  • 執行 n8n 的方式(Docker、npm、n8n cloud、桌面應用程式):systemd 服務(YunoHost)
  • 作業系統:Debian 12

看看下面的内容是否有帮助。

这很可能是 Docker 的网络引擎YunoHost 的防火墙 (AFW) 在 Debian 12 上的经典冲突。

根本原因是 YunoHost 使用 nftables(以前使用 iptables)管理防火墙,当它重新加载或应用规则时,经常会刷新 iptables 链。Docker 创建自己的自定义链(如 DOCKER 链)来处理容器路由。当 YunoHost 刷新这些链时,Docker 尝试向一个不再存在的链添加规则,导致错误:iptables: No chain/target/match by that name

因为网络规则被破坏了,你的 evolution_api 容器看不到 redis 容器,即使它们在同一个 compose 文件中。这导致了 redis disconnected 的大量输出。

这是修复这两个问题的分步解决方案。

1. 修复配置 (Evolution API)

Evolution API 需要一个连接 URI,而不是单独的 Host 和 Port 变量。你使用的是 CACHE_REDIS_HOST,API 很可能会忽略它而使用 CACHE_REDIS_URI。

**更新你的 docker-compose.yml 环境部分:**删除 CACHE_REDIS_HOST 和 CACHE_REDIS_PORT,用 CACHE_REDIS_URI 替换。

# 改这个:
- CACHE_REDIS_ENABLED=true
- CACHE_REDIS_HOST=redis
- CACHE_REDIS_PORT=6379

# 改成这个:
- CACHE_REDIS_ENABLED=true
- CACHE_REDIS_URI=redis://redis:6379

(注意:如果你为 Redis 使用了密码,格式是 redis://:password@redis:6379

2. 解决 iptables / YunoHost 冲突

要修复 Unable to enable ACCEPT OUTGOING rule 错误并恢复容器之间的连接,你必须确保 Docker 在 YunoHost 初始化防火墙之后重新创建其网络链。

快速修复(手动)

依次运行这些命令来清除冲突并强制 Docker 重建其规则:

# 1. 先重新加载 YunoHost 防火墙
yunohost firewall reload

# 2. 重启 Docker 守护程序以强制它重新注入其链到 iptables
sudo systemctl restart docker

# 3. 启动你的堆栈
docker compose up -d

永久修复(自动化)

由于 YunoHost 可能在更新或通过 WebUI 时重新加载防火墙,Docker 的规则会再次被破坏。为了防止这种情况,你可以创建一个简单的 systemd 覆盖来确保在防火墙更改时 Docker 重启,或更简单地添加一个 cron 作业/钩子。

然而,在 YunoHost 上最稳定的方法是确保 Docker 是最后启动的。如果你发现这在重启后经常发生,运行:

sudo systemctl enable docker

如果你手动重新加载防火墙,始终在其后运行 sudo systemctl restart docker

回答你的具体问题:

1. YunoHost 的本地 Redis 或 iptables 管理是否已知会冲突?

是的。 YunoHost 的防火墙管理很激进。它不

您好,

感謝您的回答。

我試過您的 docker compose 設定,但無法成功。「Redis disconnected」錯誤仍在繼續。以下是我最新的 docker-compose.yml 文件:

version: '3.8'

services:
  evolution_api:
    image: atendai/evolution-api:latest
    container_name: evolution_api
    restart: always
    network_mode: "host"
    ports:
      - "8080:8080"
    environment:
      - SERVER_TYPE=http
      - SERVER_PORT=8080
      - SERVER_URL=http://my-server-ip:8080
      - CORS_ORIGIN=*
      - CORS_METHODS=GET,POST,PUT,DELETE,PATCH
      - AUTHENTICATION_TYPE=apikey
      - WA_PHONE_VERSION=2.3000.10125062854
      - CONFIG_SESSION_PHONE_CLIENT=Chrome
      - AUTHENTICATION_API_KEY=my-auth-api-key

      # Connecting to YunoHost database
      - DATABASE_ENABLED=true
      - DATABASE_PROVIDER=postgresql
      - DATABASE_CONNECTION_URI=postgresql://evolution:password@localhost:5432/evolution?schema=public

      # Connecting to YunoHost's Redis
      - CACHE_REDIS_ENABLED=true
      - CACHE_REDIS_URI=redis://redis:6379

另外,我還有一個問題,您認為為什麼 QR 碼沒有出現?當我查看瀏覽器上的請求時,似乎沒有任何問題。一切看起來都是 200 OK。謝謝您。

您仍然看到"Redis disconnected"的原因是您新的docker-compose.yml中存在網路不匹配。

問題:network_mode: "host" vs. redis://redis

您已切換到network_mode: "host"。在此模式下,容器沒有自己的內部Docker網路;它直接共享您VPS的網路。

  • 現在的工作方式: 在您的容器內,localhost與VPS的localhost相同。

  • 錯誤: 您告訴API在主機名redisredis://redis:6379)查找Redis。但是,由於您未使用Docker橋接網路,不存在"redis"的DNS條目。容器在您的網路上查找名為"redis"的機器,卻找不到它。

由於您正在嘗試連接到YunoHost的原生Redis(直接在主機OS上運行),您必須將其稱為localhost

問題:network_mode: "host" vs. redis://redis

您已切換到network_mode: "host"。在此模式下,容器沒有自己的內部Docker網路;它直接共享您VPS的網路。

  • 現在的工作方式: 在您的容器內,localhost與VPS的localhost相同。

  • 錯誤: 您告訴API在主機名redisredis://redis:6379)查找Redis。但是,由於您未使用Docker橋接網路,不存在"redis"的DNS條目。容器在您的網路上查找名為"redis"的機器,卻找不到它。

由於您正在嘗試連接到YunoHost的原生Redis(直接在主機OS上運行),您必須將其稱為localhost

解決方案:更新docker-compose.yml

將您的CACHE_REDIS_URI改為使用localhost

services:
  evolution_api:
    image: atendai/evolution-api:latest
    container_name: evolution_api
    restart: always
    network_mode: "host" 
    # 注意:使用network_mode: host時會忽略'ports',
    # 該應用將自動綁定到您VPS IP的8080端口。
    environment:
      - SERVER_TYPE=http
      - SERVER_PORT=8080
      - SERVER_URL=http://my-server-ip:8080
      - CORS_ORIGIN=*
      - CORS_METHODS=GET,POST,PUT,DELETE,PATCH
      - AUTHENTICATION_TYPE=apikey
      - WA_PHONE_VERSION=2.3000.10125062854
      - CONFIG_SESSION_PHONE_CLIENT=Chrome
      - AUTHENTICATION_API_KEY=my-auth-api-key

      # 連接到YunoHost數據庫(正確)
      - DATABASE_ENABLED=true
      - DATABASE_PROVIDER=postgresql
      - DATABASE_CONNECTION_URI=postgresql://evolution:password@localhost:5432/evolution?schema=public

      # 連接到YunoHost的Redis(已修復)
      - CACHE_REDIS_ENABLED=true
      - CACHE_REDIS_URI=redis://localhost:6379 

重要步驟: 保存文件後,運行:

docker compose up -d

為什麼QR碼沒有出現

您提到瀏覽器請求返回200 OK,但沒有QR碼顯示。這直接由Redis斷開連接引起。

以下是技術原因:

  1. 請求(200 OK): 當您請求QR碼時,API服務器正在運行,所以它接受請求並返回有效的HTTP響應。“200 OK"只是表示"服務器正常運行並收到您的請求。”

  2. 處理(失敗): 要生成QR碼,Evolution API必須使用Baileys庫初始化WhatsApp會話。該庫需要存儲會話狀態和臨時連接數據。

  3. 崩潰: Evolution API使用Redis來管理此狀態。由於Redis斷開連接,API無法在後台創建會話。它向瀏覽器返回成功響應,但負載(實際QR碼數據)為空或無效,因為後端進程在嘗試寫入Redis時崩潰。

一旦您將CACHE_REDIS_URI修復為localhost並且"Redis disconnected"日誌停止,QR碼將立即出現。

YunoHost用戶的最終提示

如果即使更改為localhost後仍然看到"Redis disconnected",則意味著YunoHost的Redis配置為僅允許來自特定用戶的連接或設有密碼。

通過在VPS終端上運行以下命令,檢查YunoHost Redis是否有密碼:

redis-cli ping

  • 如果返回PONG,表示已打開。

  • 如果返回(error) NOAUTH Authentication required,您必須將密碼添加到您的URI中:redis://:yourpassword@localhost:6379

感謝你的回答。

我其實已經解決了 Redis 和 QR 顯示的兩個問題。

關於 Redis 的第一個問題,你的解決方案對我有效。按照你在 compose 文件中指示的更改就足夠了,我還重啟了 YunoHost (AFW) 防火牆和 Docker。

對於第二個問題,我發現 Evolution API 映像因為舊的 WhatsApp 協議而不再受支援。我更換了映像,它立即就能運作,甚至不需要更改我的 compose 文件。我已經在下面分享了我的設定:

version: '3.8'

services:
  evolution_api:
    image: evoapicloud/evolution-api:latest # 這是穩定版本
    container_name: evolution_api
    restart: always
    network_mode: "host"

    environment:
      - SERVER_TYPE=http
      - SERVER_PORT=8080
      - SERVER_URL=http://your-server-ip:8080
      - CORS_ORIGIN=*
      - CORS_METHODS=GET,POST,PUT,DELETE,PATCH
      - AUTHENTICATION_TYPE=apikey
      - AUTHENTICATION_API_KEY=your-api-key
      # 分別提及 WhatsApp 電話版本和瀏覽器。
      - WA_PHONE_VERSION=2.3000.1030415680
      - CONFIG_SESSION_PHONE_CLIENT=Chrome

      # 我們要使用 YunoHost 的資料庫。
      - DATABASE_ENABLED=true
      - DATABASE_PROVIDER=postgresql
      - DATABASE_CONNECTION_URI=postgresql://evolution:password@localhost:5432/evolution?schema=public
      - CACHE_REDIS_ENABLED=true
      - CACHE_REDIS_URI=redis://localhost:6379

      # 選項:額外穩定性的設定。
      - DELAY_MESSAGE=1000
      - QR_CODE_EXPIRATION=600

    volumes:
      - ./evolution_instances:/evolution/instances

即使解決了這些問題,仍然還有一個問題:我已經設定了 Evolution API 觸發節點,但當 n8n 收到回應時,它卡在「載入資料。」但在執行普通節點時沒有問題。只有在執行觸發節點時才會出現。我已經在 GitHub 上開啟了一個問題,但還沒有找到任何修復資源。你對此有任何資訊嗎?感謝。

很高興聽到 Redis 和 QR 碼問題已經解決!改用 evoapicloud 映像檔是正確的選擇——atendai 映像檔確實已經過時,經常無法與目前的 WhatsApp Web 協議相容。

關於 n8n 觸發節點卡在**「載入資料」**,這是在同一台 YunoHost 伺服器上執行 n8n 和 Evolution API 時的一個常見問題。

由於你的一般節點可以正常運作,所以「管道」(API → n8n)對於請求來說是有效的。但是,觸發節點的運作方式相反:API 會向 n8n 發送 Webhook。當 n8n 處於「監聽」模式並顯示「載入資料」時,它正在等待有效的 HTTP 請求擊中其 Webhook 端點。

以下是在你的特定 YunoHost 設置中最可能發生這種情況的三個原因:

1. 「髮夾」網路問題(最可能)

你可能在 Evolution API webhook 設定中使用了 n8n 實例的公開 URL(例如 https://n8n.yourdomain.com/webhook/...)。

問題: 當 Evolution API(在同一伺服器上)嘗試將資料發送到你的公開 URL 時,請求會發送到你的 VPS IP,然後嘗試返回。許多防火牆(包括 YunoHost 的 AFW/iptables)和一些 VPS 提供商出於安全考慮會阻止這種「迴路」(髮夾 NAT)。請求永遠無法到達 n8n,因此節點會永遠停留在「載入資料」。

修復方法: 在 Evolution API webhook 設定中,嘗試使用 n8n 的內部位址而非公開位址。

  • 變更: https://n8n.yourdomain.com/webhook/...

  • 改為: http://localhost:5678/webhook/...(或 n8n 在內部執行的任何連接埠)。

2. n8n WEBHOOK_URL 環境變數

如果 n8n 不知道自己的公開 URL,它有時會產生使用 localhost 或內部 IP 的「測試」Webhook URL,這取決於 Docker 網路如何與 YunoHost systemd 服務互動,Evolution API 可能無法正確路由。

修復方法: 確保你的 n8n 服務(通過 YunoHost 或環境變數)已明確設定 WEBHOOK_URL

WEBHOOK_URL=https://n8n.yourdomain.com/

如果未設定此變數,n8n 可能會給 API 一個在 UI 中看起來正確但對於傳入請求來說實際上已損毀的 URL。

3. 資料承載不匹配(「UI 掛起」)

由於你改用了 evoapicloud 映像檔,發送到 n8n 的事件 JSON 結構可能與 n8n Evolution API 節點期望的結構略有不同。

當 n8n 的觸發節點收到無法解析為預期架構的請求時,UI 有時會停留在「載入資料」而不是顯示錯誤,因為它陷入了迴圈,嘗試將傳入的 JSON 映射到節點的內部欄位。

如何測試:

  1. 在 n8n 中建立標準的 Webhook 節點(不是 Evolution API 觸發節點)。

  2. 複製該 Webhook URL 並將其放入 Evolution API webhook 設定中。

  3. 觸發事件(向機器人發送訊息)。

  4. 如果標準 Webhook 節點接收了資料,那麼問題是 Evolution API 觸發節點中的架構不匹配。在這種情況下,你可以實際上使用標準 Webhook 節點和「設定」或「代碼」節點來建立整個工作流以清理資料——這通常比使用專用觸發節點更穩定。

你的檢查清單摘要:

  1. 使用標準 Webhook 節點進行測試。 如果這有效,問題是觸發節點的代碼(架構不匹配)。

  2. 將 Evolution API 中的 Webhook URL 變更為 http://localhost:5678/... 以繞過 YunoHost 防火牆/迴路問題。

  3. 檢查 n8n 日誌sudo journalctl -u n8n 或類似命令),在節點「載入資料」時查看是否出現任何 403 ForbiddenConnection Refused 錯誤。

神奇的是,我通過將 n8n 從版本 1.15.1 更新到 1.19.2 解決了這個問題,不過我真的不明白它是如何解決的。