SSD Nodes Learn 🎉 VPS $5.50/माह से
गाइड Matt Connorलेखक: Matt Connor

Docker Compose के साथ अपना ntfy सर्वर कैसे सेटअप करें

Docker Compose का उपयोग करके अपने VPS पर ntfy सर्वर को TLS के साथ सेटअप करें। ACLs और यूजर ऑथेंटिकेशन के जरिए सुरक्षित नोटिफिकेशन पाएं और cron jobs से अलर्ट भेजना सीखें।

Self-hosted ntfy सर्वर क्या करता है

एक self-hosted ntfy सर्वर HTTP POST को आपके फोन पर push notification में बदल देता है। आप curl के साथ publish करते हैं, और संदेश Android ऐप, iOS ऐप, ब्राउज़र टैब, या किसी भी ऐसी चीज़ पर पहुँच जाता है जो HTTP कनेक्शन को खुला रख सकती है। इसमें इंस्टॉल करने के लिए कोई client library नहीं है और न ही कोई message broker चलाने की आवश्यकता है।

ntfy संदेशों को topic के माध्यम से संबोधित करता है। Topic URL पाथ में एक नाम होता है, जैसे https://ntfy.example.com/alerts, और यह उस क्षण अस्तित्व में आ जाता है जब कोई उस पर publish करता है। डिफ़ॉल्ट इंस्टॉलेशन पर, जो कोई भी उस नाम को जानता है वह topic को पढ़ सकता है और उस पर लिख सकता है, यही कारण है कि प्रोजेक्ट का अपना documentation topic के नाम की तुलना पासवर्ड से करता है। यह मॉडल सार्वजनिक ntfy.sh सेवा के लिए ठीक है। यह उस सर्वर के लिए ठीक नहीं है जो आपके बैकअप विफलताओं की जानकारी ले जा रहा हो, इसलिए यह गाइड पहला संदेश भेजे जाने से पहले ही authentication को चालू कर देती है।

शुरू करने से पहले आपकी आवश्यकताएं

आपको Ubuntu 24.04 या Debian 13 पर चलने वाला एक VPS चाहिए, जिसमें Docker Engine और Compose plugin इंस्टॉल हो। इसके साथ ही एक domain name और बहुत कम RAM की आवश्यकता होगी। एक DNS (domain name system) A record बनाएँ जो ntfy.example.com को सर्वर के public IP address पर point करे, और किसी भी अन्य कार्य से पहले यह सुनिश्चित करें कि यह resolve हो रहा है।

dig +short ntfy.example.com
sudo ufw allow 80,443/tcp
sudo ufw status

dig को आपके सर्वर का IP print करना चाहिए। यदि यह कुछ भी print नहीं करता है, तो certificate जारी करने की प्रक्रिया विफल हो जाएगी, क्योंकि certificate authority बाहर से नाम की जाँच करती है। Port 80 को open रखें क्योंकि ACME (automatic certificate management environment), जो Let's Encrypt के पीछे का protocol है, इसका उपयोग HTTP challenge के लिए करता है। ntfy container के लिए कभी भी कोई public port open नहीं किया जाता है।

ntfy कॉन्फ़िगरेशन फ़ाइल लिखें

Docker image में कोई कॉन्फ़िगरेशन फ़ाइल नहीं होती है, इसलिए आपको एक बनानी होगी। इस गाइड में बाद में आने वाले सभी कमांड इसी फ़ाइल से डेटा पढ़ेंगे। सबसे पहले वह user ID और group ID पता करें जिसके तहत container चलेगा।

id -u
id -g
sudo install -d -o "$(id -u)" -g "$(id -g)" /etc/ntfy /var/cache/ntfy /var/lib/ntfy
sudo nano /etc/ntfy/server.yml
base-url: "https://ntfy.example.com"
listen-http: ":2586"
behind-proxy: true
cache-file: "/var/cache/ntfy/cache.db"
cache-duration: "12h"
auth-file: "/var/lib/ntfy/user.db"
auth-default-access: "deny-all"
enable-login: true
enable-signup: false

