架好了 Bot 伺服器,設定了 Webhook URL,結果訊息就是收不到?這篇文章整理了所有可能的原因和解決方法,從網路基礎到各平台的設定細節,讓你不用再到處問人。
Webhook 連通的必要條件
在開始排查之前,先確認你理解 Webhook 的運作方式:是對方(Telegram/LINE/Discord)主動發請求到你的伺服器,不是你去拉資料。
這意味著你的伺服器必須滿足以下條件:
- 外網可訪問:對方的伺服器能連到你
- 有效的 HTTPS:幾乎所有平台都要求 SSL 憑證
- 正確的 Port:通常是 443(HTTPS)或平台指定的 Port
- 防火牆放行:你的伺服器/路由器沒有擋掉請求
少一個都不行。下面逐一說明。
第一關:你的伺服器外網能不能連?
情況一:雲端 VPS(AWS、GCP、Azure、Linode、DigitalOcean...)
恭喜,這是最簡單的情況。雲端 VPS 通常直接有公網 IP,你只需要:
- 確認安全群組(Security Group)/ 防火牆有開放 80 和 443 Port
- 確認伺服器本機的防火牆(iptables、ufw、firewalld)也有開
- 把你的服務綁定到
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)
- 登入路由器後台
- 找到「Port Forwarding」或「虛擬伺服器」設定
- 把外部 Port 443 轉發到你電腦的內網 IP 和 Port
- 設定 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。
- 註冊 Cloudflare 並添加你的域名
- 將 DNS 記錄指向你的伺服器 IP
- 確保 Proxy 狀態是橘色雲朵(開啟)
- 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 設定:
- 進入你的 Channel 設定
- 找到「Messaging API」標籤
- 在「Webhook URL」填入你的 URL
- 點擊「Verify」測試連線
- 確保「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 等互動功能。
設定方式:
- 進入 Discord Developer Portal
- 選擇你的 Application
- 在「General Information」填入「Interactions Endpoint URL」
- Discord 會發一個驗證請求,你的伺服器必須正確回應
Discord 的要求:
- 必須是 HTTPS
- 必須正確處理 Discord 的簽名驗證
- 必須在 3 秒內回應
Slack
設定 Event Subscriptions:
- 進入 Slack App 設定頁面
- 開啟「Event Subscriptions」
- 填入 Request URL
- 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 連通看起來複雜,但其實就是三件事:
- 外網能連到你(公網 IP 或 Tunnel)
- 有有效的 HTTPS(Let"s Encrypt 或 Cloudflare)
- 正確處理請求(回應 200、處理驗證)
按照這篇的檢查清單一項一項排查,99% 的問題都能解決。真的還是不行?那可能是你的程式有 Bug,不是網路的問題。