- 发布于
ntfy 消息推送服务完全指南:简单高效的跨平台通知解决方案
- 作者

- 姓名
- 全能波
- GitHub
- @weicracker
ntfy 消息推送服务完全指南:简单高效的跨平台通知解决方案
ntfy 是一个简单而强大的开源消息推送服务,它让发送通知变得极其简单。无需注册、无需 API 密钥,只需一个 HTTP 请求就能发送通知到手机、桌面或任何支持的设备。
ntfy 简介
什么是 ntfy
ntfy(发音为 "notify")是一个基于 HTTP 的发布-订阅通知服务。它允许你通过简单的 HTTP 请求发送消息到手机、桌面或其他设备。
核心特性
# 最简单的使用方式
curl -d "Hello World" ntfy.sh/mytopic
# 带标题的消息
curl -H "Title: 重要通知" -d "服务器重启完成" ntfy.sh/alerts
# 带优先级的消息
curl -H "Priority: urgent" -d "紧急:数据库连接失败" ntfy.sh/monitoring
主要优势
- 零配置:无需注册账号或 API 密钥
- 跨平台:支持 Android、iOS、Web、桌面
- 开源免费:完全开源,可自托管
- 简单易用:一行命令即可发送通知
- 功能丰富:支持附件、图片、按钮等
快速开始
安装客户端
# Android
# 从 Google Play Store 或 F-Droid 下载 ntfy 应用
# iOS
# 从 App Store 下载 ntfy 应用
# Linux (Snap)
sudo snap install ntfy
# macOS (Homebrew)
brew install ntfy
# Windows
# 下载 .exe 文件或使用 Scoop
scoop install ntfy
基础使用
# 1. 发送简单消息
curl -d "Hello from server" ntfy.sh/myalerts
# 2. 使用 POST 方法
curl -X POST -d "Backup completed" ntfy.sh/backups
# 3. 使用 PUT 方法
echo "System update available" | curl -T- ntfy.sh/updates
# 4. 使用 GET 方法(URL 编码)
curl "ntfy.sh/alerts?message=Server+is+down"
订阅主题
# 命令行订阅
ntfy subscribe ntfy.sh/myalerts
# 或者使用 curl 持续监听
curl -s ntfy.sh/myalerts/raw
# WebSocket 连接
curl -s -N -H "Accept: text/event-stream" ntfy.sh/myalerts/sse
高级功能
消息格式化
# 设置消息标题
curl -H "Title: 系统监控" \
-d "CPU 使用率超过 80%" \
ntfy.sh/monitoring
# 设置消息优先级
curl -H "Priority: high" \
-H "Title: 警告" \
-d "磁盘空间不足" \
ntfy.sh/alerts
# 添加标签
curl -H "Tags: warning,server" \
-d "服务器负载过高" \
ntfy.sh/monitoring
# 延迟发送
curl -H "Delay: 30min" \
-d "定时提醒:会议开始" \
ntfy.sh/reminders
优先级设置
# 优先级级别:1(min) - 5(max)
curl -H "Priority: 1" -d "低优先级消息" ntfy.sh/topic # 最小
curl -H "Priority: 2" -d "普通消息" ntfy.sh/topic # 低
curl -H "Priority: 3" -d "默认消息" ntfy.sh/topic # 默认
curl -H "Priority: 4" -d "重要消息" ntfy.sh/topic # 高
curl -H "Priority: 5" -d "紧急消息" ntfy.sh/topic # 最大
# 使用名称
curl -H "Priority: urgent" -d "紧急通知" ntfy.sh/alerts
curl -H "Priority: high" -d "高优先级" ntfy.sh/alerts
curl -H "Priority: default" -d "普通消息" ntfy.sh/alerts
curl -H "Priority: low" -d "低优先级" ntfy.sh/alerts
curl -H "Priority: min" -d "最低优先级" ntfy.sh/alerts
添加操作按钮
# 单个按钮
curl -H "Actions: view, 查看详情, https://example.com" \
-d "新订单已创建" \
ntfy.sh/orders
# 多个按钮
curl -H "Actions: view, 查看, https://example.com; http, 重启, https://api.example.com/restart, method=POST" \
-d "服务异常,需要处理" \
ntfy.sh/alerts
# 带确认的按钮
curl -H "Actions: http, 删除数据, https://api.example.com/delete, method=DELETE, confirm=true" \
-d "发现恶意文件" \
ntfy.sh/security
发送附件
# 发送文件
curl -T /path/to/file.pdf \
-H "Filename: report.pdf" \
ntfy.sh/documents
# 发送图片
curl -T /path/to/image.jpg \
-H "Title: 监控截图" \
ntfy.sh/monitoring
# 从 URL 发送附件
curl -H "Attach: https://example.com/file.zip" \
-H "Filename: backup.zip" \
-d "备份文件已准备" \
ntfy.sh/backups
实际应用场景
服务器监控
#!/bin/bash
# server-monitor.sh
TOPIC="server-monitoring"
SERVER_NAME="Web-Server-01"
# 检查 CPU 使用率
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
if (( $(echo "$CPU_USAGE > 80" | bc -l) )); then
curl -H "Title: ⚠️ CPU 警告" \
-H "Priority: high" \
-H "Tags: warning,cpu" \
-d "服务器 $SERVER_NAME CPU 使用率: ${CPU_USAGE}%" \
ntfy.sh/$TOPIC
fi
# 检查磁盘空间
DISK_USAGE=$(df -h / | awk 'NR==2{print $5}' | cut -d'%' -f1)
if [ $DISK_USAGE -gt 90 ]; then
curl -H "Title: 🚨 磁盘空间警告" \
-H "Priority: urgent" \
-H "Tags: critical,disk" \
-d "服务器 $SERVER_NAME 磁盘使用率: ${DISK_USAGE}%" \
ntfy.sh/$TOPIC
fi
# 检查内存使用
MEM_USAGE=$(free | grep Mem | awk '{printf("%.2f", $3/$2 * 100.0)}')
if (( $(echo "$MEM_USAGE > 85" | bc -l) )); then
curl -H "Title: ⚠️ 内存警告" \
-H "Priority: high" \
-H "Tags: warning,memory" \
-d "服务器 $SERVER_NAME 内存使用率: ${MEM_USAGE}%" \
ntfy.sh/$TOPIC
fi
备份通知
#!/bin/bash
# backup-notify.sh
TOPIC="backup-alerts"
BACKUP_DIR="/backup"
DATE=$(date +"%Y-%m-%d %H:%M:%S")
# 执行备份
if mysqldump -u root -p$DB_PASSWORD mydb > $BACKUP_DIR/mydb_$(date +%Y%m%d).sql; then
# 备份成功
BACKUP_SIZE=$(du -h $BACKUP_DIR/mydb_$(date +%Y%m%d).sql | cut -f1)
curl -H "Title: ✅ 备份成功" \
-H "Priority: default" \
-H "Tags: success,backup" \
-d "数据库备份完成
时间: $DATE
大小: $BACKUP_SIZE
位置: $BACKUP_DIR" \
ntfy.sh/$TOPIC
else
# 备份失败
curl -H "Title: ❌ 备份失败" \
-H "Priority: urgent" \
-H "Tags: error,backup" \
-H "Actions: view, 查看日志, https://monitor.example.com/logs" \
-d "数据库备份失败
时间: $DATE
请立即检查系统状态" \
ntfy.sh/$TOPIC
fi
应用程序集成
# Python 示例
import requests
import json
class NtfyNotifier:
def __init__(self, base_url="https://ntfy.sh", topic="myapp"):
self.base_url = base_url
self.topic = topic
def send_notification(self, message, title=None, priority="default", tags=None, actions=None):
url = f"{self.base_url}/{self.topic}"
headers = {"Content-Type": "text/plain; charset=utf-8"}
if title:
headers["Title"] = title
if priority:
headers["Priority"] = priority
if tags:
headers["Tags"] = ",".join(tags) if isinstance(tags, list) else tags
if actions:
headers["Actions"] = actions
response = requests.post(url, data=message.encode('utf-8'), headers=headers)
return response.status_code == 200
def send_error(self, error_message, context=None):
title = "🚨 应用程序错误"
message = f"错误信息: {error_message}"
if context:
message += f"\n上下文: {context}"
return self.send_notification(
message=message,
title=title,
priority="urgent",
tags=["error", "app"],
actions="view, 查看日志, https://logs.example.com"
)
def send_success(self, operation, details=None):
title = "✅ 操作成功"
message = f"操作: {operation}"
if details:
message += f"\n详情: {details}"
return self.send_notification(
message=message,
title=title,
priority="default",
tags=["success", "app"]
)
# 使用示例
notifier = NtfyNotifier(topic="myapp-alerts")
try:
# 执行某些操作
result = perform_critical_operation()
notifier.send_success("数据处理", f"处理了 {result['count']} 条记录")
except Exception as e:
notifier.send_error(str(e), "数据处理模块")
Node.js 集成
// ntfy-client.js
const axios = require('axios');
class NtfyClient {
constructor(baseUrl = 'https://ntfy.sh', topic = 'myapp') {
this.baseUrl = baseUrl;
this.topic = topic;
}
async sendNotification(options) {
const {
message,
title,
priority = 'default',
tags,
actions,
delay,
attach,
filename
} = options;
const url = `${this.baseUrl}/${this.topic}`;
const headers = {
'Content-Type': 'text/plain; charset=utf-8'
};
if (title) headers['Title'] = title;
if (priority) headers['Priority'] = priority;
if (tags) headers['Tags'] = Array.isArray(tags) ? tags.join(',') : tags;
if (actions) headers['Actions'] = actions;
if (delay) headers['Delay'] = delay;
if (attach) headers['Attach'] = attach;
if (filename) headers['Filename'] = filename;
try {
const response = await axios.post(url, message, { headers });
return response.status === 200;
} catch (error) {
console.error('Failed to send notification:', error.message);
return false;
}
}
async sendAlert(level, message, context = {}) {
const priorities = {
info: 'default',
warning: 'high',
error: 'urgent',
critical: 'urgent'
};
const emojis = {
info: 'ℹ️',
warning: '⚠️',
error: '❌',
critical: '🚨'
};
const title = `${emojis[level]} ${level.toUpperCase()}`;
let fullMessage = message;
if (Object.keys(context).length > 0) {
fullMessage += '\n\n详细信息:\n';
for (const [key, value] of Object.entries(context)) {
fullMessage += `${key}: ${value}\n`;
}
}
return this.sendNotification({
message: fullMessage,
title,
priority: priorities[level],
tags: [level, 'app']
});
}
}
// 使用示例
const ntfy = new NtfyClient('https://ntfy.sh', 'webapp-monitoring');
// 发送不同级别的警报
ntfy.sendAlert('info', '应用启动成功', {
version: '1.2.3',
environment: 'production',
timestamp: new Date().toISOString()
});
ntfy.sendAlert('error', '数据库连接失败', {
database: 'mysql-prod',
error: 'Connection timeout',
retries: 3
});
// 发送带操作按钮的通知
ntfy.sendNotification({
message: '新用户注册需要审核',
title: '👤 用户管理',
priority: 'default',
tags: ['user', 'admin'],
actions: 'view, 审核用户, https://admin.example.com/users/pending; http, 自动批准, https://api.example.com/users/approve, method=POST'
});
自托管部署
Docker 部署
# docker-compose.yml
version: '3.8'
services:
ntfy:
image: binwiederhier/ntfy
container_name: ntfy
command:
- serve
environment:
- NTFY_BASE_URL=https://ntfy.yourdomain.com
- NTFY_CACHE_FILE=/var/cache/ntfy/cache.db
- NTFY_AUTH_FILE=/var/lib/ntfy/auth.db
- NTFY_AUTH_DEFAULT_ACCESS=deny-all
- NTFY_BEHIND_PROXY=true
volumes:
- ./data/cache:/var/cache/ntfy
- ./data/lib:/var/lib/ntfy
- ./server.yml:/etc/ntfy/server.yml:ro
ports:
- "8080:80"
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:80/v1/health"]
interval: 60s
timeout: 10s
retries: 3
start_period: 40s
nginx:
image: nginx:alpine
container_name: ntfy-nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
ports:
- "80:80"
- "443:443"
depends_on:
- ntfy
restart: unless-stopped
配置文件
# server.yml
base-url: "https://ntfy.yourdomain.com"
# 监听配置
listen-http: ":80"
listen-https: ""
# 缓存配置
cache-file: "/var/cache/ntfy/cache.db"
cache-duration: "12h"
# 认证配置
auth-file: "/var/lib/ntfy/auth.db"
auth-default-access: "deny-all"
# 速率限制
visitor-request-limit-burst: 60
visitor-request-limit-replenish: "5s"
visitor-email-limit-burst: 16
visitor-email-limit-replenish: "1h"
# 附件配置
attachment-cache-dir: "/var/cache/ntfy/attachments"
attachment-total-size-limit: "5G"
attachment-file-size-limit: "15M"
attachment-expiry-duration: "3h"
# Web 推送
web-push-public-key: "your-vapid-public-key"
web-push-private-key: "your-vapid-private-key"
web-push-file: "/var/lib/ntfy/webpush.db"
web-push-email-address: "admin@yourdomain.com"
# 日志配置
log-level: "INFO"
log-format: "text"
# SMTP 配置(可选)
smtp-sender-addr: "smtp.gmail.com:587"
smtp-sender-user: "your-email@gmail.com"
smtp-sender-pass: "your-app-password"
smtp-sender-from: "ntfy@yourdomain.com"
# 主题配置
global-topic-limit: 15000
visitor-subscription-limit: 30
Nginx 反向代理
# nginx.conf
events {
worker_connections 1024;
}
http {
upstream ntfy {
server ntfy:80;
}
server {
listen 80;
server_name ntfy.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name ntfy.yourdomain.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# 安全头
add_header Strict-Transport-Security "max-age=63072000" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
location / {
proxy_pass http://ntfy;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 支持
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
}
安全和最佳实践
主题命名
# ✅ 好的主题名
ntfy.sh/myapp-prod-alerts
ntfy.sh/server-monitoring-2024
ntfy.sh/backup-notifications
# ❌ 避免的主题名
ntfy.sh/test
ntfy.sh/alerts
ntfy.sh/notifications
访问控制
# 创建用户
ntfy user add --role=admin admin
ntfy user add --role=user alice
# 设置主题权限
ntfy access alice myapp-alerts rw
ntfy access alice monitoring r
# 使用认证发送消息
curl -u alice:password \
-d "Authenticated message" \
https://ntfy.yourdomain.com/myapp-alerts
速率限制
# 避免频繁发送
# 使用批量发送或聚合消息
# 示例:聚合多个事件
#!/bin/bash
EVENTS=()
EVENTS+=("Event 1 occurred")
EVENTS+=("Event 2 occurred")
EVENTS+=("Event 3 occurred")
# 聚合发送
MESSAGE=$(printf '%s\n' "${EVENTS[@]}")
curl -H "Title: 批量事件通知" \
-d "$MESSAGE" \
ntfy.sh/events
总结
ntfy 的核心优势和最佳实践:
🎯 核心优势
- 简单易用:无需注册,一行命令发送通知
- 跨平台支持:Android、iOS、Web、桌面全覆盖
- 功能丰富:支持优先级、附件、按钮等高级功能
- 开源免费:完全开源,可自托管
✅ 适用场景
- 服务器监控和告警
- 应用程序状态通知
- 自动化脚本反馈
- 个人提醒和通知
- 团队协作通知
🚀 最佳实践
- 使用有意义的主题名称
- 合理设置消息优先级
- 避免频繁发送消息
- 自托管提高可靠性
- 配置适当的访问控制
💡 高级技巧
- 结合脚本实现自动化监控
- 使用操作按钮提高交互性
- 集成到 CI/CD 流程
- 配置多个主题分类管理
掌握 ntfy,让你的通知系统变得简单而强大!
ntfy 让消息推送回归简单,是现代开发者不可或缺的工具。