熱評
加載中...
當前位置:首頁技術館建站教學網站建設ntfy:自建一個簡單易用的消息推送服務

ntfy:自建一個簡單易用的消息推送服務

ntfy:自建一個簡單易用的消息推送服務

往往折騰完一套自動化流程後,總需要在特定情景下推送通知,獲取運行結果,以確認是否成功運行,實現運行錯誤能推送錯誤等。

<a href="https://docs.ntfy.sh/">ntfy</a><em> 允許您使用簡單的 HTTP PUT 或 POST 請求,通過任何電腦的腳本將推送通知發送到您的手機或桌面。</em>

簡介

Ntfy 是一個簡單但功能強大的發布-訂閱(pub-sub)通知服務
通過 HTTP PUT/POST 請求發送通知到任何設備
這是一個自託管的替代方案
可以取代 Line Notify 等服務

功能特性

通知方式多元化:

  • 手機推播通知(Android / iOS)
  • 電子郵件通知
  • WebSocket 即時通知
  • Webhook 整合

多種格式支援:

  • 純文字訊息
  • 結構化 JSON 資料
  • 附加檔案傳輸
  • 支援 Markdown 格式

安全性功能:

  • 訪問控制與身份驗證
  • 端到端加密
  • 即時訊息傳遞確認
  • 支援 HTTPS 加密傳輸

