ติดตั้ง Ntfy แจ้งเตือน Push Notification บน VPS
Ntfy (อ่านว่า "notify") คือ self-hosted push notification server ที่ส่งการแจ้งเตือนผ่าน HTTP ไปยังมือถือ (Android/iOS) เดสก์ท็อป และ browser ได้โดยตรง โดยไม่ต้องพึ่ง Firebase, APNs หรือบริการ cloud ภายนอกใดๆ ใช้งานฟรี 100% และเหมาะมากสำหรับการแจ้งเตือนจาก script, cron job, server event หรือ CI/CD pipeline บน VPS
ในบทความนี้จะครอบคลุม: ติดตั้ง Ntfy บน Ubuntu, ตั้งค่า Nginx reverse proxy พร้อม SSL, เพิ่ม authentication, และการส่ง notification จาก command line, script, และ webhook
ข้อกำหนดเบื้องต้น
- VPS Ubuntu 22.04 หรือ 24.04 (RAM 512MB+ เพียงพอ)
- โดเมนพร้อม DNS ชี้มาที่ VPS แล้ว
- Nginx ติดตั้งแล้ว (ดูคู่มือ Nginx Reverse Proxy)
- Let's Encrypt SSL (ดูคู่มือ SSL Let's Encrypt)
- ความเข้าใจพื้นฐาน Linux command line
ทำไมต้องใช้ Ntfy?
เมื่อ VPS ทำงานเสร็จ เช่น backup สำเร็จ, deploy เสร็จ, หรือ disk เต็มใกล้ถึง 90% — คุณต้องการรู้ทันที Ntfy ทำสิ่งนี้ได้ด้วยคำสั่ง curl บรรทัดเดียว:
curl -d "Backup สำเร็จแล้ว!" ntfy.sh/mytopic
แต่ถ้าใช้ ntfy.sh สาธารณะ ข้อมูลทุกอย่างเป็น public — ใครก็อ่านได้ การ self-host บน VPS จึงเป็นทางเลือกที่ดีกว่าสำหรับข้อมูล sensitive
| Feature | ntfy.sh (Public) | Self-hosted |
|---|---|---|
| ฟรี | ✅ | ✅ (เฉพาะค่า VPS) |
| ข้อมูลเป็น Private | ❌ | ✅ |
| ไม่จำกัด topics | ❌ (tier จำกัด) | ✅ |
| ไม่จำกัด subscribers | ❌ | ✅ |
| Authentication | จำกัด | ✅ เต็มรูปแบบ |
| File attachments | จำกัดขนาด | กำหนดเองได้ |
ติดตั้ง Ntfy
ติดตั้งผ่าน official APT repository ของ Ntfy:
# เพิ่ม Ntfy APT repository
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 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 -y
# ตรวจสอบ version
ntfy version
หรือดาวน์โหลด binary โดยตรง (เหมาะกับ ARM VPS):
# ตรวจหา latest version
NTFY_VER=$(curl -s https://api.github.com/repos/binwiederhier/ntfy/releases/latest | grep tag_name | cut -d'"' -f4)
# ดาวน์โหลด (สำหรับ x86_64/amd64)
wget https://github.com/binwiederhier/ntfy/releases/download/${NTFY_VER}/ntfy_${NTFY_VER#v}_linux_amd64.tar.gz
tar xzf ntfy_*.tar.gz
sudo cp -a ntfy_*/ntfy /usr/local/bin/ntfy
ntfy version
ตั้งค่า Ntfy Server
สร้าง config directory และไฟล์ตั้งค่าหลัก:
sudo mkdir -p /etc/ntfy /var/cache/ntfy/attachments
sudo chown ntfy:ntfy /var/cache/ntfy/attachments 2>/dev/null || true
สร้างไฟล์ /etc/ntfy/server.yml:
sudo nano /etc/ntfy/server.yml
# /etc/ntfy/server.yml
base-url: "https://notify.yourdomain.com"
listen-http: ":2586"
# Cache & storage
cache-file: "/var/cache/ntfy/cache.db"
cache-duration: "12h"
# Attachment storage
attachment-cache-dir: "/var/cache/ntfy/attachments"
attachment-total-size-limit: "5G"
attachment-file-size-limit: "15M"
attachment-expiry-duration: "3h"
# Authentication
auth-file: "/var/lib/ntfy/user.db"
auth-default-access: "deny-all"
# Rate limiting
visitor-subscription-limit: 30
visitor-request-limit-burst: 60
visitor-request-limit-replenish: "5s"
# Logging
log-level: "info"
notify.yourdomain.com ด้วยโดเมนจริงของคุณ ค่า auth-default-access: "deny-all" จะบังคับให้ทุก request ต้องใส่ user/passwordตั้งค่า Systemd Service
sudo nano /etc/systemd/system/ntfy.service
[Unit]
Description=ntfy server
After=network.target
[Service]
Type=simple
User=ntfy
Group=ntfy
ExecStart=/usr/bin/ntfy serve --config /etc/ntfy/server.yml
Restart=on-failure
RestartSec=5s
AmbientCapabilities=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
# สร้าง user สำหรับ ntfy (ถ้าติดตั้งผ่าน APT มีให้แล้ว)
sudo useradd --system --no-create-home --shell /usr/sbin/nologin ntfy 2>/dev/null || true
# สร้าง directory สำหรับ auth database
sudo mkdir -p /var/lib/ntfy
sudo chown ntfy:ntfy /var/lib/ntfy
# เปิดใช้และ start service
sudo systemctl daemon-reload
sudo systemctl enable --now ntfy
sudo systemctl status ntfy
ตั้งค่า Nginx Reverse Proxy
sudo nano /etc/nginx/sites-available/ntfy
server {
listen 80;
server_name notify.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name notify.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/notify.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/notify.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://127.0.0.1:2586;
proxy_http_version 1.1;
# WebSocket + SSE support
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;
# Timeout สำหรับ long-polling subscription
proxy_read_timeout 2620s;
proxy_send_timeout 2620s;
# Disable buffering สำหรับ SSE
proxy_buffering off;
proxy_cache off;
proxy_redirect off;
client_max_body_size 20m;
}
}
sudo ln -s /etc/nginx/sites-available/ntfy /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
สร้าง User และ Topic Access Control
Ntfy ใช้ระบบ user/password พร้อม ACL สำหรับควบคุมว่าใครเข้าถึง topic ใดได้บ้าง:
# สร้าง admin user (ได้สิทธิ์ทุก topic)
sudo ntfy user add --role=admin myadmin
# จะให้ใส่ password
# สร้าง user ทั่วไป
sudo ntfy user add myuser
# กำหนดสิทธิ์ให้ user เข้าถึง topic เฉพาะ
sudo ntfy access myuser server-alerts rw # อ่าน+เขียน
sudo ntfy access myuser backups ro # อ่านอย่างเดียว
sudo ntfy access myuser '*' deny # ปิดทุก topic ที่เหลือ
# ดูสิทธิ์ทั้งหมด
sudo ntfy access
role=admin มีสิทธิ์ publish/subscribe ทุก topic อัตโนมัติ ส่วน user ทั่วไปต้องกำหนด ACL ทีละ topicวิธีส่ง Notification
จาก Command Line (curl)
# ส่งข้อความพื้นฐาน
curl -u myuser:mypassword \
-d "Backup เสร็จแล้ว $(date)" \
https://notify.yourdomain.com/server-alerts
# ส่งพร้อม title, priority, และ tags
curl -u myuser:mypassword \
-H "Title: Deploy สำเร็จ" \
-H "Priority: high" \
-H "Tags: white_check_mark,rocket" \
-d "Version 2.1.0 deployed successfully" \
https://notify.yourdomain.com/deployments
# ส่ง JSON format
curl -u myuser:mypassword \
-H "Content-Type: application/json" \
-d '{
"topic": "server-alerts",
"message": "Disk usage เกิน 90%!",
"title": "Server Warning",
"priority": 5,
"tags": ["warning","hard_drive"]
}' \
https://notify.yourdomain.com
จาก Shell Script (ใช้กับ Cron)
#!/bin/bash
# /usr/local/bin/ntfy-notify.sh
NTFY_URL="https://notify.yourdomain.com"
NTFY_USER="myuser"
NTFY_PASS="mypassword"
NTFY_TOPIC="server-alerts"
ntfy_send() {
local message="$1"
local title="${2:-Server Notification}"
local priority="${3:-default}"
curl -s -u "${NTFY_USER}:${NTFY_PASS}" \
-H "Title: ${title}" \
-H "Priority: ${priority}" \
-d "${message}" \
"${NTFY_URL}/${NTFY_TOPIC}" > /dev/null
}
# ตัวอย่างการใช้งาน
ntfy_send "Backup database เสร็จแล้ว" "Backup OK" "default"
# ตรวจ disk แล้วแจ้งเตือน
DISK_USAGE=$(df -h / | awk 'NR==2{print $5}' | tr -d '%')
if [ "$DISK_USAGE" -gt 85 ]; then
ntfy_send "Disk usage: ${DISK_USAGE}% กรุณาตรวจสอบ" "Disk Warning" "high"
fi
Mobile App (Android / iOS)
ติดตั้ง Ntfy app บนมือถือ:
- Android: ดาวน์โหลดจาก F-Droid หรือ Google Play (ค้นหา "ntfy")
- iOS: ดาวน์โหลดจาก App Store (ค้นหา "ntfy")
ใน app ให้กด "Add subscription" → เลือก "Use another server" → ใส่ URL server ของคุณ พร้อม username/password ที่สร้างไว้
Web Browser (PWA)
เปิด https://notify.yourdomain.com ในเบราว์เซอร์ — Ntfy มี web UI ในตัวพร้อม Web Push notification รองรับการใช้เป็น PWA ได้เลย
Integration กับ Cron Jobs และ CI/CD
แจ้งเตือนผลการทำงานของ cron job อัตโนมัติ:
# /etc/cron.d/backup-with-notify
0 2 * * * root /usr/local/bin/backup.sh && \
curl -s -u backup_user:pass \
-H "Title: Backup OK" \
-H "Tags: white_check_mark" \
-d "Daily backup $(date +%Y-%m-%d) เสร็จแล้ว" \
https://notify.yourdomain.com/backups \
|| \
curl -s -u backup_user:pass \
-H "Title: Backup FAILED" \
-H "Priority: urgent" \
-H "Tags: x,rotating_light" \
-d "Backup $(date +%Y-%m-%d) ล้มเหลว! ตรวจสอบด่วน" \
https://notify.yourdomain.com/backups
Priority Levels
| ค่า | ชื่อ | ความหมาย |
|---|---|---|
| 1 | min | ข้อมูลไม่สำคัญ ไม่ส่งเสียง |
| 2 | low | เสียงเบา แจ้งเตือนน้อย |
| 3 | default | ปกติ (ค่าเริ่มต้น) |
| 4 | high | เสียงดัง แบนเนอร์ใหญ่ |
| 5 | urgent/max | สั่นซ้ำ ข้ามโหมดเงียบ |
ตรวจสอบว่า Ntfy ทำงานถูกต้อง
# ตรวจสอบ service status
sudo systemctl status ntfy
# ตรวจสอบ port ที่ listen
ss -tlnp | grep 2586
# ทดสอบ HTTP API โดยตรง
curl -v http://127.0.0.1:2586/v1/health
# ทดสอบผ่าน Nginx
curl -v https://notify.yourdomain.com/v1/health
# ส่ง notification ทดสอบ
curl -u myadmin:adminpassword \
-H "Title: Test Notification" \
-H "Priority: default" \
-d "ทดสอบ Ntfy ทำงานปกติ $(date)" \
https://notify.yourdomain.com/test-topic
# ดู log realtime
sudo journalctl -u ntfy -f
# ตรวจสอบ user list
sudo ntfy user list
/v1/health ควร return {"healthy":true} ถ้า Ntfy ทำงานปกติ ใช้เป็น health check endpoint สำหรับ Uptime Kuma ได้เลยแก้ปัญหาที่พบบ่อย
Error: "403 Forbidden — unauthorized"
เกิดเมื่อส่ง request โดยไม่ใส่ credential หรือ user ไม่มีสิทธิ์ใน topic นั้น
# ตรวจสอบว่า user มีอยู่จริง
sudo ntfy user list
# ตรวจสอบ ACL ของ user
sudo ntfy access myuser
# เพิ่มสิทธิ์ให้ user
sudo ntfy access myuser server-alerts rw
# ทดสอบด้วย admin user ก่อน
curl -u myadmin:adminpass -d "test" https://notify.yourdomain.com/test-topic
Error: "502 Bad Gateway" จาก Nginx
Nginx เชื่อมต่อ Ntfy ไม่ได้ มักเกิดจาก Ntfy service ไม่ทำงาน หรือ port ไม่ตรง
# ตรวจสอบ Ntfy ว่ายัง run อยู่
sudo systemctl status ntfy
sudo systemctl restart ntfy
# ตรวจสอบ port ที่ใช้
sudo grep listen-http /etc/ntfy/server.yml
ss -tlnp | grep ntfy
# ตรวจสอบ Nginx config
sudo nginx -t
sudo tail -20 /var/log/nginx/error.log
Mobile App รับ notification ช้าหรือไม่ได้รับ
ปัญหานี้มักเกิดจาก proxy_read_timeout ใน Nginx สั้นเกินไป ทำให้ SSE connection ขาด
# ตรวจสอบ Nginx timeout config
grep proxy_read_timeout /etc/nginx/sites-available/ntfy
# ค่าควรเป็น 2620s หรือมากกว่า
# แก้ไขและ reload
sudo nano /etc/nginx/sites-available/ntfy
sudo nginx -t && sudo systemctl reload nginx
# ทดสอบ SSE connection
curl -u myuser:pass \
"https://notify.yourdomain.com/server-alerts/json?poll=1"
Error: "disk quota exceeded" สำหรับ attachments
พื้นที่เก็บ attachment เต็ม ต้องล้าง cache หรือเพิ่มขนาด
# ดูขนาด attachment cache
du -sh /var/cache/ntfy/attachments/
# ลบ cache เก่า
sudo find /var/cache/ntfy/attachments -mtime +1 -delete
# หรือเพิ่มขนาด limit ใน server.yml
sudo nano /etc/ntfy/server.yml
# แก้ attachment-total-size-limit: "10G"
sudo systemctl restart ntfy
ไม่สามารถส่ง notification จาก Python ได้
ตรวจสอบ encoding ของ message body โดยเฉพาะภาษาไทย ต้องส่งเป็น UTF-8
import requests
def ntfy_send(message, title="", priority="default"):
requests.post(
"https://notify.yourdomain.com/server-alerts",
data=message.encode(encoding='utf-8'),
headers={
"Title": title.encode(encoding='utf-8'),
"Priority": priority,
"Tags": "bell"
},
auth=("myuser", "mypassword")
)
ntfy_send("Deploy สำเร็จแล้ว", "Deploy OK")
คำถามที่พบบ่อย
Ntfy ต่างจาก Gotify อย่างไร?
ทั้งคู่เป็น self-hosted notification server แต่ Ntfy โดดเด่นกว่าตรงที่รองรับ HTTP PUT/POST ธรรมดา ส่ง notification ได้เลยโดยไม่ต้องใช้ API key พิเศษ รองรับ iOS push notification แบบ native ผ่าน UnifiedPush และมี Web UI ที่ใช้งานง่ายกว่า นอกจากนี้ยังรองรับ self-hosted ได้โดยที่ mobile app ยังใช้งานได้เต็มรูปแบบ
Ntfy ใช้ทรัพยากร VPS มากไหม?
Ntfy เขียนด้วย Go จึงใช้ทรัพยากรน้อยมาก RAM เพียง 20-50MB สำหรับการใช้งานปกติ CPU แทบไม่ใช้เลยขณะ idle VPS ขนาด 512MB RAM ก็รันได้สบาย เหมาะกับการรัน Ntfy ร่วมกับ service อื่นบน VPS เดียวกัน
จะส่ง notification จาก GitHub Actions ได้ไหม?
ได้เลย ใส่ Ntfy URL และ credentials เป็น GitHub Secrets แล้วเรียกใช้ใน workflow:
- name: Notify Deploy Success
run: |
curl -u ${{ secrets.NTFY_USER }}:${{ secrets.NTFY_PASS }} \
-H "Title: Deploy สำเร็จ" \
-H "Tags: rocket,white_check_mark" \
-d "Branch ${{ github.ref_name }} deployed" \
${{ secrets.NTFY_URL }}/deployments