इनमें से चार पंक्तियाँ सबसे महत्वपूर्ण हैं। base-url का मान सटीक public HTTPS पता होना चाहिए, क्योंकि ntfy इसी का उपयोग करके attachment links बनाता है और web app के स्वयं के requests तैयार करता है। यदि यह मान गलत हुआ, तो web app लोड तो हो जाएगा लेकिन कोई भी action पूरा नहीं कर पाएगा। listen-http: ":2586" container के अंदर सभी interfaces से bind होता है। यह देखने में असुरक्षित लग सकता है, लेकिन यह सही है: container का अपना network namespace होता है, इसलिए वहाँ 127.0.0.1 पर bind करने से port host से unreachable हो जाएगा और Docker का published port कभी connect नहीं हो पाएगा। auth-default-access: "deny-all" आपकी पूरी सुरक्षा व्यवस्था है, क्योंकि यह स्पष्ट अनुमति के बिना किसी को भी read या write करने से रोकता है। behind-proxy: true ntfy को यह निर्देश देता है कि वह client का पता X-Forwarded-For header से ले, ताकि rate limits reverse proxy को एक व्यस्त client मानने के बजाय वास्तविक visitors की गणना करें।

enable-login: true web app और phone apps को password के साथ sign in करने की अनुमति देता है। enable-signup को false ही रहने दें, क्योंकि private server पर self-service account creation एक खुला निमंत्रण देने जैसा है।

sudo chown "$(id -u):$(id -g)" /etc/ntfy/server.yml
sudo chmod 600 /etc/ntfy/server.yml

Docker Compose के साथ ntfy चलाएं

इसे /opt/ntfy/compose.yaml में रखें और 1000:1000 को ऊपर दिए गए दो नंबरों id -u और id -g से बदलें।

services:
  ntfy:
    image: binwiederhier/ntfy:v2.27.0
    container_name: ntfy
    command: serve
    user: "1000:1000"
    environment:
      - TZ=UTC
    volumes:
      - /etc/ntfy:/etc/ntfy
      - /var/cache/ntfy:/var/cache/ntfy
      - /var/lib/ntfy:/var/lib/ntfy
    ports:
      - "127.0.0.1:2586:2586"
    restart: unless-stopped
cd /opt/ntfy
sudo docker compose up -d
sudo docker compose logs ntfy
curl -s http://127.0.0.1:2586/v1/health

एक स्वस्थ सर्वर {"healthy":true} का उत्तर देता है। उस compose फ़ाइल में दो विवरण जानबूझकर दिए गए हैं। image को v2.27.0 पर पिन किया गया है, जो अगस्त 2026 तक का वर्तमान release है, न कि latest पर, क्योंकि latest के साथ अगला docker compose pull आपके सर्वर का वर्शन बदल देता है और आपको बाद में changelog से पता चलता है। port को 127.0.0.1:2586:2586 के रूप में publish किया गया है, इसलिए container केवल host के loopback address से ही पहुँच योग्य है। इसके बजाय 2586:2586 लिखें और Docker आपके firewall नियमों से पहले अपने नियम डाल देता है, जिसका अर्थ है कि port इंटरनेट से उत्तर देता है, भले ही ufw status यह कहे कि port बंद है।

यदि curl Connection refused प्रिंट करता है, तो container log पढ़ें। /var/lib/ntfy/user.db पर permission error का अर्थ है कि user: लाइन उन directories के owner से मेल नहीं खाती है, इसलिए process अपना database नहीं बना पाती और बंद हो जाती है। VPS के लिए Docker Compose बेसिक्स गाइड volume ownership और restart policies के बारे में अधिक विस्तार से जानकारी देती है।

Caddy के साथ TLS का उपयोग करें

Caddy स्वयं certificate का अनुरोध और नवीनीकरण (renewal) करता है, जो TLS (transport layer security) को कार्यशील बनाने का सबसे छोटा रास्ता है।

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddy

/etc/caddy/Caddyfile की सामग्री को तीन लाइनों से बदलें।

ntfy.example.com {
    reverse_proxy 127.0.0.1:2586
}
sudo systemctl reload caddy
curl -s https://ntfy.example.com/v1/health

