ntfy 完整教學 2026:35K 星自架推播通知,監控與腳本一次接

ntfy 是一套用 HTTP PUT/POST 就能推播到手機與桌面的開源通知伺服器(GitHub 3.5 萬星、Apache-2.0)。本文用 Docker 實測 v2.35.0:映像檔 35MB、閒置記憶體 14.8MiB,完整設定 auth/ACL/token、iOS 與 Web Push 的坑、反向代理,並附上接 Uptime Kuma、changedetection.io、Grafana、Frigate、備份腳本的實戰寫法與六套工具比較表。

  • Dennis
  • 12 分鐘閱讀
ntfy 完整教學 2026:35K 星自架推播通知,監控與腳本一次接

ntfy 是一套開源推播通知伺服器,只要對 https://你的網域/主題名 發一個 HTTP POST,訊息就會出現在手機或桌面。它用 Apache-2.0/GPLv2 雙授權、GitHub 3.5 萬星,Docker 映像檔 35MB、閒置只吃約 15MB 記憶體,是自架監控與腳本通知最省事的選擇。

為什麼要為「通知」這件事自架一個服務

多數人第一條通知是 Telegram bot:免費、五分鐘搞定、手機一定收得到。問題會在第三個月出現:

痛點實際會遇到的情況
平台風險通知服務本身被關掉、API 改版、bot token 政策變動。國內常見的 LINE Notify 就是例子——它在 2025 年 3 月底終止服務(以官方公告為準),當時一堆排程腳本一夜失效
內容外流你的告警訊息會經過第三方伺服器,裡面常有主機名、內網 IP、資料庫連線字串片段
額度與限速服務掛掉時告警會「爆量」,免費 bot 很容易撞到每分鐘上限,最需要通知的時候剛好被擋
機構網路某些企業或校園網路直接封鎖 Telegram,工程師在家測得通、進公司就收不到
格式受限想帶圖片(例如監視器抓到的畫面)、想放「重開服務」按鈕,多數 bot API 做得不直覺

ntfy 走的是完全不同的路線:它只是一個 HTTP 端點。不需要 SDK、不需要註冊應用程式、不需要管 token 政策,curl 就是完整功能的客戶端。這件事在維運場景特別重要——你半夜三點在修機器時,不會想先讀 API 文件。

一表看懂:ntfy 到底提供什麼

項目內容備註
專案binwiederhier/ntfy2021 年建立,至今持續活躍
星數35,187GitHub API 查詢,2026-10-30
授權Apache-2.0 與 GPLv2 雙授權自架商用沒問題
最新版v2.35.0(2026-10-30 發布)本文實測版本
映像檔大小35.0 MBdocker image inspect 實測
閒置記憶體14.79 MiBdocker stats 實測
訊息長度上限4,096 bytes超過自動轉為附件
附件上限單檔 15MB、每位訪客 100MB、總計 5GB自架預設值;ntfy.sh 免費為單檔 2MB
附件保存3 小時attachment-expiry-duration
訊息快取12 小時支援 since= 補抓與斷線重連
費率限制每位訪客 60 次請求的桶子,每 5 秒補 1 次可調
平台Android、iOS、Web、CLI、任何能發 HTTP 的東西Android 有 F-Droid 版(不用 Firebase)
資料庫預設 SQLite;可換 PostgreSQL換 PostgreSQL 會順帶啟用認證

(以上數字除特別標註「實測」者外,以官方文件與 GitHub API 於 2026-10-30 的顯示為準。)

運作流程:為什麼它「不用裝任何東西」也能推播

角色做什麼對應動作
發布端對 POST /<topic> 送出訊息,可帶標題、優先級、標籤、附件、按鈕curl、Python、Shell、CI、監控系統 webhook
伺服器驗證權限 → 寫入快取 → 推給目前連線的訂閱者你的 ntfy 容器
訂閱端長輪詢或 SSE 收訊息;App 收到後交給系統通知手機 App、Web UI、CLI
系統推播Android 走 FCM、iOS 走 APNs、瀏覽器走 Web Push這是「手機關螢幕也收得到」的關鍵

有一個關鍵設計要知道:主題(topic)本身就是頻道,訂閱與發布都用同一個名字,不存在「先建立頻道」這一步。所以在 ntfy.sh 上免註冊使用時,主題名就等於密碼——取什麼 test、alert 這種名字,全世界都猜得到也訂得到。

5 分鐘先試用:不架站也能玩

先用官方公用伺服器確認你要的通知長什麼樣子。手機裝好 App(Google Play/F-Droid/App Store)→ 訂閱一個只有你知道的名字:

curl -d "伺服器重開完成" ntfy.sh/most-tw-demo-8f3k2

