自架伺服器讓 Telegram、LINE、Discord Webhook 連通的完整指南

管管
教學文章 技術分享
伺服器網路連線示意圖

架好了 Bot 伺服器,設定了 Webhook URL,結果訊息就是收不到?這篇文章整理了所有可能的原因和解決方法,從網路基礎到各平台的設定細節,讓你不用再到處問人。

Webhook 連通的必要條件

在開始排查之前,先確認你理解 Webhook 的運作方式:是對方(Telegram/LINE/Discord)主動發請求到你的伺服器,不是你去拉資料。

這意味著你的伺服器必須滿足以下條件:

  • 外網可訪問:對方的伺服器能連到你
  • 有效的 HTTPS:幾乎所有平台都要求 SSL 憑證
  • 正確的 Port:通常是 443(HTTPS)或平台指定的 Port
  • 防火牆放行:你的伺服器/路由器沒有擋掉請求

少一個都不行。下面逐一說明。

第一關:你的伺服器外網能不能連?

情況一:雲端 VPS(AWS、GCP、Azure、Linode、DigitalOcean...)

恭喜,這是最簡單的情況。雲端 VPS 通常直接有公網 IP,你只需要:

  1. 確認安全群組(Security Group)/ 防火牆有開放 80 和 443 Port
  2. 確認伺服器本機的防火牆(iptables、ufw、firewalld)也有開
  3. 把你的服務綁定到 0.0.0.0 而不是 127.0.0.1

測試方法:

# 從外部測試(用手機網路或請朋友幫忙)
curl -I http://你的IP:你的Port/

# 或用線上工具
# https://www.yougetsignal.com/tools/open-ports/

情況二:家用網路 / 公司網路

這是最多人卡關的地方。家用網路通常是這樣的架構:

網際網路 → ISP 分配的 IP → 路由器 (NAT) → 你的電腦 (192.168.x.x)

外網連不進來的原因:

  • NAT 阻擋:路由器的 NAT 不會主動轉發外部請求
  • 沒有公網 IP:很多 ISP 給的是 CGNAT(100.x.x.x),根本沒有獨立的公網 IP
  • 動態 IP:就算有公網 IP,可能每次重開機就換一個

解決方案(選一個):

方案 A:Port Forwarding(需要有公網 IP)

  1. 登入路由器後台
  2. 找到「Port Forwarding」或「虛擬伺服器」設定
  3. 把外部 Port 443 轉發到你電腦的內網 IP 和 Port
  4. 設定 DDNS(如果是動態 IP)

方案 B:使用 ngrok / Cloudflare Tunnel(推薦)

不需要設定路由器,不需要公網 IP,一行指令搞定:

# ngrok
ngrok http 3000

# Cloudflare Tunnel(免費且穩定)
cloudflared tunnel --url http://localhost:3000

詳細教學請參考:ngrok 教學:讓外網 Webhook 安全連到你的本機開發環境

方案 C:租一台便宜的 VPS

月費 5 美金以下的 VPS 很多(Vultr、DigitalOcean、Linode),省去一堆網路設定的麻煩。

第二關:HTTPS 憑證設定

幾乎所有 IM 平台都要求 HTTPS,而且是有效的 SSL 憑證,自簽憑證通常不被接受。

方法一:Let"s Encrypt 免費憑證(推薦)

使用 Certbot 自動申請和續約:

# 安裝 Certbot(Ubuntu/Debian)
sudo apt install certbot

# 申請憑證(需要先有域名指向你的伺服器)
sudo certbot certonly --standalone -d yourdomain.com

# 憑證會存在 /etc/letsencrypt/live/yourdomain.com/

方法二:使用 Caddy(自動 HTTPS)

Caddy 是一個自帶 HTTPS 的網頁伺服器,設定超簡單:

# Caddyfile
yourdomain.com {
    reverse_proxy localhost:3000
}

啟動後它會自動幫你申請和續約 Let"s Encrypt 憑證。

方法三:Cloudflare(免費 SSL)

把域名的 DNS 託管到 Cloudflare,開啟 Proxy 模式,就有免費的 SSL。

  1. 註冊 Cloudflare 並添加你的域名
  2. 將 DNS 記錄指向你的伺服器 IP
  3. 確保 Proxy 狀態是橘色雲朵(開啟)
  4. SSL/TLS 設定選「Full」或「Full (Strict)」

第三關:各平台 Webhook 設定

Telegram

設定 Webhook:

curl "https://api.telegram.org/bot你的TOKEN/setWebhook?url=https://yourdomain.com/webhook/telegram"