HTTPS पर वही {"healthy":true} का अर्थ है कि पूरा पाथ सही ढंग से काम कर रहा है। Caddy से मिलने वाला 502 यह दर्शाता है कि ntfy listening मोड में नहीं है: sudo ss -lntp | grep 2586 के साथ इसकी जाँच करें। certificate error का सामान्य अर्थ है कि DNS record गलत है या port 80 ब्लॉक है, और sudo journalctl -u caddy -n 50 यह बताता है कि इनमें से कौन सी समस्या है।

यदि आप पहले से ही nginx चला रहे हैं, तो ntfy द्वारा बताए गए proxy settings को कॉपी करें: proxy_http_version 1.1, proxy_buffering off, proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for, और read तथा send timeouts को कम से कम तीन मिनट पर सेट करें। एक subscriber जब तक listening मोड में होता है, तब तक एक HTTP connection खुला रखता है, और nginx डिफ़ॉल्ट रूप से 60 सेकंड के बाद idle upstream connection को बंद कर देता है। इस कारण subscriber बार-बार reconnect होते हैं और इस अंतराल के दौरान भेजे गए संदेश छूट जाते हैं।

उपयोगकर्ता बनाएँ और टॉपिक्स को लॉक करें

Authentication चालू है और अभी किसी के पास किसी भी चीज़ का एक्सेस नहीं है, जो कि इसका उद्देश्य है। अपने लिए एक admin अकाउंट और स्क्रिप्ट्स के लिए एक machine अकाउंट बनाएँ। ये कमांड्स कंटेनर के अंदर से /etc/ntfy/server.yml को पढ़ती हैं, इसीलिए कॉन्फ़िगरेशन फ़ाइल एक वॉल्यूम माउंट है।

sudo docker compose exec ntfy ntfy user add --role=admin admin
sudo docker compose exec ntfy ntfy user add robot
sudo docker compose exec ntfy ntfy user list

प्रत्येक कमांड पासवर्ड के लिए प्रॉम्प्ट करती है। एक admin एक्सेस लिस्ट को अनदेखा करता है और हर टॉपिक को पढ़ और लिख सकता है, इसलिए उस अकाउंट को अपने और फोन ऐप के लिए सुरक्षित रखें। robot एक सामान्य उपयोगकर्ता है जिसके पास तब तक कोई एक्सेस नहीं होता जब तक आप उसे प्रदान न करें।

sudo docker compose exec ntfy ntfy access robot alerts write
sudo docker compose exec ntfy ntfy access robot "alerts_*" write
sudo docker compose exec ntfy ntfy access

एक ACL (एक्सेस कंट्रोल लिस्ट) एंट्री में एक उपयोगकर्ता, एक टॉपिक और एक अनुमति (permission) होती है। टॉपिक या तो एक literal नाम होता है या एक पैटर्न, जहाँ * किसी भी चीज़ से मेल खाता है, इसलिए alerts_* में alerts_backup और alerts_db दोनों शामिल हो जाते हैं, जिससे प्रति होस्ट अलग कमांड चलाने की आवश्यकता नहीं पड़ती। अनुमति write का अर्थ है केवल पब्लिश करना, ताकि cron जॉब से चुराया गया टोकन सब्सक्राइब न कर सके और जो भेजा गया है उसे वापस पढ़ न सके। विशेष उपयोगकर्ता नाम everyone यह निर्धारित करता है कि एक अनधिकृत विज़िटर क्या कर सकता है, और आप इसका उपयोग केवल किसी ऐसी चीज़ को सार्वजनिक करने के लिए करेंगे जो जानबूझकर सार्वजनिक हो, जैसे कि ntfy access everyone status read

स्क्रिप्ट्स के पास आपका पासवर्ड नहीं, बल्कि एक टोकन होना चाहिए।

sudo docker compose exec ntfy ntfy token add robot