整合能力:

  • REST API 支援
  • 命令列工具
  • 支援 Docker 部署
  • 提供各種程式語言的套件(python/Go/PHP/C#/.NET/R/JS/Java/Node)

Ntfy 相較於 Line Notify 的優點

  • 開源且可自行架設
  • 支援多種通知方式
  • 彈性的訂閱方案
  • 具備檔案傳輸功能
  • API 介面完整
  • 不需要辦理帳號即可使用

使用上若是無自己架設的需求
使用官方伺服器路徑https://ntfy.sh/ 即可
想一個不容易被猜到的topic(訊息主題)即可開始享用
其實跟MQTT很像
只是應用的方向不太一樣
有配套的APP使用上是能取代Line Notify

網站網址

電腦端

https://ntfy.sh/app

ntfy:自建一個簡單易用的消息推送服務

手機端

安卓

ntfy:自建一個簡單易用的消息推送服務

蘋果

ntfy:自建一個簡單易用的消息推送服務


ntfy:自建一個簡單易用的消息推送服務

安裝教學

ntfy 有個官方實例 ntfy.sh,但是我推薦你自部署一個 ntfy 私有實例,因為官方實例的通知名稱大都被用了,隨機名稱用起來不夠優雅,而且 ntfy 記憶體佔用不大,隨便一個伺服器都能部署。

根據 ntfy 官方文檔 - Installation,大致有三種安裝方式:靜態二進位檔、包管理器、Docker。

這裡我就用包管理器的方法來安裝,之後更新也方便。

因為我的伺服器是 Debian,所以使用下面命令來安裝:

nginx
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://archive.heckel.io/apt/pubkey.txt | sudo gpg --dearmor -o /etc/apt/keyrings/archive.heckel.io.gpg
sudo apt install apt-transport-https
sudo sh -c "echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/archive.heckel.io.gpg] https://archive.heckel.io/apt debian main' \
    > /etc/apt/sources.list.d/archive.heckel.io.list"
sudo apt update
sudo apt install ntfy
sudo systemctl enable ntfy
sudo systemctl start ntfy

你如果伺服器裝了 Docker,當然可以使用 Docker Compose 安裝,這樣管理起來更方便一點。

配置

因為我們是打算部署一個 ntfy 私有實例,所以還需要對 ntfy 的配置檔進行一定的修改。

根據 ntfy 官方文檔 - Configuration,如果你像我一樣使用 Debian 和包管理器安裝 ntfy 的,那麼就要修改位於 /etc/ntfy/server.yml 的配置檔。

/etc/ntfy/server.yml

nginx
sudo vim /etc/ntfy/server.yml

基礎設置

  • base-url 是 ntfy 伺服器的外部 URL,即反代後的訪問位址 。https://ntfy.example.com
  • listen-http 是 HTTP 監聽位址 。127.0.0.1:2586

⚠️ 注意把 example.com 改成你自己的功能變數名稱。

nginx
base-url: "https://ntfy.example.com"
listen-http: "127.0.0.1:2586"

消息快取

ntfy 預設是在記憶體中緩存 12h 的消息,而且實例重啟就丟失了(記憶體特性)。 這裏設置成在硬碟緩存,ntfy 會將消息存儲在基於 SQLite 的緩存,我們設置 24*7=168 h 的持續時間。

  • cache-file:快取檔案位址 /var/cache/ntfy/cache.db
  • cache-duration:消息在快取中存儲的持續時間 168h
BASIC
cache-file: "/var/cache/ntfy/cache.db"
cache-duration: "168h"

訪問控制

設置成私有實例,需要創建使用者和生成訪問令牌來使用,在下文添加使用者、訪問令牌給出了相應操作。

  • auth-file:user/access 資料庫位址 ,/var/lib/ntfy/user.db 用於存放使用者和訪問令牌。
  • auth-default-accessdeny-all 匿名使用者的訪問授權 ,即未驗證使用者不能讀寫ntfy主題消息。
BASIC
auth-file: "/var/lib/ntfy/user.db"
auth-default-access: "deny-all"

通過電子郵件發送通知

這裡就是設置前言中提到的某些服務的通知設置只支援郵件通知的情況下,也可以通過電子郵件發送消息到 ntfy 主題。

⚠️ 注意把 example.com 改成你自己的功能變數名稱。

BASIC
smtp-server-listen: ":25"
smtp-server-domain: "ntfy.example.com"
smtp-server-addr-prefix: "ntfy-"

值得一提的是,雖然很多雲伺服器商都默認關閉 25 埠的發送,給我們創建域名郵箱設立了門檻,但大多未禁止 25 埠的接收,需要手動放行 25 埠

之後就可以使用 位址來接收郵件。ntfy-<topic>+<access token>@ntfy.example.com

添加 DNS 記錄

除了修改 /etc/ntfy/server.yml 之外,還需要給你的功能變數名稱 添加 DNS 記錄以實現正常訪問 example.com

⚠️ 注意把 example.com 改成你自己的功能變數名稱。

名稱類型備註
ntfy.example.comA公網 IPv4 地址對應 ,是訪問 WebUI 的位址
base-url
ntfy.example.comMXntfy-mx.example.com對應 ,是郵寄地址
smtp-server-domain
ntfy-mx.example.comA公網 IPv4 地址和上面的值對應。

其實沒有必要添加第三條記錄,將 MX 記錄的值 改成 ntfy-mx.example.comntfy.example.com 就可以了。

反向代理

根據 ntfy 官方文檔 - Behind a proxy,但我沒有用文檔給出的參考配置。

nginx
sudo vim /etc/caddy/Caddyfile
nginx
ntfy.k1r.in {
        encode gzip
        tls /home/acme/certs/example.com.fc.crt /home/acme/certs/example.com.pem
        reverse_proxy 127.0.0.1:2586
}
nginx
sudo caddy fmt --overwrite /etc/caddy/Caddyfile
sudo systemctl reload caddy

文檔給出的配置檔主要是為了將 HTTP 重定向到 HTTPS,讓它在使用 不用添加 前綴,我覺得沒有必要。curl https://

另外,使用 Caddy 在這裡有個好處就是不用額外配置就支援 WebSockets,在 ntfy 用戶端更改連結協定為 WebSockets,相比於“HTTP 傳輸的 JSON 數據流”更加省電(開發者說的,我沒怎麼體會到)。

如果成功配置了反向代理,你現在就可以通過 https://ntfy.example.com 訪問到自部署的 ntfy 私有實例了。

添加使用者、訪問令牌

根據 ntfy 官方文檔 - Users and roles,我們可以使用 來添加使用者。ntfy user

需要注意的是,由於 僅擁有者 ntfy 可寫,使用 命令需要 root 許可權。auth-file: "/var/lib/ntfy/user.db"ntfy user

⚠️ 可以將 phil 改成你想要的使用者名。

nginx
sudo ntfy user add --role=admin phil
sudo ntfy user list

根據 ntfy 官方文檔 - Access tokens,我們可以使用 來添加訪問令牌。ntfy token

原因同上,使用 ntfy token 命令需要 root 許可權。

⚠️ 記得將 phil 改成你的使用者名。

nginx
sudo ntfy token add phil
sudo ntfy token list

使用

到此,你已經部署好一個 ntfy 私有實例了。

在官方文檔 - Sending messages 中,已經把發送通知的參數說明清楚了,推薦完整閱讀,我這裡就不贅述了。

接下來就講一下在各種場景中怎麼使用,主要是因為私有實例,需要進行身份驗證。

(1) bash 指令稿(命令行)

BASIC
curl \
  -H "Authorization: Bearer tk_123456" \
  -H "Title: Unauthorized access detected" \
  -d "Remote access to phils-laptop detected. Act right away." \
  https://ntfy.example.com/phil_alerts

身份驗證有兩種方式:

  1. 存取權杖:-H "Authorization: Bearer tk_123456"
  2. 使用者密碼:-u testuser:fakepassword

注意最後一行的網址要加 前綴,因為前面反向代理並沒有設置將 HTTP 重定向到 HTTPS。https://

(2) Webhook 推送

前面提到,很多服務都集成通知設置,其中大多支援 ntfy,而他們大多都是以 JSON 的格式配置通知的。

還有一些服務(如 Jellyfin Webhook 外掛程式),本身並未集成 ntfy 通知,但是支援通用的 Webhook,也是如下設置。

根據官方文檔 - Publish as JSON

  • URL:https://ntfy.example.com
  • Header:
BASIC
{
  "Authorization": "Bearer tk_123456"
}
  • Body:
BASIC
{
  "topic": "phil_alerts",
  "title": "Unauthorized access detected",
  "message": "Remote access to phils-laptop detected. Act right away."
}

需要注意的是,URL 不能帶上主題,即只能是 https://ntfy.example.com ,不能是 。https://ntfy.example.com/phil_alerts

另外,有些服務的 Webhook 只支援接受一行連結,且發送的消息是 JSON 文本,ntfy 也能將其轉換成可讀的消息,參見文末 Waline 示例。

(3) 通過郵件推送

一些服務(如 TrueNAS Core 的系統警報服務),既沒集成 ntfy 通知,也不支援通用 Webhook,但是支援發送郵件。

電子郵件接收位址為 [email protected]

  • ntfy- smtp-server-addr-prefix 是設置的位址前綴。
  • phil_alerts 是你的主題名稱。
  • tk_123456 是你的訪問令牌,前面用 + 連接z。
  • ntfy.example.com 是設置的郵件位址 smtp-server-domain

示例

這裡放一些在我自部署過程中遇到的比較特殊的 ntfy 通知設置。

Jellyfin Webhook

Jellyfin Webhook Ntfy 官方範本

主要涉及 Python jinja 語法,需要修改的話,可以用 .handlebars 後綴保存檔,就會有語法高亮。

acme.sh

根據 acme.sh 專案 Wiki - Set notification for ntfy,使用下面的命令來設置通知。

BASIC
export NTFY_URL="https://ntfy.sh"
export NTFY_TOPIC="xxxxxxxxxxxxx"

acme.sh --set-notify --notify-hook ntfy

只提供了 URL 和 Topic 的傳入,沒有身份驗證的方式。 查閱對應的代碼得知,其實就是對URL和 Topic 兩個變數進行簡單拼接,所以我們可以通過在 Topic 變數里添加查詢參數對來實現身份驗證。

根據 ntfy.sh 官方文檔 - Query param,可以使用 來完成身份驗證,但這裡的值不是用戶密碼/訪問令牌,而是對二者編碼后的結果。auth

在 Linux 系統可以運行下面的命令(二者取其一即可)。

⚠️ 注意將命令中的 user:passwd 或者 tk_123456 改成你的。

BASIC
echo -n "Basic `echo -n 'phil:password' | base64`" | base64 | tr -d '='
# 或者对访问令牌
echo -n "Bearer tk_123456" | base64 | tr -d '='

然後就可以使用如下命令設置 acme.sh 的 ntfy 通知。

BASIC
export NTFY_URL="https://ntfy.example.com"
export NTFY_TOPIC="acmesh?auth=QmFza..."

acme.sh --set-notify --notify-hook ntfy

waline - 使用範本

我博客的評論用的 Waline,它的 Webhook 推送只有一行簡單的連結,如果不加以處理的話,推送的消息就是 JSON 文本,可讀性很差(下面示例我省略了很多東西)。

JavaScript
{
  "type": "new_comment",
  "data": {
    "comment": {
      "link": "https://k1r.in",
      "mail": "[email protected]",
      "nick": "KrDw",
      "url": "/posts/build-your-rss-flow/",
      "comment": "**2025-02-02 17:00:00 更新**...",
      "rawComment": "**2025-02-02 17:00:00 更新**..."
    }
  }
}

參照官方文檔 - Message templating,我們可以使用 GO 範本對 JSON 數據格式化成可讀的推送,需要設置 ?template=yes 參數。

我這裡就直接給出我的範本了,最好使用 urlencoder 進行編碼。

BASIC
Title: {{.data.comment.url}} 有新评论了
Title-Encoded: %7B%7B.data.comment.url%7D%7D%20%E6%9C%89%E6%96%B0%E8%AF%84%E8%AE%BA%E4%BA%86
Message:
读者 {{.data.comment.nick}} 在 {{.data.comment.createdAt}} 评论:\n\n{{.data.comment.rawComment}}
Message-Encoded:
%E8%AF%BB%E8%80%85%20%7B%7B.data.comment.nick%7D%7D%20%E5%9C%A8%20%7B%7B.data.comment.createdAt%7D%7D%20%E8%AF%84%E8%AE%BA%EF%BC%9A%5Cn%5Cn%7B%7B.data.comment.rawComment%7D%7D

配合前面 acme.sh 示例中提到的身份驗證查詢參數 auth ,最終得到如下 Webhook 連結(為了你的閱讀體驗我使用了換行,請在實際使用中不要換行):

BASIC
https://ntfy.example.com/waline
?auth=QmFza...
&markdown=yes
&template=yes
&title=%7B%7B.data.comment.url%7D%7D%20%E6%9C%89%E6%96%B0%E8%AF%84%E8%AE%BA%E4%BA%86
&message=%E8%AF%BB%E8%80%85%20%7B%7B.data.comment.nick%7D%7D%20%E5%9C%A8%20%7B%7B.data.comment.createdAt%7D%7D%20%E8%AF%84%E8%AE%BA%EF%BC%9A%5Cn%5Cn%7B%7B.data.comment.rawComment%7D%7D

進階使用教學

結合Node-Red

ntfy:自建一個簡單易用的消息推送服務
BASIC
[
    {
        "id": "c956e688cc74ad8e",
        "type": "http request",
        "z": "fabdd7a3.4045a",
        "name": "ntfy.sh",
        "method": "POST",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "https://ntfy.sh/mytopic",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "credentials":
        {
            "user": "",
            "password": ""
        },
        "x": 590,
        "y": 3160,
        "wires":
        [
            []
        ]
    },
    {
        "id": "32ee1eade51fae50",
        "type": "function",
        "z": "fabdd7a3.4045a",
        "name": "data",
        "func": "msg.payload = \"Something happened\";\nmsg.headers = {};\nmsg.headers['tags'] = 'house';\nmsg.headers['X-Title'] = 'Home Assistant';\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 470,
        "y": 3160,
        "wires":
        [
            [
                "c956e688cc74ad8e"
            ]
        ]
    },
    {
        "id": "b287e59cd2311815",
        "type": "inject",
        "z": "fabdd7a3.4045a",
        "name": "Manual start",
        "props":
        [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "20",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 330,
        "y": 3160,
        "wires":
        [
            [
                "32ee1eade51fae50"
            ]
        ]
    }
]
BASIC
// 使用 Base64 編碼中文標題
function encodeHeaderAsRFC2047(text) {
    // 轉換成 Base64
    const base64 = Buffer.from(text).toString('base64');
    return `=?UTF-8?B?${base64}?=`;
}

msg.payload = `測站: ${msg.payload.測站}
⏰ 時間: ${msg.payload.時間}
📊 偵測值: ${msg.payload.偵測值}
⚠️ 預警值: ${msg.payload.預警值}
`;

msg.headers = {};
msg.headers['tags'] = 'rotating_light';  // 加入警告和警報 emoji
msg.headers['X-Title'] = encodeHeaderAsRFC2047('監測警報');
msg.headers['Priority'] = 5;  // 設定最高優先級 (5 = max/urgent)

return msg;

Home Assistant

結合到HA也十分方便

BASIC
notify:
  - name: ntfy
    platform: rest
    method: POST_JSON
    data:
      topic: YOUR_NTFY_TOPIC
    title_param_name: title
    message_param_name: message
    resource: https://ntfy.sh

收費方案

主要是可以辦帳號用於保存相關的資料

ntfy:自建一個簡單易用的消息推送服務

是否可以商用?

最後最重要一點
Ntfy 是以 Apache 許可證 2.0 和 GPLv2 許可證下獲得雙重許可發布的開源軟體
Apache License 2.0 主要特點:

  • 完全允許商業使用:
    • 可以免費用於商業目的
    • 可以修改原始碼
    • 可以自由分發
    • 可以私有使用
  • 主要要求:
    • 必須保留原始版權聲明
    • 必須包含 Apache License 的副本
    • 若修改了代碼,需要明確說明
  • 商業應用場景:
    • 企業內部部署
    • 整合到商業產品中
    • 提供託管服務
    • 二次開發後商用
  • 授權相容性:
    • 與大多數開源授權相容
    • 可以與專有軟體結合
    • 可以改變授權條款

網站網址

AngelaL博客

       本文是原創文章,採用CC BY-NC-SA 4.0協議,完整轉載請註明來自AngelaL博客

給TA打賞
共{{data.count}}人
人已打賞
網站建設

Vertex: 專注於PT玩家的追劇刷流一體化綜合管理工具

2025-3-17 23:04:48

網站建設

n8n:無需代碼,自動化你的工作流程

2025-3-18 0:18:26

0 條回复 A文章作者 M管理员
    
    暫無討論,說說你的看法吧
個人中心
購物車
優惠劵
今日簽到
有新私信 私信列表
搜索