檢查 Webhook 狀態:

curl "https://api.telegram.org/bot你的TOKEN/getWebhookInfo"

Telegram 的要求:

  • 必須是 HTTPS
  • 支援的 Port:443, 80, 88, 8443
  • 憑證必須是受信任的 CA 簽發(自簽可以,但要額外上傳憑證)

常見錯誤:

  • "error_code":400,"description":"Bad Request: bad webhook: ..." → URL 格式錯誤或 SSL 問題
  • "pending_update_count" 一直增加但收不到 → 你的伺服器沒有正確回應 200

LINE

在 LINE Developers Console 設定:

  1. 進入你的 Channel 設定
  2. 找到「Messaging API」標籤
  3. 在「Webhook URL」填入你的 URL
  4. 點擊「Verify」測試連線
  5. 確保「Use webhook」是開啟的

LINE 的要求:

  • 必須是 HTTPS
  • 必須是 Port 443
  • 回應必須在 1 秒內,否則會被視為失敗

常見錯誤:

  • Verify 失敗 → 檢查 SSL 憑證、防火牆、伺服器有沒有在跑
  • 收到 Webhook 但訊息重複 → 你的伺服器沒有回應 200 OK

Discord

Discord Bot 有兩種模式:

Gateway(WebSocket)模式:不需要 Webhook,你的 Bot 主動連線到 Discord。大多數 Discord Bot 用這種。

Interactions Endpoint(Webhook)模式:用於 Slash Commands 等互動功能。

設定方式:

  1. 進入 Discord Developer Portal
  2. 選擇你的 Application
  3. 在「General Information」填入「Interactions Endpoint URL」
  4. Discord 會發一個驗證請求,你的伺服器必須正確回應

Discord 的要求:

  • 必須是 HTTPS
  • 必須正確處理 Discord 的簽名驗證
  • 必須在 3 秒內回應

Slack

設定 Event Subscriptions:

  1. 進入 Slack App 設定頁面
  2. 開啟「Event Subscriptions」
  3. 填入 Request URL
  4. Slack 會發送一個 challenge 請求,你必須回傳 challenge 值
// 處理 Slack URL 驗證
if (body.type === "url_verification") {
    return res.send(body.challenge);
}

排查清單

Webhook 收不到?按這個順序檢查:

1. 網路層

  • ☐ 伺服器是否有公網 IP?(或用 ngrok/Cloudflare Tunnel)
  • ☐ 防火牆是否開放對應 Port?
  • ☐ 服務是否綁定到 0.0.0.0?
  • ☐ 從外網能不能連到?(用手機網路測試)

2. SSL 層

  • ☐ 有沒有設定 HTTPS?
  • ☐ 憑證是否有效?(用 SSL Labs 檢查)
  • ☐ 憑證是否過期?
  • ☐ 中繼憑證是否完整?

3. 應用層

  • ☐ Webhook URL 是否正確?(注意結尾的 /)
  • ☐ 伺服器有沒有在執行?
  • ☐ 路由是否正確設定?
  • ☐ 是否有回應 HTTP 200?
  • ☐ 回應時間是否在平台要求內?

4. 平台設定

  • ☐ Webhook 是否有啟用?
  • ☐ Token / 密鑰是否正確?
  • ☐ 是否訂閱了正確的事件類型?

快速除錯技巧

用 curl 模擬 Webhook 請求

# 測試你的伺服器能不能收到 POST 請求
curl -X POST https://yourdomain.com/webhook \
  -H "Content-Type: application/json" \
  -d "{\"test\": \"hello\"}"

用 ngrok 的 Web 介面看請求

啟動 ngrok 後,打開 http://127.0.0.1:4040,可以看到所有請求的詳細內容,包括 Headers、Body、Response。

查看伺服器 Log

如果請求有進來但處理有問題,通常 Log 會有錯誤訊息。確保你的程式有適當的錯誤處理和日誌記錄。

用 RequestBin 測試

RequestBin 可以生成一個臨時的 URL 來接收請求。先把 Webhook 設到 RequestBin,確認平台有發出請求,再換成你的伺服器。

總結

Webhook 連通看起來複雜,但其實就是三件事:

  1. 外網能連到你(公網 IP 或 Tunnel)
  2. 有有效的 HTTPS(Let"s Encrypt 或 Cloudflare)
  3. 正確處理請求(回應 200、處理驗證)

按照這篇的檢查清單一項一項排查,99% 的問題都能解決。真的還是不行?那可能是你的程式有 Bug,不是網路的問題。