यह कमांड tk_ से शुरू होने वाला एक टोकन प्रिंट करती है। एक टोकन को ठीक उसी उपयोगकर्ता का एक्सेस मिलता है जिससे वह संबंधित है, इसलिए यह टोकन केवल alerts टॉपिक्स पर पब्लिश कर सकता है और कुछ नहीं। ntfy token list यह दिखाता है कि क्या मौजूद है, और ntfy token remove उपयोगकर्ता के पासवर्ड को छुए बिना किसी टोकन को रद्द (revoke) कर देता है।

अपना पहला संदेश भेजें और सुनिश्चित करें कि लॉक काम कर रहा है

सबसे पहले यह जाँचें कि दरवाजा बंद है या नहीं।

curl -s -o /dev/null -w '%{http_code}\n' -d "hello" https://ntfy.example.com/alerts

यह 403 प्रिंट करता है, और 403 सही उत्तर है: auth-default-access: "deny-all" anonymous publish को अस्वीकार कर देता है। अब एक वास्तविक संदेश भेजें।

curl -H "Authorization: Bearer tk_REPLACE_WITH_YOUR_TOKEN" \
  -H "Title: Nightly backup finished" \
  -H "Priority: default" \
  -H "Tags: white_check_mark" \
  -d "42 GB copied in 11 minutes" \
  https://ntfy.example.com/alerts

सर्वर JSON के रूप में संग्रहीत संदेश के साथ उत्तर देता है, जिससे आपको पता चलता है कि संदेश स्वीकार कर लिया गया है। Title पहली बोल्ड लाइन है। Priority 1 से 5 तक चलता है, या min से urgent तक नाम के अनुसार, और यह तय करता है कि फोन ध्वनि करेगा या नहीं। जब नाम किसी ज्ञात emoji short code से मेल खाता है, तो Tags नोटिफिकेशन पर emoji बन जाते हैं, और मेल न खाने पर वे plain text के रूप में ही रहते हैं।

टर्मिनल से किसी topic को monitor करने के लिए, उसे stream करें:

curl -s -u admin https://ntfy.example.com/alerts/raw

curl पासवर्ड के लिए संकेत देता है। प्रत्येक संदेश एक लाइन के रूप में आता है, और बीच-बीच में दिखाई देने वाली खाली लाइनें keepalives हैं। ब्राउज़र में https://ntfy.example.com खोलकर और उसी account से sign in करने पर आपको उसी stream का web app संस्करण मिल जाता है।

रेट लिमिट सेट करें ताकि कोई एक स्क्रिप्ट सर्वर को फ्लड न कर सके

डिफ़ॉल्ट रूप से प्रत्येक विज़िटर को 60 रिक्वेस्ट की बकेट मिलती है, जो हर 5 सेकंड में एक रिक्वेस्ट की दर से रिफिल होती है। एक प्राइवेट सर्वर के लिए यह काफी उदार है, और यदि कोई स्क्रिप्ट रिट्राई लूप में फंस जाती है, तो वह इसे पूरी तरह खत्म कर देगी। server.yml में लिमिट्स जोड़ें।

visitor-request-limit-burst: 30
visitor-request-limit-replenish: "10s"
visitor-message-daily-limit: 500
sudo docker compose restart ntfy

लिमिट से अधिक रिक्वेस्ट भेजने वाले विज़िटर को डिलीवर किए गए मैसेज के बजाय HTTP 429 मिलता है। लिमिट की गणना प्रति विज़िटर एड्रेस के आधार पर की जाती है, यही कारण है कि behind-proxy: true इतना महत्वपूर्ण है: इसके बिना ntfy केवल Caddy का एड्रेस देखता है, हर क्लाइंट एक ही विज़िटर के रूप में गिना जाता है, और एक शोर मचाने वाली स्क्रिप्ट उस बकेट को खत्म कर देती है जिसे आपका फोन और आपके अन्य सर्वर साझा करते हैं।

Cron job विफल होने पर अलर्ट

टोकन को कमांड लाइन से बाहर रखें। ps aux बॉक्स पर मौजूद हर यूजर को हर चल रही प्रोसेस की पूरी कमांड लाइन दिखाता है, इसलिए -H के साथ पास किया गया टोकन तब तक किसी भी लोकल अकाउंट द्वारा पढ़ा जा सकता है जब तक curl चलता है। एक curl कॉन्फ़िगरेशन फ़ाइल इससे बचाती है।

