ntfy 实战指南从 cron 定时任务到 CI/CD20 个推送通知自动化场景详解【免费下载链接】ntfySend push notifications to your phone or desktop using PUT/POST项目地址: https://gitcode.com/GitHub_Trending/nt/ntfy导读ntfy 允许通过简单的 HTTP PUT/POST 请求把消息推送到手机或桌面项目描述Send push notifications to your phone or desktop using PUT/POST。官方文档 docs/examples.md 收集了大量由社区贡献的真实使用案例从 cron 备份通知、SSH 登录告警、磁盘空间预警到 Ansible、GitHub Actions、Home Assistant、Uptime Kuma、Node-RED 等生态集成。本文以该文档为骨架结合仓库内 examples/ 目录的现成脚本与 docs/publish.md 的发布参数规范完整复现每个场景的可运行代码并补充源码级细节让你读完即可把 ntfy 接入自己的日常运维与自动化体系。提示文中的示例大多由 ntfy 用户贡献官方文档亦注明无法保证全部可用、许多作者本人也未逐一实测使用前请根据你的环境调整主题名、域名与认证信息。前置基础ntfy 发布消息的两种姿势所有示例的本质都是向一个主题topic发一条消息。ntfy 没有注册流程主题名本身相当于密码——只要别人猜到你的主题名就能读写因此请选择不可猜测的主题名只能包含字母、数字、下划线和短横线最长 64 字符。两种最常用的发布方式方式一curl 直接发布消息体即 POST body主题在 URL 路径中curl -d Backup successful ntfy.sh/mytopic方式二JSON 发布POST 到服务器根 URL主题写在 JSON body 里。这种方式被 Home Assistant、UptimeRobot、Jellyseerr 等大量工具采用因为它们天然以 JSON 发送请求curl ntfy.sh \ -d { topic: mytopic, message: Backup successful, title: Backup, tags: [heavy_check_mark], priority: 3 }发布时可附加Title、Priority、Tags、Click、Attach、Actions、Markdown等头部或 JSON 字段来控制通知的标题、紧急程度、emoji、点击跳转、附件与操作按钮完整字段说明见 docs/publish.md如publish as JSON一节见 docs/publish.md#publish-as-json。Cron 定时任务与长任务完成通知ntfy 非常适合任何 cron 任务或备份、流水线、rsync 等长任务结束时的通知。最常见的做法是把curl调用直接串在执行命令后面利用/||实现成功/失败分流rsync -a rootlaptop /backups/laptop \ zfs snapshot ... \ curl -H prio:low -d Laptop backup succeeded ntfy.sh/backups \ || curl -H tags:warning -H prio:high -d Laptop backup failed ntfy.sh/backups成功时发送低优先级消息失败时发送带warning标签渲染为 ⚠️和高优先级prio:high的告警。另一个历史时刻式的例子每隔 6 分钟探测一次 GitHub 用户名是否可注册一旦可用立即通知# Check github/ntfy user */6 * * * * if curl -s https://api.github.com/users/ntfy | grep Not Found; then curl -d github.com/ntfy is available -H Tags: tada -H Prio: high ntfy.sh/my-alerts; fi如果你想在通知里直接带上 cron 任务的完整输出以便知道失败原因可以使用社区工具ntfy-run0 0 * * * ntfy-run -n https://ntfy.sh/backups --success-priority low --failure-tags warning ~/backup-computer终端长命令完成通知shell function alias文档还给出了一种更通用的做法在.bashrc或.bash_profile中定义函数与别名任何长命令执行完无论成功失败都推送一条通知并带上刚执行的命令文本与退出码。首先若服务器启用了访问控制把 bearer token 安全存放echo your_bearer_token_here ~/.ntfy_token chmod 600 ~/.ntfy_token然后加入以下函数和别名注意exit_status必须在任何其他操作之前捕获# Function for alert notifications using ntfy.sh notify_via_ntfy() { local exit_status$? # Capture the exit status before doing anything else local token$( ~/.ntfy_token) # Securely read the token local status_icon$([ $exit_status -eq 0 ] echo magic_wand || echo warning) local last_command$(history | tail -n1 | sed -e s/^[[:space:]]*[0-9]\{1,\}[[:space:]]*// -e s/[;|][[:space:]]*alert$//) # for zsh users, use the same sed pattern but get the history differently. # local last_command$(history $HISTCMD | sed -e s/^[[:space:]]*[0-9]\{1,\}[[:space:]]*// -e s/[;|][[:space:]]*alert$//) curl -s -X POST https://n.example.dev/alerts \ -H Authorization: Bearer $token \ -H Title: Terminal \ -H X-Priority: 3 \ -H Tags: $status_icon \ -d Command: $last_command (Exit: $exit_status) echo Tags: $status_icon echo $last_command (Exit: $exit_status) } # Add an alert alias for long running commands using ntfy.sh alias alertnotify_via_ntfy使用方式在长命令后追加alert命令结束即收到通知成功显示 magic_wand、失败显示 ⚠️warningsleep 10; alert测试失败通知false; alert # Always fails (exit 1) ls --invalid; alert # Invalid option cat nonexistent_file; alert # File not found低磁盘空间告警一个简单有效的磁盘监控 cron 脚本用df检测根分区剩余空间低于阈值时通过 curl 发出带标题、高优先级和warning,cd标签的通知#!/bin/bash mingigs10 avail$(df | awk $6 / $4 $mingigs * 1024*1024 { print $4/1024/1024 }) topicurlhttps://ntfy.sh/mytopic if [ -n $avail ]; then curl \ -d Only $avail GB available on the root disk. Better clean that up. \ -H Title: Low disk space alert on $(hostname) \ -H Priority: high \ -H Tags: warning,cd \ $topicurl fi其中Priority: high对应 4 级优先级Tags: warning,cd会被渲染为 ⚠️ 和 两个 emojiemoji 短码映射见 docs/emojis.md。SSH 登录告警PAM 集成通过 Linux PAMPluggable Authentication Modules的pam_exec.so可以在每次 SSH 登录时触发通知适合在服务器被入侵时第一时间察觉。在/etc/pam.d/sshd文件末尾追加一行# at the end of the file session optional pam_exec.so /usr/bin/ntfy-ssh-login.sh然后创建脚本/usr/bin/ntfy-ssh-login.sh并赋予执行权限chmod x#!/bin/bash if [ ${PAM_TYPE} open_session ]; then curl \ -H prio:high \ -H tags:warning \ -d SSH login: ${PAM_USER} from ${PAM_RHOST} \ ntfy.sh/alerts fiPAM 会在会话建立时open_session向脚本注入PAM_TYPE、PAM_USER、PAM_RHOST等环境变量脚本据此拼装出谁从哪个 IP 登录的告警。仓库 examples/ssh-login-alert/ntfy-ssh-login.sh 提供了带hostname的完整版本消息为SSH login to host: user from ip同目录下的 examples/ssh-login-alert/pam_sshd 是 PAM 配置参考。从多台机器收集数据流式订阅如果你在多台服务器上运行任务、想把各节点的中间结果汇总成一个 CSV可以让每台服务器向同一主题发布结果再用一台中央机器通过curl -s topic/raw流式订阅实时落盘collect-results.sh中央收集端raw端点返回 JSON Lines 流stdbuf保证逐行读取while read result; do [ -n $result ] echo $result results.csv done (stdbuf -i0 -o0 curl -s ntfy.sh/results/raw)publish-result.sh每台服务器发布结果$count、$time为各自计算的中间结果// This script was run on each of the 20 servers. It was doing heavy processing ... // Publish script results curl -d $(hostname),$count,$time ntfy.sh/results关于流式订阅的底层原理与更多端点/json、/sse、/ws等可参考仓库中的浏览器示例 examples/web-example-eventsource/example-sse.htmlServer-Sent Events与 examples/web-example-websocket/example-ws.htmlWebSocket以及各语言的订阅示例examples/subscribe-go/main.go、examples/subscribe-python/subscribe.py、examples/subscribe-php/subscribe.php。Ansible、Salt 与 Puppet 集成可以把 ntfy 轻松接入 Ansible、Salt 或 Puppet在任务完成或高状态highstate时获得通知。最简单的做法是使用 Ansible 内置的uri模块发 POST- name: Send ntfy.sh update uri: url: https://ntfy.sh/{{ ntfy_channel }} method: POST body: {{ inventory_hostname }} reseeding complete如果希望通知在 Ansible 控制节点上执行可以使用社区插件ansible-ntfy一个 action pluginattrs等属性均为可选- name: Notify ntfy that were done ntfy: msg: deployment on {{ inventory_hostname }} is complete. attrs: tags: [ heavy_check_mark ] priority: 1GitHub Actions 工作流通知在 CI 工作流中可以用 curl 发送包含仓库、提交、引用与任务状态的消息- name: Actions Ntfy run: | curl \ -u ${{ secrets.NTFY_CRED }} \ -H Title: Title here \ -H Content-Type: text/plain \ -d $Repo: ${{ github.repository }}\nCommit: ${{ github.sha }}\nRef: ${{ github.ref }}\nStatus: ${{ job.status}} \ ${{ secrets.NTFY_URL }}其中secrets.NTFY_URL建议直接填主题 URL如https://ntfy.sh/mycisecrets.NTFY_CRED是访问控制开启时的用户/令牌凭据-u user:pass或-u tk_xxx均可详见 docs/config.md#access-control。网页变更监控changedetection.iochangedetection.io 使用 Apprise 库做通知集成因此只需在其通知列表中加入 ntfy 风格的 Apprise URL 即可格式ntfy://{topic}或ntfy://{user}:{password}{host}:{port}/{topics}在 changedetection.io 中对单个网站 watch或分组点击EditNotifications把上面的 ntfy Apprise URL 添加到 Notification List 即可在网站变化时收到推送容器更新通知WatchtowershoutrrrWatchtower 自动更新容器后可通过 shoutrrr 把更新结果发到 ntfy 主题。docker-compose.yml示例services: watchtower: image: containrrr/watchtower environment: - WATCHTOWER_NOTIFICATION_SKIP_TITLETrue - WATCHTOWER_NOTIFICATION_URLntfy://ntfy.sh/my_watchtower_topic?titleWatchtowerUpdatesWATCHTOWER_NOTIFICATION_SKIP_TITLE是必需的如果不设置Watchtower 会用自己的标题覆盖掉 URL 中的title查询参数。如果只想单独用 shoutrrr 发消息shoutrrr send -u ntfy://ntfy.sh/my_watchtower_topic?titleWatchtowerUpdates -m testMessage认证令牌同样受支持两种 URL 格式请替换为自己的域名、主题和令牌推荐ntfy URL 格式ntfy://:TOKENDOMAIN/TOPIC通用 webhook 授权头格式generichttps://DOMAIN/TOPIC?authorizationBearerTOKEN媒体管理套件Sonarr、Radarr、Lidarr、Readarr、Prowlarr、SABnzbdRadarr、Prowlarr 以及 Sonarr v4 在Settings Connect中原生支持 ntfy直接填写即可Sonarr v3、Readarr 和 SABnzbd 需要通过自定义脚本实现下载、告警、抓取等事件的推送。Node-RED 流示例Node-RED 可以用 HTTP request 节点发送消息。下面是官方文档给出的两套可导入的 flow JSON。示例一发送一条消息Inject 手动触发 → function 设置tags与X-Title头 → POST 到https://ntfy.sh/mytopic[ { 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 ] ] } ]示例二发送一张图片Inject → GET 下载外部图片二进制→ function 设置tags与X-Title头 → PUT 到https://ntfy.sh/mytopic以附件形式推送[ { id: d135a13eadeb9d6d, type: http request, z: fabdd7a3.4045a, name: Download image, method: GET, ret: bin, paytoqs: ignore, url: https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png, tls: , persist: false, proxy: , authType: , senderr: false, credentials: { user: , password: }, x: 490, y: 3320, wires: [ [ 6e75bc41d2ec4a03 ] ] }, { id: 6e75bc41d2ec4a03, type: function, z: fabdd7a3.4045a, name: data, func: msg.payload msg.payload;\nmsg.headers {};\nmsg.headers[tags] house;\nmsg.headers[X-Title] Home Assistant - Picture;\n\nreturn msg;, outputs: 1, noerr: 0, initialize: , finalize: , libs: [], x: 650, y: 3320, wires: [ [ eb160615b6ceda98 ] ] }, { id: eb160615b6ceda98, type: http request, z: fabdd7a3.4045a, name: ntfy.sh, method: PUT, ret: bin, paytoqs: ignore, url: https://ntfy.sh/mytopic, tls: , persist: false, proxy: , authType: , senderr: false, credentials: { user: , password: }, x: 770, y: 3320, wires: [ [] ] }, { id: 5b8dbf15c8a7a3a5, 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: 310, y: 3320, wires: [ [ d135a13eadeb9d6d ] ] } ]健康检查与可用性监控GatusGatus 提供了ntfy告警 provider直接在配置中声明即可alerting: ntfy: url: https://ntfy.sh topic: YOUR_NTFY_TOPIC priority: 3备选方案使用自定义告警 provider通过 JSON body 控制更多字段[ENDPOINT_NAME]、[ALERT_DESCRIPTION]、[ALERT_TRIGGERED_OR_RESOLVED]等为 Gatus 内置占位符alerting: custom: url: https://ntfy.sh method: POST body: | { topic: mytopic, message: [ENDPOINT_NAME] - [ALERT_DESCRIPTION], title: Gatus, tags: [[ALERT_TRIGGERED_OR_RESOLVED]], priority: 3 } default-alert: enabled: true description: health check failed send-on-resolved: true failure-threshold: 3 success-threshold: 3 placeholders: ALERT_TRIGGERED_OR_RESOLVED: TRIGGERED: warning RESOLVED: white_check_markUptime Kuma 集成在 Uptime Kuma 的Settings Notifications中点击Setup Notification设置标题如 Uptime Kuma、ntfy 主题、服务器 URL 与优先级1-5即可配置完成后可以先测试通知再把该通知应用到具体监控项上这样站点宕机down与恢复up都会推送到手机UptimeRobot 集成在 UptimeRobot 的My Settings Alert Contacts Add Alert Contact中选择Alert Contact Type Webhook设置 Friendly Name如 ntfy-sh-UP、URL to Notify、POST value并勾选Send as JSON (application/json)。注意JSON 必须 POST 到 ntfy 服务器根 URL不带主题名主题名放在 JSON body 的topic字段中——这正是 docs/publish.md#publish-as-json 描述的 JSON 发布方式。{ topic:myTopic, title: *monitorFriendlyName* *alertTypeFriendlyName*, message: *alertDetails*, tags: [green_circle], priority: 3, click: https://uptimerobot.com/dashboard#*monitorID* }可以创建两个 Alert Contact分别使用不同图标与优先级例如用green_circle表示恢复、red_circle表示故障{ topic:myTopic, title: *monitorFriendlyName* *alertTypeFriendlyName*, message: *alertDetails*, tags: [red_circle], priority: 3, click: https://uptimerobot.com/dashboard#*monitorID* }DDoS 检测告警FlowtriqFlowtriq 的 Linux 代理 ftagent 支持 webhook 告警可直接 POST 到 ntfy 主题检测到攻击时手机立刻收到推送。在/etc/ftagent/ftagent.yml中配置 webhook URL# /etc/ftagent/ftagent.yml alerts: webhooks: - url: https://ntfy.sh/flowtriq-attacks method: POST也可以用 curl 手动模拟一条攻击告警来测试集成curl \ -H Title: DDoS Attack Detected \ -H Priority: urgent \ -H Tags: rotating_light \ -d Attack detected on 203.0.113.5: 14.2 Gbps UDP flood from 3,482 sources \ ntfy.sh/flowtriq-attacksApprise 直接发送ntfy 已被 Apprise 原生集成。最简单用法apprise -vv -t Test Message Title -b Test Message Body \ ntfy://mytopic自建服务器同样支持把域名换成你自己的apprise -vv -t Test Message Title -b Test Message Body \ ntfy://ntfy.example.com/mytopicRundeck 集成邮件模板法Rundeck 默认只发送 HTML 邮件而 ntfy 的 SMTP 服务器不处理 HTML 邮件因此需要自定义邮件模板为纯 HTML 并在其中嵌入执行信息。向rundeck-config.properties追加# Template rundeck.mail.template.file/path/to/template.html rundeck.mail.template.log.formattedfalsetemplate.html示例divExecution ${execution.id} was b${execution.status}/b/div ul lia href${execution.href}Execution result/a/li lia href${job.href}Job/a/li lia href${execution.projectHref}Project: ${execution.project}/a/li lia href${rundeck.href}Rundeck/a/li /ul在 Rundeck 中添加通知时附件类型必须选择Attached as file to email最终通知会通过 SMTP 进入 ntfy 并推送Traccar 集成自建实例通过 SMS provider该方案仅适用于自托管Traccar 实例因为sms.http.*配置项无法通过 UI 修改。思路是把 ntfy 配置为 Traccar 的 SMS 提供方再把 ntfy 主题当作账号的手机号注意手机号要加在 traccar 账号上而不是设备上否则不会触发 SMS 发送。另外由于 ntfy 不支持 HTML 邮件通过邮件通知 ntfy 的方式不可行。entry keysms.http.urlhttps://ntfy.sh/entry entry keysms.http.template { topic: {phone}, message: {message} } /entryCautionJSON 发布只能 POST 到 ntfy 实例的根 URL见 docs/publish.md#publish-as-json本例中sms.http.url正是根 URL{phone}会被替换为账号手机号即主题名。如果启用了访问控制且目标主题不允许匿名写入还需要提供授权头例如特权 tokenentry keysms.http.authorizationBearer tk_JhbsnoMrgy2FcfHeofv97Pi5uXaZZ/entry或者直接给 Traccar 配置合法的用户名/密码entry keysms.http.userphil/entry entry keysms.http.passwordmypass/entry家庭自动化Home AssistantREST notify在configuration.yml中配置 REST notify 组件。由于 Home Assistant 以 JSON 方式 POST必须把resource指向 ntfy 的根 URL主题写在data.topic中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 资源做认证加上authentication、username、passwordnotify: - name: ntfy platform: rest method: POST_JSON authentication: basic username: YOUR_USERNAME password: YOUR_PASSWORD data: topic: YOUR_NTFY_TOPIC title_param_name: title message_param_name: message resource: https://ntfy.sh如需添加 priority、tags 等 ntfy 专有参数直接加到data中即可notify: - name: ntfy platform: rest method: POST_JSON data: topic: YOUR_NTFY_TOPIC priority: 4 title_param_name: title message_param_name: message resource: https://ntfy.sh影视请求管理Jellyseerr / Overseerr webhook给 jellyseerr/overseerr 配置自定义 webhookJSON payload 如下。记得把https://request.example.com替换为你的站点 URL即 JSON 中click键的值如果你不使用requests这个主题也要把 payload 里的topic改掉{ topic: requests, title: {{event}}, message: {{subject}}\n{{message}}\n\nRequested by: {{requestedBy_username}}\n\nStatus: {{media_status}}\nRequest Id: {{request_id}}, priority: 4, attach: {{image}}, click: https://requests.example.com/{{media_type}}/{{media_tmdbid}} }这里用到了 JSON 发布的多项字段priority控制紧急程度、attach附加请求海报图片、click让通知点击后直达对应媒体页面。仓库内置的现成示例代码除了文档中的场景examples/ 目录还提供了可直接运行的各语言示例可作为你接入自己项目的起点发布端examples/publish-go/main.goGo含无头消息一行代码与带 Title/Priority/Tags 的完整示例、examples/publish-python/publish.py、examples/publish-php/publish.php订阅端examples/subscribe-go/main.go、examples/subscribe-python/subscribe.py、examples/subscribe-php/subscribe.phpWeb 实时订阅examples/web-example-eventsource/example-sse.html、examples/web-example-websocket/example-ws.htmlLinux 桌面通知examples/linux-desktop-notifications/notify-desktop.sh用notify-send把订阅到的消息显示为桌面通知Grafana 告警examples/grafana-dashboard/ntfy-grafana.jsonGrafana 仪表盘/告警配置配合 server/templates/grafana.yml 通知模板使用以 Go 发布为例examples/publish-go/main.go 展示了两种用法——不带附加头只需一行http.Post带标题/优先级/标签则需要构造 Request 并设置 Header// Without additional headers (priority, tags, title), its a one liner. http.Post(https://ntfy.sh/mytopic, text/plain, strings.NewReader(Backup successful )) // If youd like to add title, priority, or tags, its a little harder. req, err : http.NewRequest(POST, https://ntfy.sh/phil_alerts, strings.NewReader(Remote access to phils-laptop detected. Act right away.)) if err ! nil { log.Fatal(err) } req.Header.Set(Title, Unauthorized access detected) req.Header.Set(Priority, urgent) req.Header.Set(Tags, warning,skull) if _, err : http.DefaultClient.Do(req); err ! nil { log.Fatal(err) }常用发布参数速查上文大量示例反复用到以下参数均见 docs/publish.md可通过 HTTP 头或 JSON 字段传递参数HTTP 头别名JSON 字段说明标题X-TitleTitle/ti/ttitle覆盖默认主题 URL 标题优先级X-PriorityPriority/prio/ppriority1-5或min/low/default/high/urgent默认 3标签/emojiX-TagsTags/tag/tatags逗号分隔匹配 emoji 短码时渲染为 emoji如warning→⚠️MarkdownX-MarkdownMarkdown/mdmarkdown设为true/1/yes启用或用Content-Type: text/markdown点击跳转X-ClickClickclickhttp(s)://、mailto:、geo:、ntfy://等 URI附件URLX-AttachAttach/aattach外部 URL 附件自动从 URL 推导文件名附件本地文件X-FilenameFilename/File/f—用 PUT 发送本地文件配合-T使用操作按钮X-ActionsActions/Actionactions最多 3 个支持view/broadcast/http/copy四种动作图标X-IconIconicon通知图标 URL仅支持 JPEG/PNG目前仅 Android几点从源码/文档可以确认的边界详见 docs/publish.md 的Limitations与附件章节普通消息超过 4,096 字节或包含非 UTF-8 内容时服务器会自动按附件处理需要X-Filename指定文件名公共实例 ntfy.sh 的附件上限为 15 MB/文件、100 MB/访客总量附件 3 小时后过期外部 URL 附件X-Attach不受这些限制主题名仅允许[-_A-Za-z0-9]最长 64 字符HTTP 头支持 UTF-8但部分语言库不支持遇到标题乱码可改用 RFC 2047 编码base64 或 quoted-printable。小结从本文可以看出ntfy 的接入成本极低——绝大多数集成就是发一条 HTTP 请求cron 里的curl -d、Ansible 的uri模块、GitHub Actions 的run: curl、Home Assistant 的 REST notify、监控平台的 webhook/JSON POST 等等。把上述任一场景接入后你还能用Title、Priority、Tags、Click、Actions等参数把通知打磨成该响则响、不该响不打扰的形态低优先级消息静默落入通知栏、高优先级紧急告警弹窗加长振动、带操作按钮的通知甚至能直接在手机上触发 HTTP 请求完成处置。更多参数细节与限制请继续查阅 docs/publish.md、docs/config.md访问控制、速率限制等服务器配置以及 docs/examples.md 原文与 examples/ 目录中持续更新的社区示例。【免费下载链接】ntfySend push notifications to your phone or desktop using PUT/POST项目地址: https://gitcode.com/GitHub_Trending/nt/ntfy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考