加上標題、優先級與 emoji 標籤只要多幾個 header:

curl \
  -H "Title: 備份完成" \
  -H "Priority: high" \
  -H "Tags: white_check_mark,floppy_disk" \
  -d "restic snapshot ok,耗時 4 分 12 秒" \
  ntfy.sh/most-tw-demo-8f3k2

優先級共五級(1/2/3/4/5,或 min/low/default/high/urgent)。它決定手機要不要響、要不要震、要不要彈出橫幅——這件事比多數人想像的重要:全部設 urgent 的結果就是全部被無視。

想帶圖片(例如監視器畫面)就把檔案 PUT 上去:

curl -T snapshot.jpg \
  -H "Filename: snapshot.jpg" \
  -H "Message: 前門偵測到人" \
  ntfy.sh/most-tw-demo-8f3k2

公用伺服器的免費額度(依官方文件):每天 250 則訊息、附件單檔 2MB、每位訪客每日 200MB 流量。拿來測試夠用,拿來當正式告警不夠——所以下面開始自架。

自架:一份 compose 就跑起來

官方映像檔是 binwiederhier/ntfy,啟動參數固定 serve。這份是實際測試過的設定(裸機 Docker,無反向代理,先把認證與快取打開):

services:
  ntfy:
    image: binwiederhier/ntfy:v2.35.0
    restart: unless-stopped
    command: serve
    environment:
      NTFY_BASE_URL: http://localhost:2586
      NTFY_LISTEN_HTTP: ":80"
      NTFY_CACHE_FILE: /var/lib/ntfy/cache.db
      NTFY_AUTH_FILE: /var/lib/ntfy/user.db
      NTFY_AUTH_DEFAULT_ACCESS: deny-all
      NTFY_BEHIND_PROXY: "true"
      NTFY_ATTACHMENT_CACHE_DIR: /var/lib/ntfy/attachments
      NTFY_ENABLE_LOGIN: "true"
    volumes:
      - ./data:/var/lib/ntfy
    ports:
      - "2586:80"
    healthcheck:
      test: ["CMD-SHELL", "wget -q --spider http://127.0.0.1:80/v1/health || exit 1"]
      interval: 10s
      timeout: 3s
      retries: 5

啟動後驗證:

docker compose config --quiet      # 先驗語法,錯字在這裡就會被抓到
docker compose up -d
curl -s http://127.0.0.1:2586/v1/health
# {"healthy":true,"role":"active"}