sudo install -d -m 700 /etc/ntfy-alert
printf 'header = "Authorization: Bearer tk_REPLACE_WITH_YOUR_TOKEN"\n' | sudo tee /etc/ntfy-alert/curlrc
sudo chmod 600 /etc/ntfy-alert/curlrc

अब जॉब को रैप करें। इसे /usr/local/bin/backup-with-alert.sh के रूप में सेव करें और इसे chmod 750 करें।

#!/bin/bash
out=$(/usr/local/bin/backup.sh 2>&1)
code=$?
if [ "$code" -ne 0 ]; then
  printf '%s' "$out" | tail -c 1000 | curl -K /etc/ntfy-alert/curlrc \
    -H "Title: backup.sh failed with exit $code" \
    -H "Priority: high" \
    -H "Tags: warning" \
    --data-binary @- \
    https://ntfy.example.com/alerts
fi
exit "$code"
17 3 * * * /usr/local/bin/backup-with-alert.sh >> /var/log/backup-alert.log 2>&1

$? को कमांड के ठीक बाद वाली लाइन पर कैप्चर किया जाता है, क्योंकि अगली कमांड इसे ओवरराइट कर देगी। आउटपुट tail -c 1000 के माध्यम से जाता है क्योंकि ntfy अधिकतम मैसेज साइज लागू करता है और नोटिफिकेशन कोई लॉग व्यूअर नहीं है। अंतिम exit "$code" मूल स्टेटस को सुरक्षित रखता है, ताकि इस जॉब को मॉनिटर करने वाली कोई भी अन्य चीज़ अभी भी विफलता देख सके। एक रन के लिए स्क्रिप्ट को /bin/false पर पॉइंट करके पूरे सेटअप का परीक्षण करें।

एक विफलता शाखा (failure branch) जो कभी निष्पादित नहीं होती, वह अलर्ट न होने से भी बदतर है, क्योंकि ऐसा लगता है कि चुप्पी का मतलब सफलता है। Cron आपके जॉब को लगभग खाली एनवायरनमेंट और आपके लॉगिन शेल की तुलना में बहुत छोटा PATH देता है, इसलिए जो स्क्रिप्ट आपके हाथ से चलाने पर काम करती है, वह curl लाइन तक पहुँचने से पहले ही विफल हो सकती है। Cron जॉब क्यों नहीं चलती, इस पर गाइड उन एनवायरनमेंट संबंधी समस्याओं को कवर करती है। हर जगह एब्सोल्यूट पाथ का उपयोग करें, और यह मानने के बजाय कि सब ठीक है, पहले शेड्यूल किए गए रन के बाद लॉग फ़ाइल को पढ़ें।

systemd unit विफल होने पर अलर्ट प्राप्त करना

Cron निर्धारित कार्यों के लिए उपयुक्त है। लंबे समय तक चलने वाली सेवाओं के लिए OnFailure= की आवश्यकता होती है, जिसे systemd तब चलाता है जब कोई unit failed स्थिति में आ जाती है। एक template unit बनाएँ और उसे सर्वर की प्रत्येक सेवा के लिए पुनः उपयोग करें। इसे /etc/systemd/system/ntfy-unit-failed@.service के रूप में सहेजें।

[Unit]
Description=Send an ntfy alert because %i failed

[Service]
Type=oneshot
ExecStart=/usr/local/bin/ntfy-unit-failed %i

फिर /usr/local/bin/ntfy-unit-failed चलाएँ, mode 750 के साथ:

#!/bin/bash
unit="$1"
journalctl -u "$unit" -n 15 --no-pager -o cat | tail -c 1000 | curl -K /etc/ntfy-alert/curlrc \
  -H "Title: $unit failed on $(hostname -s)" \
  -H "Priority: urgent" \
  -H "Tags: rotating_light" \
  --data-binary @- \
  https://ntfy.example.com/alerts

इसे एक drop-in के माध्यम से किसी सेवा के साथ जोड़ें, ताकि package upgrade आपके संपादन को ओवरराइट न कर सके।

