Ntfy Push Notification Server บน VPS

ติดตั้ง Ntfy แจ้งเตือน Push Notification บน VPS

เผยแพร่: 26 กันยายน 2026 · อ่าน 12 นาที · Ubuntu 22.04 / 24.04

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

ข้อกำหนดเบื้องต้น

ทำไมต้องใช้ Ntfy?

เมื่อ VPS ทำงานเสร็จ เช่น backup สำเร็จ, deploy เสร็จ, หรือ disk เต็มใกล้ถึง 90% — คุณต้องการรู้ทันที Ntfy ทำสิ่งนี้ได้ด้วยคำสั่ง curl บรรทัดเดียว:

curl -d "Backup สำเร็จแล้ว!" ntfy.sh/mytopic

แต่ถ้าใช้ ntfy.sh สาธารณะ ข้อมูลทุกอย่างเป็น public — ใครก็อ่านได้ การ self-host บน VPS จึงเป็นทางเลือกที่ดีกว่าสำหรับข้อมูล sensitive

Featurentfy.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"
Tip: แทน 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
Tip: 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 บนมือถือ:

ใน 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

ค่าชื่อความหมาย
1minข้อมูลไม่สำคัญ ไม่ส่งเสียง
2lowเสียงเบา แจ้งเตือนน้อย
3defaultปกติ (ค่าเริ่มต้น)
4highเสียงดัง แบนเนอร์ใหญ่
5urgent/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
Tip: endpoint /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