Cara Self-Host ntfy untuk Notifikasi Server
Jalankan ntfy di VPS sendiri dengan TLS dan Docker Compose. Amankan topic memakai user serta ACL, lalu kirim peringatan dari cron dan unit systemd OnFailure.
Fungsi server ntfy yang di-host sendiri
Server ntfy yang di-host sendiri mengubah HTTP POST menjadi notifikasi push di ponsel Anda. Anda mengirim pesan menggunakan curl, lalu pesan tersebut tiba di aplikasi Android, aplikasi iOS, tab browser, atau perangkat lain yang dapat mempertahankan koneksi HTTP tetap terbuka. Anda tidak perlu memasang pustaka klien atau menjalankan message broker.
ntfy mengalamatkan pesan berdasarkan topic. Topic adalah nama pada path URL, seperti https://ntfy.example.com/alerts, dan langsung tersedia saat seseorang mengirim pesan ke sana. Pada instalasi default, siapa pun yang mengetahui nama tersebut dapat membaca dan menulis ke topic. Karena itu, dokumentasi resmi proyek ini membandingkan nama topic dengan password. Model tersebut sesuai untuk layanan ntfy.sh publik. Namun, model ini tidak sesuai untuk server yang mengirimkan kegagalan backup Anda. Karena itu, panduan ini mengaktifkan autentikasi sebelum pesan pertama dikirim.
Yang Anda perlukan sebelum memulai
Anda memerlukan VPS yang menjalankan Ubuntu 24.04 atau Debian 13 dengan Docker Engine dan plugin Compose, nama domain, serta RAM yang sangat kecil. Buat catatan DNS (domain name system) A yang mengarahkan ntfy.example.com ke alamat IP publik server, lalu pastikan catatan tersebut dapat di-resolve sebelum melakukan hal lain.
dig +short ntfy.example.com
sudo ufw allow 80,443/tcp
sudo ufw statusdig harus menampilkan IP server Anda. Penerbitan sertifikat gagal jika perintah tersebut tidak menampilkan apa pun karena otoritas sertifikat memeriksa nama tersebut dari luar. Port 80 harus tetap terbuka karena ACME (automatic certificate management environment), protokol yang digunakan Let's Encrypt, memakainya untuk challenge HTTP. Container ntfy sendiri tidak pernah membuka port publik.
Tulis file konfigurasi ntfy
Docker image tidak menyertakan file konfigurasi, jadi Anda harus membuatnya. Setiap perintah berikutnya dalam panduan ini membaca file tersebut. Pertama, cari user ID dan group ID yang akan digunakan 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.ymlbase-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: falseEmpat baris tersebut memiliki peran penting. base-url harus berupa alamat HTTPS publik yang tepat, karena ntfy menggunakannya untuk membuat tautan lampiran dan request dari web app. Nilai yang salah akan membuat web app berhasil dimuat, tetapi gagal menjalankan setiap tindakan. listen-http: ":2586" mengikat layanan ke semua interface di dalam container. Ini memang benar, meskipun terlihat terlalu terbuka. Container memiliki network namespace sendiri. Karena itu, jika layanan diikat ke 127.0.0.1 di dalam container, port tersebut tidak akan dapat dijangkau dari host dan koneksi ke published port Docker tidak akan pernah berhasil. auth-default-access: "deny-all" menentukan seluruh konfigurasi keamanannya, karena akses baca dan tulis ditolak bagi siapa pun yang tidak memiliki izin eksplisit. behind-proxy: true memberi tahu ntfy agar mengambil alamat client dari header X-Forwarded-For. Dengan begitu, rate limit menghitung pengunjung yang sebenarnya, bukan reverse proxy sebagai satu client yang sangat aktif.
enable-login: true memungkinkan web app dan aplikasi ponsel masuk menggunakan password. enable-signup tetap false, karena pembuatan akun mandiri pada server privat merupakan celah akses yang tidak perlu.
sudo chown "$(id -u):$(id -g)" /etc/ntfy/server.yml
sudo chmod 600 /etc/ntfy/server.ymlJalankan ntfy dengan Docker Compose
Letakkan ini di /opt/ntfy/compose.yaml, lalu ganti 1000:1000 dengan dua angka id -u dan id -g yang tercetak di atas.
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-stoppedcd /opt/ntfy
sudo docker compose up -d
sudo docker compose logs ntfy
curl -s http://127.0.0.1:2586/v1/healthServer yang sehat merespons {"healthy":true}. Dua detail dalam file compose tersebut sengaja dibuat demikian. Image dikunci ke v2.27.0, yaitu rilis saat ini per Agustus 2026, bukan latest, karena dengan latest, docker compose pull berikutnya akan mengubah versi server Anda dan Anda baru mengetahuinya dari changelog setelah perubahan terjadi. Port dipublikasikan sebagai 127.0.0.1:2586:2586, sehingga container hanya dapat dijangkau dari alamat loopback host. Jika Anda menulis 2586:2586, Docker menyisipkan aturan firewall-nya sendiri sebelum aturan Anda. Akibatnya, port tersebut dapat diakses dari Internet meskipun ufw status menyatakan bahwa port itu tertutup.
Jika curl mencetak Connection refused, baca log container. Error izin pada /var/lib/ntfy/user.db berarti baris user: tidak sesuai dengan pemilik direktori tersebut. Akibatnya, proses tidak dapat membuat database sendiri dan keluar. Panduan dasar Docker Compose untuk VPS membahas kepemilikan volume dan kebijakan restart secara lebih rinci.
Letakkan TLS di depan dengan Caddy
Caddy meminta dan memperbarui sertifikat secara mandiri. Ini adalah cara tercepat untuk mengaktifkan TLS (keamanan lapisan transport).
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 caddyGanti isi /etc/caddy/Caddyfile dengan tiga baris.
ntfy.example.com {
reverse_proxy 127.0.0.1:2586
}sudo systemctl reload caddy
curl -s https://ntfy.example.com/v1/health{"healthy":true} yang sama melalui HTTPS menunjukkan bahwa seluruh jalur berfungsi. 502 dari Caddy berarti ntfy tidak sedang mendengarkan: periksa dengan sudo ss -lntp | grep 2586. Error sertifikat biasanya berarti record DNS salah atau port 80 diblokir. sudo journalctl -u caddy -n 50 menunjukkan penyebabnya.
Jika Anda sudah menjalankan nginx, salin pengaturan proxy yang didokumentasikan ntfy: proxy_http_version 1.1, proxy_buffering off, proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for, serta timeout baca dan kirim minimal tiga menit. Subscriber mempertahankan satu koneksi HTTP tetap terbuka selama masih mendengarkan. nginx secara default menutup koneksi upstream yang menganggur setelah 60 detik. Akibatnya, subscriber terhubung kembali berulang kali dan pesan yang dikirim selama jeda terlewat.
Buat pengguna dan batasi akses topik
Autentikasi sudah aktif, tetapi belum ada yang memiliki akses ke apa pun. Memang demikian tujuannya. Buat satu akun admin untuk Anda sendiri dan satu akun mesin untuk skrip. Perintah ini membaca /etc/ntfy/server.yml dari dalam container. Karena itu, file konfigurasi dipasang sebagai volume.
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 listSetiap perintah akan meminta password. Admin mengabaikan daftar kontrol akses dan dapat membaca serta menulis ke setiap topik. Karena itu, gunakan akun tersebut hanya untuk Anda sendiri dan aplikasi ponsel. robot adalah pengguna biasa tanpa akses apa pun sampai Anda memberinya akses.
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 accessEntri ACL (access control list) terdiri atas pengguna, topik, dan izin. Topik dapat berupa nama literal atau pattern dengan * yang mencocokkan apa pun. Dengan demikian, alerts_* mencakup alerts_backup dan alerts_db tanpa memerlukan satu perintah untuk setiap host. Izin write berarti hanya dapat melakukan publish. Dengan demikian, token yang dicuri dari cron job tidak dapat melakukan subscribe dan membaca kembali data yang dikirimnya. Nama pengguna khusus everyone menentukan tindakan yang dapat dilakukan pengunjung tanpa autentikasi. Gunakan nama ini hanya jika Anda sengaja ingin membuka sesuatu untuk publik, seperti ntfy access everyone status read.
Skrip harus menggunakan token, bukan password Anda.
sudo docker compose exec ntfy ntfy token add robotPerintah tersebut mencetak token yang diawali dengan tk_. Token mewarisi akses pengguna yang terkait dengannya secara persis. Karena itu, token ini hanya dapat melakukan publish ke topik alerts dan tidak dapat melakukan tindakan lain. ntfy token list menampilkan entri yang ada, sedangkan ntfy token remove mencabut salah satunya tanpa mengubah password pengguna.
Kirim pesan pertama dan buktikan bahwa penguncian berfungsi
Mulai dengan memeriksa bahwa pintu sudah tertutup.
curl -s -o /dev/null -w '%{http_code}\n' -d "hello" https://ntfy.example.com/alertsPerintah tersebut mencetak 403, dan 403 adalah jawaban yang benar: auth-default-access: "deny-all" menolak publikasi anonim. Sekarang kirim pesan yang sebenarnya.
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/alertsServer membalas dengan pesan yang tersimpan dalam format JSON. Dengan demikian, Anda tahu bahwa pesan tersebut diterima, bukan diabaikan. Title adalah baris pertama yang dicetak tebal. Priority menggunakan nilai dari 1 hingga 5, atau nama dari min hingga urgent. Nilai ini menentukan apakah ponsel mengeluarkan suara. Tags menjadi emoji pada notifikasi jika namanya cocok dengan kode singkat emoji yang dikenal, dan tetap menjadi teks biasa jika tidak cocok.
Untuk memantau topic dari terminal, alirkan datanya:
curl -s -u admin https://ntfy.example.com/alerts/rawcurl meminta password. Setiap pesan muncul sebagai satu baris, sedangkan baris kosong yang sesekali muncul adalah keepalive. Buka https://ntfy.example.com di browser dan masuk menggunakan akun yang sama untuk mendapatkan versi web dari aliran yang sama.
Tetapkan batas laju agar satu skrip tidak membanjiri server
Secara default, setiap pengunjung mendapatkan bucket berisi 60 request yang diisi kembali dengan laju satu request setiap 5 detik. Batas ini cukup longgar untuk server pribadi, dan skrip yang terjebak dalam loop retry akan menghabiskan seluruhnya. Tambahkan batas ke server.yml.
visitor-request-limit-burst: 30
visitor-request-limit-replenish: "10s"
visitor-message-daily-limit: 500sudo docker compose restart ntfyPengunjung yang melewati batas akan menerima HTTP 429, bukan pesan yang berhasil dikirimkan. Batas ini dihitung berdasarkan alamat pengunjung. Karena itu, behind-proxy: true sangat penting: tanpa pengaturan tersebut, ntfy hanya melihat alamat Caddy, sehingga semua client dihitung sebagai pengunjung yang sama. Akibatnya, satu skrip yang terlalu banyak mengirim request dapat menghabiskan bucket yang digunakan bersama oleh ponsel dan server Anda yang lain.
Peringatan dari cron job yang gagal
Jangan menaruh token pada baris perintah. ps aux menampilkan baris perintah lengkap dari setiap proses yang berjalan kepada setiap pengguna pada server, sehingga token yang diteruskan dengan -H dapat dibaca oleh akun lokal mana pun selama curl berjalan. File konfigurasi curl menghindari masalah tersebut.
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/curlrcSekarang bungkus job tersebut. Simpan sebagai /usr/local/bin/backup-with-alert.sh, lalu jadikan 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$? ditangkap pada baris tepat setelah perintah tersebut karena perintah berikutnya akan menimpanya. Output diteruskan melalui tail -c 1000 karena ntfy menerapkan ukuran pesan maksimum dan notifikasi bukan penampil log. exit "$code" penutup mempertahankan status asli, sehingga apa pun yang memantau job ini tetap melihat kegagalan. Uji seluruh proses dengan mengarahkan skrip ke /bin/false untuk satu kali eksekusi.
Branch kegagalan yang tidak pernah dijalankan lebih buruk daripada tidak memiliki sistem peringatan, karena kondisi tersebut membuat keheningan terlihat seperti keberhasilan. Cron memberikan environment yang hampir kosong kepada job Anda dan PATH yang jauh lebih pendek daripada shell login Anda. Karena itu, skrip yang berhasil saat dijalankan secara manual dapat berhenti sebelum mencapai baris curl. Panduan tentang alasan cron job tidak berjalan membahas masalah environment tersebut. Gunakan path absolut di semua tempat, lalu baca file log setelah eksekusi terjadwal pertama, bukan berasumsi semuanya berhasil.
Waspadai kegagalan unit systemd
Cron menangani pekerjaan terjadwal. Layanan yang berjalan lama memerlukan OnFailure=, yang dijalankan systemd setiap kali unit memasuki status failed. Buat satu unit template dan gunakan kembali untuk setiap service pada server. Simpan sebagai /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 %iKemudian /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/alertsPasang pada sebuah service menggunakan drop-in agar upgrade paket tidak menimpa perubahan Anda.
sudo systemctl edit myapp.service[Unit]
OnFailure=ntfy-unit-failed@%n.service%n diperluas menjadi nama unit lengkap, sehingga instance menjadi ntfy-unit-failed@myapp.service, dan %i di dalam template meneruskan myapp.service ke skrip sebagai argumen pertamanya. Dengan demikian, satu template dapat digunakan untuk setiap unit. Buktikan bahwa konfigurasi ini berfungsi dengan unit yang sengaja dibuat gagal, lalu simpan sebagai /etc/systemd/system/ntfy-selftest.service.
[Unit]
Description=Deliberately failing unit
OnFailure=ntfy-unit-failed@%n.service
[Service]
Type=oneshot
ExecStart=/bin/falsesudo systemctl daemon-reload
sudo systemctl start ntfy-selftest.servicePerintah start keluar dengan kode non-zero dan mencetak Job for ntfy-selftest.service failed because the control process exited with error code. Ponsel akan bergetar sekitar satu detik kemudian. Hapus unit pengujian setelah selesai.
Perhatikan satu jebakan. OnFailure= hanya berjalan ketika unit mencapai status failed. Service dengan Restart=always mungkin tidak pernah mencapai status tersebut karena systemd terus me-restart-nya. Unit baru dianggap gagal setelah melebihi StartLimitBurst restart dalam StartLimitIntervalSec. Tetapkan kedua nilai tersebut pada setiap service yang ingin Anda pantau. Jika tidak, loop crash dapat terus berjalan tanpa terdeteksi selama berhari-hari. Timer merupakan pengganti yang lebih baik untuk pola cron di atas karena service unit milik timer mendapatkan OnFailure= secara otomatis, dan panduan tentang service dan timer systemd pada VPS menjelaskan cara mengonversi salah satunya.
Hubungkan monitor uptime ke topik yang sama
Uptime Kuma, monitor status yang di-host sendiri, menyediakan jenis notifikasi ntfy. Buka Settings, lalu Notifications, kemudian Setup Notification, pilih Ntfy, tetapkan URL server ke https://ntfy.example.com dan topik ke alerts, pilih prioritas, lalu tempel token akses robot. Kirim notifikasi uji sebelum menyimpan, karena nama topik yang salah gagal secara diam-diam pada grant write yang tidak mencakupnya.
Batasan pengaturan ini perlu dipahami: monitor yang berjalan pada VPS yang sama tidak dapat memberi tahu bahwa VPS tersebut tidak aktif, dan ntfy tidak dapat menyampaikan informasi bahwa ntfy tidak aktif. Jalankan monitor pada mesin lain, lalu berikan kanal notifikasi kedua, seperti email, untuk monitor yang mengawasi ntfy itu sendiri. Jenis monitor Push di Uptime Kuma mengatasi titik buta lainnya: tugas cron Anda memanggil URL push setelah berhasil dijalankan, dan Kuma mengirim peringatan ketika panggilan tersebut berhenti masuk. Cabang kegagalan hanya aktif ketika tugas dijalankan, sehingga tidak dapat memberi tahu bahwa tugas tidak pernah dimulai.
Apakah ntfy yang di-self-host dapat digunakan pada Android dan iPhone?
Pada Android, ya, tanpa pengecualian. Instal aplikasi dari Google Play atau F-Droid, buka Settings, tetapkan server default ke https://ntfy.example.com, tambahkan akun Anda pada layar pengelolaan pengguna, lalu subscribe ke alerts. Pengiriman instan mempertahankan foreground service agar pesan tetap diterima meskipun ponsel berada dalam mode doze. Notifikasi permanen yang menyertainya merupakan persyaratan Android untuk foreground service, bukan bug. Build F-Droid sama sekali tidak menyertakan kode Firebase, sehingga setiap subscription menggunakan pengiriman instan. ntfy juga dapat berfungsi sebagai distributor UnifiedPush, yaitu pengganti terbuka untuk layanan push Google. Dengan demikian, aplikasi lain yang mendukung UnifiedPush juga dapat mengirim notifikasi melalui server Anda.
Pada iOS, fitur ini berfungsi dengan satu dependensi yang tidak dapat dihapus. Apple hanya membangunkan aplikasi yang berjalan di latar belakang melalui APNs (Apple push notification service). Hanya pihak yang memegang kredensial penandatanganan aplikasi yang dapat mengirim notifikasi ke aplikasi tersebut. Karena itu, server Anda tidak dapat menghubungi aplikasi secara langsung. ntfy mengatasi hal ini dengan relay: server Anda mengirim poll_request yang berisi ID pesan ke ntfy.sh. ntfy.sh meneruskannya melalui Firebase dan APNs untuk membangunkan aplikasi. Aplikasi kemudian mengambil isi pesan dari server Anda.
upstream-base-url: "https://ntfy.sh"Pahami konsekuensi pengaturan ini. Isi pesan tetap berada di server Anda, tetapi fakta bahwa pesan telah diterima dan ID pesannya melewati infrastruktur yang tidak Anda kelola. Tanpa pengaturan ini, notifikasi pada iPhone dari server yang di-self-host akan terlambat atau tidak diterima sama sekali karena tidak ada mekanisme yang membangunkan aplikasi. Satu-satunya cara untuk menghapus relay adalah membangun dan mengirimkan aplikasi iOS sendiri menggunakan akun Apple developer serta kunci APNs milik Anda. Cara ini memerlukan biaya tahunan dan build ulang untuk setiap pembaruan. Jika relay tidak dapat diterima untuk kebutuhan Anda, gunakan Android atau aplikasi web desktop untuk menerima notifikasi.
Cadangan, upgrade, dan pinning image
Dua path tidak dapat dibuat ulang: /etc/ntfy/server.yml dan /var/lib/ntfy/user.db. Path kedua menyimpan semua pengguna, hash kata sandi, entri ACL, dan token. Perlakukan path ini seperti private key.
sudo tar czf ntfy-backup.tgz -C / etc/ntfy var/lib/ntfy
sudo chmod 600 ntfy-backup.tgzSalin file tersebut ke luar server. cache.db hanya menyimpan pesan terbaru selama 12 jam, bersama cache-duration di atas. Kehilangannya tidak menimbulkan dampak yang perlu dilindungi. Untuk melakukan upgrade, edit tag dalam file compose lalu jalankan proses pull.
sudo docker compose pull
sudo docker compose up -d
curl -s https://ntfy.example.com/v1/healthBaca catatan rilis terlebih dahulu. Database SQLite dimigrasikan saat proses start. Karena itu, melakukan rollback ke tag yang lebih lama setelah perubahan skema tidak aman. Simpan cadangan yang baru dibuat sampai versi baru berjalan selama satu hari.
Gotify dan Apprise
Gotify adalah opsi yang lebih kecil: satu binary dengan web UI dan aplikasi Android, tanpa wildcard topik dan tanpa klien iOS resmi. Ini cocok untuk server privat yang hanya menargetkan Android. Apprise adalah library Python dan alat command line, bukan server. Apprise meneruskan satu pesan ke lebih dari seratus layanan, termasuk ntfy. Ini cocok untuk skrip yang harus mengirim pesan ke beberapa tujuan sekaligus. ntfy menyediakan server, API HTTP, serta aplikasi untuk kedua platform seluler. Karena itu, ntfy biasanya digunakan untuk mengirim alert dari server sewaan.
FAQ
Mengapa publikasi ke server ntfy saya menghasilkan 403?
Dengan auth-default-access: "deny-all" di server.yml, publikasi anonim ditolak. Ini merupakan perilaku yang memang diharapkan. Kirim kredensial dengan -u user:pass atau -H "Authorization: Bearer tk_...". Jika Anda sudah mengirim token tetapi masih menerima 403, pengguna di balik token tersebut tidak memiliki entri ACL yang cocok untuk topik itu. Jalankan ntfy access untuk menampilkan daftar lengkapnya. Ingat bahwa grant write tidak mengizinkan subscribe, sehingga akun yang berhasil melakukan publikasi tetap akan ditolak saat mencoba membaca topik yang sama.
Apakah notifikasi berfungsi di iPhone dengan server ntfy yang di-host sendiri?
Notifikasi berfungsi melalui relay yang tidak dapat dihindari. Apple hanya membangunkan aplikasi melalui APNs (Apple push notification service), dan hanya publisher aplikasi yang dapat mengirim ke layanan tersebut. Karena itu, ntfy meneruskan poll_request yang berisi ID pesan ke ntfy.sh, lalu layanan tersebut meneruskannya ke perangkat. Atur upstream-base-url: "https://ntfy.sh" di server.yml, lalu restart container. Isi pesan tetap diambil dari server Anda. Tanpa pengaturan tersebut, notifikasi iOS tertunda atau tidak pernah muncul.
Mengapa peringatan ntfy dari cron job saya tidak pernah diterima?
Jalankan baris curl secara terpisah terlebih dahulu untuk memastikan token dan topiknya benar. Jika berhasil dijalankan secara manual tetapi gagal dari cron, masalahnya terjadi sebelum peringatan dikirim. cron menjalankan job dengan environment minimal dan PATH yang singkat, sehingga script yang memanggil command tanpa nama lengkap path dapat berhenti sebelum mencapai baris curl. Gunakan path absolut, alihkan output job ke file log, lalu baca file tersebut setelah eksekusi berikutnya. Respons 429, bukan pengiriman notifikasi, berarti rate limit berfungsi dan script Anda mencoba lagi terlalu cepat.
Haruskah saya mengekspos ntfy ke Internet publik?
Aplikasi ponsel harus dapat mengaksesnya dari jaringan seluler. Karena itu, endpoint HTTPS publik dengan auth-default-access: "deny-all" dan ACL per topik merupakan konfigurasi yang umum, dan tetap aman selama tidak ada topik yang dapat dibaca oleh everyone. Instance yang hanya dapat diakses melalui VPN merupakan pilihan yang wajar jika setiap subscriber adalah mesin yang Anda kendalikan. Namun, konfigurasi ini kurang sesuai untuk ponsel karena aplikasi hanya menerima notifikasi saat tunnel aktif. Akibatnya, peringatan akan mengantre sampai ponsel tersambung kembali.