sudo systemctl edit myapp.service
[Unit]
OnFailure=ntfy-unit-failed@%n.service

%n का विस्तार पूर्ण unit नाम में हो जाता है, इसलिए instance ntfy-unit-failed@myapp.service बन जाता है, और template के अंदर %i, myapp.service को script के पहले तर्क (argument) के रूप में भेजता है। यही वह विशेषता है जो एक template को प्रत्येक unit के लिए कार्य करने में सक्षम बनाती है। इसे एक ऐसी unit के साथ सिद्ध करें जो जानबूझकर विफल हो जाती है, जिसे /etc/systemd/system/ntfy-selftest.service के रूप में सहेजें।

[Unit]
Description=Deliberately failing unit
OnFailure=ntfy-unit-failed@%n.service

[Service]
Type=oneshot
ExecStart=/bin/false
sudo systemctl daemon-reload
sudo systemctl start ntfy-selftest.service

start command non-zero exit code देता है और Job for ntfy-selftest.service failed because the control process exited with error code प्रिंट करता है, और लगभग एक सेकंड बाद फोन पर सूचना आ जानी चाहिए। परीक्षण के बाद test unit को हटा दें।

एक सावधानी आवश्यक है। OnFailure= केवल तब चलता है जब कोई unit failed स्थिति तक पहुँचती है, और Restart=always वाली सेवा शायद ही कभी उस स्थिति तक पहुँचे, क्योंकि systemd उसे बार-बार restart करता रहता है। unit केवल तभी विफल मानी जाती है जब वह StartLimitIntervalSec के भीतर StartLimitBurst से अधिक बार restart हो जाए। जिन सेवाओं के बारे में आप सूचित होना चाहते हैं, उन पर ये दो मान सेट करें, अन्यथा crash loop दिनों तक चुपचाप चलती रहेगी। Timers ऊपर दिए गए cron पैटर्न का एक बेहतर विकल्प हैं, क्योंकि timer की service unit को OnFailure= स्वतः प्राप्त हो जाता है, और VPS पर systemd services और timers के लिए गाइड इसे बदलने की प्रक्रिया को विस्तार से समझाती है।

Uptime monitor को उसी topic से जोड़ें

Uptime Kuma, self-hosted status monitor, में ntfy notification type पहले से मौजूद है। Settings खोलें, फिर Notifications पर जाएँ, उसके बाद Setup Notification चुनें, Ntfy को select करें, server URL को https://ntfy.example.com पर सेट करें और topic को alerts पर रखें, एक priority चुनें, और robot access token को paste करें। Save करने से पहले test notification भेजें, क्योंकि गलत topic name होने पर write grant उसे चुपचाप fail कर देता है।

इस व्यवस्था की एक वास्तविक सीमा यह है: यदि monitor उसी VPS पर चल रहा है, तो वह आपको यह नहीं बता पाएगा कि VPS down है, और ntfy यह सूचना नहीं दे पाएगा कि ntfy down है। monitor को किसी दूसरी machine पर चलाएँ, और जो monitor ntfy की निगरानी करता है, उसके लिए email जैसा एक दूसरा notification channel रखें। Uptime Kuma का Push monitor type एक और blind spot को कवर करता है: आपका cron job सफल run के बाद एक push URL को call करता है, और जब ये calls आनी बंद हो जाती हैं तो Kuma alert भेजता है। failure branch केवल तब सक्रिय होती है जब job run होता है, इसलिए यह उस job के बारे में कुछ नहीं बताता जो कभी शुरू ही नहीं हुआ।

क्या self-hosted ntfy Android और iPhone पर काम करता है?

Android पर, हाँ, बिना किसी शर्त के। Google Play या F-Droid से app इंस्टॉल करें, Settings खोलें, default server को https://ntfy.example.com पर सेट करें, user management screen के अंतर्गत अपना account जोड़ें, और फिर alerts को subscribe करें। Instant delivery के लिए एक foreground service चलती रहती है ताकि phone के doze mode में होने पर भी messages प्राप्त हो सकें। इसके साथ आने वाली permanent notification Android की foreground services की आवश्यकता है, न कि कोई bug। F-Droid build में कोई भी Firebase code नहीं होता है, इसलिए हर subscription instant delivery का उपयोग करती है। ntfy एक UnifiedPush distributor के रूप में भी काम कर सकता है, जो Google की push service का एक open विकल्प है, ताकि UnifiedPush का समर्थन करने वाली अन्य apps भी आपके server के माध्यम से delivery कर सकें।