實測結果:容器約 11 秒進入 healthy,映像檔 35.0MB,閒置記憶體 14.79 MiB,Web UI(http://主機:2586/)回應 200。資料落地只有三個東西——cache.db(訊息快取)、user.db(帳號與 ACL)、attachments/(附件),全部在 ./data 底下,備份就是備份這個資料夾。

⚠️ NTFY_AUTH_DEFAULT_ACCESS: deny-all 是這份設定最重要的一行。沒設的話預設是 read-write,任何人都能對任何主題發布——那等於把一個公開的推播 API 掛在網路上。

私有化:帳號、ACL、Token 三件事

ntfy 的權限模型很簡單:兩種角色(user/admin)× 每個主題的權限(read-write/read-only/write-only/deny),外加一個代表匿名存取的 *。

# 建管理員(用環境變數給密碼,避免互動式輸入)
docker exec -e NTFY_PASSWORD='你的密碼' ntfy ntfy user add --role=admin admin

# 建一個只能寫 backups 主題的機器人帳號
docker exec -e NTFY_PASSWORD='另一個密碼' ntfy ntfy user add backup-script
docker exec ntfy ntfy access backup-script backups rw

# 發一把長期 token(給 Grafana、Uptime Kuma 這類不能存密碼的整合用)
docker exec ntfy ntfy token add --label "grafana" admin

實測行為(本機 Docker,deny-all 設定):

動作結果
匿名 POST 到任意主題403(正確被擋)
backup-script POST 到自己沒權限的主題403
backup-script POST 到 backups200
用 Authorization: Bearer tk_… 發布200
用 admin 帳密輪詢 /backups/json?poll=1&since=all回傳含 title、priority、tags 的 JSON

輪詢回來的 JSON 長這樣(實際輸出,主題與時間已換成示例):

{"id":"AbU0WGO71AVD","time":1793390702,"expires":1793433902,"event":"message",
 "topic":"backups","title":"備份完成","message":"restic snapshot ok: 12.4GB",
 "priority":4,"tags":["white_check_mark","backup"]}

expires 是 time 加 12 小時,正好對上預設的 cache-duration。這代表「手機離線一段時間後回來,還能把漏掉的訊息補收」——這是 ntfy 相對純推播服務的實質差異。

附件也順手驗了:PUT 一個 16 bytes 的文字檔,回傳的 JSON 會多一個 attachment 物件,內含 name、type、size,以及一個 /file/<id>.txt 的網址,到期時間是 3 小時後(1793401503 - 1793390703 = 10800 秒)。

反向代理與 HTTPS:這步不能省

推播本身走 HTTP 沒問題,但附件、Web UI 登入、Web Push 全部需要有效的 HTTPS(瀏覽器的 service worker 不接受自簽憑證)。三條路都已經有現成教學:

用反向代理時,NTFY_BASE_URL 一定要填對外網址(https://ntfy.你的網域),並把 NTFY_BEHIND_PROXY 設 true,否則費率限制會把所有請求都算在同一個來源 IP 上——自己人先被自己擋掉。

Caddy 的設定大概長這樣:

ntfy.你的網域 {
    reverse_proxy 127.0.0.1:2586
}

手機端:Android 很順,iOS 有一個坑

平台取得方式要注意的事
AndroidGoogle Play/F-Droid/GitHub Releases APKF-Droid 版不含 Firebase,所有訂閱預設就是即時;Play 版若想即時,要開「instant delivery」(會有一個常駐通知,背景連線耗電約 0–1%/17 小時)
iOSApp Store自架伺服器要即時收到,必須設 upstream-base-url: https://ntfy.sh
桌面/瀏覽器Web UI + Web Push自架要先生成 VAPID 金鑰並設定 web-push-*

iOS 那個坑值得展開,因為它是很多人「自架後覺得 iOS 很慢」的真正原因。ntfy 的 iOS App 是靠 Apple 推播(APNs)叫醒的,而 APNs 只有 Apple 認得的推播服務能送。官方解法是讓你的自架伺服器在收到訊息時,只把「訊息 ID」丟給 ntfy.sh,再由 App 回頭跟你自己的伺服器拉內容——訊息本文不經過 upstream。設定只有一行:

NTFY_UPSTREAM_BASE_URL: https://ntfy.sh

不設定的話,官方文件的說法是「通知最終還是會到,但可能要幾小時,取決於手機狀態;如果你正在用手機,通常不超過 20–30 分鐘」。對告警來說,20 分鐘跟沒收到差不多。

Web Push(瀏覽器關掉也收得到)要另外備金鑰:

docker exec ntfy ntfy webpush keys   # 產生 VAPID keypair

把產出的公鑰/私鑰、web-push-file、web-push-email-address 填進設定即可。這組金鑰只服務「同一個 origin」,不能拿 A 站的金鑰去訂 B 站。

實戰:五個可以直接抄的接法

1. 接 Uptime Kuma(服務掛掉)

Uptime Kuma 內建 ntfy 通知類型,只要填伺服器網址、主題、優先級,需要認證時填帳密或 token。設定細節在站上的 Uptime Kuma 完整教學。

2. 接 changedetection.io(降價、補貨、公告)

changedetection.io 的 ntfy:// 通知格式是官方整合清單第一項,適合拿來盯商品頁與政府公告,寫法見 changedetection.io 完整教學。

3. 接 Grafana 告警

Grafana 的 contact point 選 webhook,指向 https://ntfy.你的網域/grafana-alerts,並在 ntfy 端開一個只給 Grafana 用的 token。這樣 Prometheus 的門檻值告警、Loki 的錯誤率告警都會落到同一支手機。整套堆疊見 Grafana+Prometheus+Loki 完整教學。

4. 接 Frigate(監視器有人就推一張圖)

Frigate 偵測到人/車時可以同時發通知與附上截圖,ntfy 的附件功能在這裡很實用(記得自架的 15MB 上限比 ntfy.sh 的 2MB 寬鬆很多)。設定見 Frigate NVR 完整教學。

5. 接備份腳本(最少人做、最有價值的一件事)

備份最常見的失敗不是備份失敗,是沒人知道它失敗了。borgmatic 與 restic 都有現成的 ntfy 掛法,最土法煉鋼的版本是這樣:

#!/usr/bin/env bash
set -o pipefail
TOPIC="https://ntfy.你的網域/backups"
TOKEN="tk_xxxxxxxxxxxx"

if restic backup /data --tag nightly 2>&1 | tail -3 > /tmp/restic.log; then
  curl -s -H "Authorization: Bearer $TOKEN" \
       -H "Title: 備份成功" -H "Tags: white_check_mark" -H "Priority: low" \
       --data-binary @/tmp/restic.log "$TOPIC"
else
  curl -s -H "Authorization: Bearer $TOKEN" \
       -H "Title: 備份失敗" -H "Tags: rotating_light" -H "Priority: 5" \
       --data-binary @/tmp/restic.log "$TOPIC"
fi

搭配 restic/Kopia/Duplicati 備份完整教學 的 3-2-1 策略,這支腳本就是「備份有沒有真的跑」的唯一證據。

順帶一提:ntfy 的發布端不限 curl。Python 一行 requests.post()、CI 的 curl step、Cron 的 &&/||、Home Assistant 的官方整合、甚至巴法雲這類中國平台的 webhook 都能接。

六套方案比較:什麼時候不該用 ntfy

方案型態自架手機端授權適合誰明顯缺點
ntfy推播伺服器✅Android/iOS/Web/CLIApache-2.0+GPLv2想要一個 HTTP 端點打通所有腳本與監控iOS 自架要借道 upstream;公用伺服器主題名即密碼
Gotify推播伺服器✅只有 Android 官方 App授權檔非標準 SPDX(GitHub 判定 NOASSERTION)純 Android 團隊、想更單純沒有官方 iOS App,這是最大分水嶺
Bark推播服務(可自架)✅iOS 為主MIT全 Apple 生態、想要極簡Android 支援弱、功能比 ntfy 少
Apprise通知函式庫—(不是伺服器)看你接的後端BSD-2-Clause已經有一堆通知管道,想統一呼叫介面它自己不推播;是「翻譯層」,仍需後端
Pushover商業 SaaS❌Android/iOS/Desktop閉源想一次買斷、不想維運每個平台 US$4.99 一次性、免費每月 10,000 則;資料經過第三方
Telegram Bot商業 SaaS❌全平台閉源個人小專案、臨時用企業/校園網路常被封;內容與主機資訊都經過第三方

一句話選型:Android 為主、想要最單純 → Gotify;全 Apple 生態 → Bark;要跨平台又要自架 → ntfy;不想維運 → Pushover;已經有一堆管道要統一 → Apprise。

已知限制與還沒解決的坑

寫在前面:以下是官方文件明列的,加上實測或查證時發現的,不是「聽說」:

  • iOS 自架的即時性有條件:沒有 upstream-base-url 時,延遲可能是幾十分鐘到數小時。這是架構限制,不是 bug。
  • Android 的即時送達要付代價:Play 版開 instant delivery 會有一個常駐通知(可關),F-Droid 版則無法關閉(因為它本來就不走 FCM)。
  • 主題名在公用伺服器上等於密碼:想保留主題名(避免被別人搶走)要買 ntfy Pro;自架則沒有這個問題,但沒有「主題已被佔用」的概念。
  • 附件與訊息都有存活期:訊息 12 小時、附件 3 小時。想拿 ntfy 當「訊息資料庫」會失望,它的定位是通知。
  • 費率限制的預設值不算寬:60 次請求的桶子、每 5 秒補 1 次、每位訪客 30 條訂閱連線。監控系統在大量服務同時掛掉時容易撞到,建議自架時把 visitor-request-limit-burst 調高。
  • PostgreSQL 是「換掉整個儲存層」:設了 database-url 後,cache-file/auth-file/web-push-file 都必須拿掉,而且會隱含啟用認證。搬家時很容易漏。
  • 實驗性叢集不要上生產:新版 server.yml 有 experimental-cluster-* 系列選項(需共用 PostgreSQL),官方自己寫明「dropped node-to-node batches are not recovered yet,且費率限制是各節點獨立計算」。
  • 本文沒有實測的部分:iOS/Android App 的實際推送延遲、FCM/APNs 的送達率、Web Push 在 Safari 的行為、以及 ntfy Pro 的實際額度。這些需要實機與真實帳號,本文只引用官方文件說明。

誰適合、誰不需要

適合:已經在自架監控(Uptime Kuma、Grafana、Frigate、changedetection.io)的人;有一堆 cron/CI 腳本想統一發通知的人;在意告警內容不該經過第三方的人;公司網路擋 Telegram 的人。

不需要:只有一個小專案、一個月幾十則通知 → Telegram bot 更省事;完全不想維運 → Pushover 一次買斷比養容器便宜;需要「通知+值班排程+升級通報」的企業流程 → 那是 PagerDuty/Grafana OnCall 這類工具的責任,ntfy 只是最後一哩。

站內延伸閱讀

原始來源

本文的 Docker 設定、權限行為與效能數字為 2026-10-30 在本機以 v2.35.0 實際執行所得;星數、授權與版本以查證當日官方頁面為準。文中無聯盟連結。

📬 訂閱 most.tw 電子報

每週精選 AI 工具教學與技術乾貨,直接送到你的信箱。免費、隨時可退訂。

訂閱即表示同意收到 most.tw 電子報,隨時可一鍵退訂。

💬 有問題想討論?加 LINE 聯絡我

歡迎透過 LINE 官方帳號直接留言,我會盡快回覆你的問題。

加入 LINE 好友