iOS पर, यह एक ऐसी dependency के साथ काम करता है जिसे आप हटा नहीं सकते। Apple background में चल रही app को केवल APNs (Apple push notification service) के माध्यम से ही जगाता है, और केवल वही पक्ष जिसके पास app की signing credentials हैं, उसे संदेश भेज सकता है, इसलिए आपके server के पास app तक सीधे पहुँचने का कोई तरीका नहीं है। ntfy इसे एक relay के साथ हल करता है: आपका server message ID वाला एक poll_request ntfy.sh को भेजता है, जो इसे Firebase और APNs के माध्यम से आगे भेजकर app को जगाता है, और फिर app आपके server से message body fetch करती है।

upstream-base-url: "https://ntfy.sh"

इसकी लागत के बारे में स्पष्ट रहें। message का content आपके server पर ही रहता है, लेकिन यह तथ्य कि एक message आया है, और उसकी ID, उस infrastructure से होकर गुजरती है जिसे आप नहीं चलाते हैं। इस setting के बिना, self-hosted server से iPhone पर notifications देर से आती हैं या बिल्कुल नहीं आती हैं, क्योंकि app को जगाने वाला कोई नहीं होता। relay को हटाने का एकमात्र तरीका यह है कि आप अपना Apple developer account और अपनी APNs keys का उपयोग करके iOS app को स्वयं build और ship करें, जिसका अर्थ है एक वार्षिक शुल्क और हर update के लिए एक नया build। यदि relay आपके उपयोग के लिए स्वीकार्य नहीं है, तो alerting को Android या desktop web app पर ही रखें।

Backups, upgrades और image को pin करना

दो paths को regenerate नहीं किया जा सकता: /etc/ntfy/server.yml और /var/lib/ntfy/user.db। दूसरे path में सभी users, password hashes, ACL entries और tokens होते हैं, इसलिए इसे private key की तरह सुरक्षित रखें।

sudo tar czf ntfy-backup.tgz -C / etc/ntfy var/lib/ntfy
sudo chmod 600 ntfy-backup.tgz

उस file की copy server से बाहर कहीं और सुरक्षित रखें। cache.db में केवल हाल के messages होते हैं, जो ऊपर दिए गए cache-duration के अनुसार 12 घंटे पुराने होते हैं, इसलिए इसे खोने से कोई महत्वपूर्ण नुकसान नहीं होता। Upgrading का अर्थ है compose file में tag को edit करना और image को pull करना।

sudo docker compose pull
sudo docker compose up -d
curl -s https://ntfy.example.com/v1/health

सबसे पहले release notes पढ़ें। SQLite databases start होने पर migrate हो जाती हैं, इसलिए schema change के बाद पुराने tag पर वापस जाना (roll back) सुरक्षित नहीं है। जब तक नया version एक दिन तक सही ढंग से न चल जाए, तब तक उस backup को संभाल कर रखें जिसे आपने अभी लिया है।

Gotify और Apprise

Gotify एक छोटा विकल्प है: इसमें एक binary, एक web UI और एक Android app है। इसमें topic wildcards नहीं हैं और न ही कोई आधिकारिक iOS client है, जो उन private servers के लिए उपयुक्त है जहाँ केवल Android का उपयोग होता है। Apprise एक server के बजाय एक Python library और command line tool है। यह एक ही message को ntfy सहित सौ से अधिक services पर भेज सकता है, जो उन scripts के लिए उपयुक्त है जिन्हें एक साथ कई जगहों पर सूचना भेजनी होती है। ntfy एक ऐसा विकल्प है जो आपको एक server, एक HTTP API और दोनों mobile platforms पर apps प्रदान करता है। यही कारण है कि rented server से alerts भेजने के लिए इसे सबसे अधिक चुना जाता है।

FAQ

मेरे ntfy सर्वर पर पब्लिश करने पर 403 क्यों मिलता है?

auth-default-access: "deny-all" को server.yml में सेट करने पर, anonymous पब्लिशिंग को अस्वीकार कर दिया जाता है, और यह अपेक्षित व्यवहार है। -u user:pass या -H "Authorization: Bearer tk_..." के साथ क्रेडेंशियल्स भेजें। यदि आप पहले से ही टोकन भेज रहे हैं और फिर भी 403 मिल रहा है, तो उस टोकन के पीछे वाले उपयोगकर्ता के पास उस टॉपिक के लिए कोई मेल खाता ACL एंट्री नहीं है। पूरी सूची देखने के लिए ntfy access चलाएँ। याद रखें कि write ग्रांट सब्सक्राइब करने की अनुमति नहीं देता है, इसलिए जो अकाउंट पब्लिश तो ठीक से कर सकता है, उसे उसी टॉपिक को पढ़ने का प्रयास करने पर मना कर दिया जाएगा।

क्या सेल्फ-होस्टेड ntfy सर्वर के साथ iPhone पर नोटिफिकेशन काम करते हैं?

वे काम करते हैं, लेकिन एक रिले के माध्यम से जिसे आप टाल नहीं सकते। Apple ऐप्स को केवल APNs (Apple push notification service) के जरिए ही जगाता है, और केवल ऐप का पब्लिशर ही इसे भेज सकता है, इसलिए ntfy मैसेज ID युक्त एक poll_request को ntfy.sh पर फॉरवर्ड करता है, जो इसे डिवाइस तक रिले करता है। upstream-base-url: "https://ntfy.sh" को server.yml में सेट करें और कंटेनर को रीस्टार्ट करें। मैसेज बॉडी अभी भी आपके सर्वर से ही फेच की जाती है। इस सेटिंग के बिना, iOS नोटिफिकेशन में देरी होती है या वे कभी नहीं दिखते।

मेरे cron जॉब का ntfy अलर्ट कभी क्यों नहीं पहुँचा?

यह साबित करने के लिए कि टोकन और टॉपिक सही हैं, पहले curl लाइन को अकेले चलाकर देखें। यदि यह मैन्युअल रूप से काम करता है लेकिन cron से नहीं, तो विफलता अलर्ट से पहले की है: cron जॉब्स को एक न्यूनतम एनवायरनमेंट और छोटे PATH के साथ चलाता है, इसलिए जो स्क्रिप्ट किसी कमांड को केवल नाम से कॉल करती है, वह curl लाइन तक पहुँचने से पहले ही समाप्त हो सकती है। एब्सोल्यूट पाथ का उपयोग करें, जॉब के आउटपुट को एक लॉग फाइल में रीडायरेक्ट करें, और अगली बार चलने के बाद उस फाइल को पढ़ें। डिलीवरी के बजाय 429 रिस्पॉन्स का मतलब है कि रेट लिमिट काम कर रही है और आपकी स्क्रिप्ट बहुत तेजी से रिट्राई कर रही है।

क्या मुझे ntfy को पब्लिक इंटरनेट पर एक्सपोज करना चाहिए?

फोन ऐप्स को इसे मोबाइल नेटवर्क से एक्सेस करने की आवश्यकता होती है, इसलिए auth-default-access: "deny-all" और प्रति-टॉपिक ACLs के साथ एक पब्लिक HTTPS एंडपॉइंट सामान्य सेटअप है, और यह तब तक सुरक्षित है जब तक कोई भी टॉपिक everyone द्वारा पढ़ने योग्य न हो। केवल VPN वाला इंस्टेंस तब उचित है जब हर सब्सक्राइबर आपके द्वारा नियंत्रित मशीन हो। यह फोन के लिए उपयुक्त नहीं है, क्योंकि ऐप केवल तभी नोटिफिकेशन प्राप्त करता है जब टनल सक्रिय हो, इसलिए अलर्ट तब तक कतार में रहते हैं जब तक फोन फिर से कनेक्ट नहीं हो जाता।