ntfy : la notification push réduite à une requête HTTP
← Retour
Électronique

ntfy : la notification push réduite à une requête HTTP

Cédrix · 28/07/2026
Modifié le 28 juillet 2026 à 07h53

Chapô — Envoyer une alerte sur son téléphone depuis un script shell ne devrait pas exiger un compte développeur, un SDK propriétaire et trois semaines d’intégration. C’est le pari tenu par ntfy, un service de publication/abonnement (pub-sub) bâti sur HTTP, auto-hébergeable, dont l’API tient en une ligne de curl. Derrière cette apparente trivialité se cache une architecture qui compose habilement avec les contraintes des écosystèmes mobiles. Plongée technique.


1. Le chaînon manquant entre la machine et l’humain

Tout administrateur système connaît ce trou fonctionnel. Une sauvegarde nocturne échoue, un certificat arrive à expiration, un capteur domotique se déclenche, un job de rendu de six heures se termine : il faudrait prévenir un humain, tout de suite, sur l’appareil qu’il a dans la poche. Les réponses classiques sont soit lourdes (une chaîne Prometheus + Alertmanager + PagerDuty), soit inadaptées (un courriel que personne ne lit avant le lendemain), soit captives (un service SaaS de notification, avec son quota, son abonnement et son API maison).

ntfy — à prononcer « notify » — répond à ce besoin précis avec une hypothèse minimaliste : une notification n’est rien d’autre qu’un message publié sur un canal nommé, et HTTP suffit à le transporter. Le projet est écrit en Go par Philipp C. Heckel, distribué sous double licence Apache 2.0 et GPLv2, et disponible à la fois comme service public gratuit sur ntfy.sh et comme binaire auto-hébergeable. Au moment où ces lignes sont écrites, le serveur en est à la version 2.26, avec des applications mobiles Android et iOS libres, une application web et une interface en ligne de commande.

L’ensemble représente aujourd’hui un projet mature, largement intégré à l’écosystème de la supervision libre — Home Assistant, Netdata, Grafana, Uptime Kuma, Watchtower, les arr, Traccar et des dizaines d’autres savent y publier nativement ou via un simple webhook*.


2. Le cœur du réacteur : pub/sub en HTTP nu

2.1 Deux verbes, un chemin

Le modèle conceptuel se résume à un tableau blanc :

  • Publier : POST ou PUT sur https://serveur/<topic>, le corps de la requête est le message.
  • S’abonner : GET sur https://serveur/<topic>, la connexion reste ouverte et le serveur y écrit les messages au fil de l’eau.
# Abonnement (terminal 1)
curl -s https://ntfy.sh/salle-machine-42

# Publication (terminal 2, ou depuis n'importe quelle machine du monde)
curl -d "Onduleur sur batterie" https://ntfy.sh/salle-machine-42

Il n’y a ni création préalable de canal, ni inscription, ni clé d’API dans la configuration par défaut. Le topic naît implicitement lors du premier abonnement ou de la première publication, et meurt quand plus personne ne s’y intéresse. Cette absence de cérémonie est le trait de conception le plus structurant du projet : elle rend ntfy scriptable partout où existe un client HTTP, c’est-à-dire à peu près partout, y compris sur des équipements réseau anciens, des automates industriels ou un busybox wget dans un conteneur de 5 Mo.

2.2 Ce que faisaient les 138 premières lignes

Le mécanisme interne mérite d’être décrit, car il n’a pratiquement pas changé depuis le premier commit du projet, un fichier main.go de 138 lignes que son auteur a documenté publiquement.

Le serveur maintient en mémoire une table associant chaque nom de topic à une liste d’abonnés. Un abonné n’est rien d’autre qu’une fonction capable d’écrire une ligne dans une réponse HTTP restée ouverte. Lorsque le gestionnaire GET est appelé, il crée le topic s’il n’existe pas, enregistre l’abonné dans la liste, puis se bloque sans jamais refermer la requête — exactement le principe du long polling ou des Server-Sent Events. Quand le gestionnaire PUT/POST reçoit un message, il retrouve le topic et écrit dans chacune des sockets encore ouvertes.

C’est tout. La sophistication ultérieure — cache, authentification, pièces jointes, passerelles mobiles — s’est empilée autour de ce noyau sans le remplacer. L’API originelle fonctionne encore telle quelle aujourd’hui, ce qui explique la stabilité remarquable des intégrations tierces.


3. Anatomie d’un message

Un message ntfy n’est pas qu’une chaîne de caractères. Ses métadonnées se transmettent au choix par en-têtes HTTP ou par un corps JSON publié à la racine du serveur. Les deux formes sont strictement équivalentes ; la première se prête aux scripts, la seconde aux clients programmatiques.

curl \
  -H "Title: Sauvegarde échouée" \
  -H "Priority: high" \
  -H "Tags: warning,floppy_disk" \
  -H "Click: https://backup.interne/rapports/1234" \
  -H "Actions: http, Relancer, https://backup.interne/api/rerun/1234, method=POST" \
  -d "Le volume /srv/data n'a pas pu être monté (code 32)." \
  https://ntfy.sh/backups-prod
POST / HTTP/1.1
Host: ntfy.sh

{
  "topic": "backups-prod",
  "title": "Sauvegarde échouée",
  "message": "Le volume /srv/data n'a pas pu être monté (code 32).",
  "priority": 4,
  "tags": ["warning", "floppy_disk"],
  "click": "https://backup.interne/rapports/1234"
}

Les principales dimensions du protocole :

En-tête Rôle
Title Titre de la notification, distinct du corps
Priority (p) Niveau de 1 (min) à 5 (max) ; pilote le son, la vibration et le contournement du mode « Ne pas déranger »
Tags Étiquettes libres ; certaines sont traduites automatiquement en émoji (warning → ⚠️)
Click URL ouverte au tap sur la notification
Actions Jusqu’à trois boutons d’action : ouvrir une URL, émettre une requête HTTP arbitraire, diffuser un intent Android
Attach / corps binaire Pièce jointe par URL externe ou téléversée sur le serveur
Delay (At, In) Livraison différée : horodatage Unix, date en langage naturel ou durée (30m, tomorrow, 8am)
Email Réexpédition simultanée vers une adresse de courriel
Call Appel téléphonique avec synthèse vocale du message (via Twilio)
Markdown Rendu enrichi du corps dans les clients qui le supportent
Template Transformation d’une charge utile JSON par un gabarit serveur
Cache, Firebase Désactivation sélective du cache serveur ou du relais Firebase

Deux fonctionnalités récentes méritent qu’on s’y arrête.

Les gabarits (templates). Un webhook GitHub, Grafana ou Alertmanager émet un JSON verbeux, illisible tel quel sur un écran de téléphone. Depuis les versions 2.2x, ntfy sait le transformer côté serveur : il suffit d’ajouter ?template=github à l’URL du topic pour que la charge utile brute soit remise en forme selon un gabarit prédéfini. Des gabarits personnalisés peuvent être déposés dans un répertoire dédié du serveur, avec l’appoint des fonctions de la bibliothèque Sprig. Cela transforme ntfy en adaptateur universel de webhooks — sans écrire une ligne de code intermédiaire. La version 2.26 a d’ailleurs durci l’exécution de ces gabarits en leur imposant une limite de temps stricte, pour fermer un risque de déni de service.

La mise à jour et la suppression de notifications, ainsi que les notifications de type heartbeat (« homme mort »), introduites début 2026. Une notification n’est plus immuable : un client peut la modifier ou la retirer après coup. Le mécanisme de heartbeat programme une alerte future que chaque battement de cœur repousse ; si les battements cessent, l’alerte se déclenche. C’est le motif exact dont on a besoin pour surveiller une tâche planifiée ou un équipement isolé — l’absence de signal devient l’événement.


4. Quatre façons de recevoir

Côté abonné, ntfy expose plusieurs transports qui diffèrent uniquement par le format de la réponse, et non par la sémantique :

  • Flux JSONGET /<topic>/json : un objet JSON par ligne. C’est le format le plus simple à consommer en shell, avec jq en aval.
  • SSEGET /<topic>/sse : des Server-Sent Events, directement exploitables par l’objet EventSource d’un navigateur.
  • WebSocketGET /<topic>/ws : pour les clients qui préfèrent une connexion bidirectionnelle.
  • Interrogation ponctuelle — le paramètre poll=1 change le comportement : le serveur renvoie les messages disponibles puis referme immédiatement la connexion. Idéal pour un cron ou un environnement qui supporte mal les connexions longues.
# Consommation shell d'un flux JSON
curl -s https://ntfy.sh/backups-prod/json | while read -r ligne; do
  titre=$(jq -r '.title // "(sans titre)"' <<< "$ligne")
  corps=$(jq -r '.message' <<< "$ligne")
  logger -t ntfy "[$titre] $corps"
done

Le paramètre since= complète le dispositif : il accepte une durée (10m), un horodatage Unix, un identifiant de message ou le mot-clé all, et permet de rattraper ce qui a été manqué pendant une coupure réseau. Cela suppose que le serveur ait activé son cache de messages — une base de données qui conserve les messages pendant une durée configurable (douze heures sur l’instance publique, paramétrable en auto-hébergement). Ce cache est aussi ce qui rend possibles la livraison différée et la relecture d’historique par un client mobile qui se reconnecte.

Point important pour la conception d’une architecture : ntfy n’est pas une file de messages. Il n’y a ni accusé de réception, ni garantie de livraison exactement-une-fois, ni persistance longue. C’est un bus de diffusion éphémère, à sémantique « au mieux ». Confondre ntfy avec RabbitMQ ou NATS mènerait à de sérieuses déconvenues.


5. Le mur du mobile : FCM, APNs, UnifiedPush et Web Push

C’est ici que l’élégance du modèle initial se heurte au monde réel. Un flux HTTP maintenu ouvert en permanence est parfait sur un serveur, acceptable sur un poste de travail, et problématique sur un téléphone : les systèmes mobiles tuent agressivement les processus d’arrière-plan pour préserver la batterie.

Sur Android, l’application existe en deux variantes. Celle distribuée sur Google Play utilise Firebase Cloud Messaging (FCM) pour les topics hébergés sur ntfy.sh : le serveur relaie le message à Google, qui le pousse au terminal via le canal système déjà maintenu par l’OS — coût batterie nul, mais Google voit passer les messages, et les délais de livraison peuvent s’étirer quand le téléphone dort. La variante distribuée sur F-Droid, ainsi que tout abonnement à un serveur auto-hébergé, n’utilise jamais Firebase : l’application maintient elle-même une connexion (flux JSON ou WebSocket) au serveur. C’est le mode dit de « livraison instantanée », activable également sur ntfy.sh au prix d’une consommation de batterie légèrement supérieure.

Sur iOS, il n’y a pas d’échappatoire : Apple interdit tout processus d’arrière-plan persistant, y compris le simple polling. Toute notification doit transiter par l’Apple Push Notification service (APNs). Pour une instance auto-hébergée, cela impose un détour architectural inhabituel : le serveur local n’envoie pas le message, mais une requête de réveil qui remonte jusqu’à ntfy.sh, puis FCM, puis APNs, puis le terminal — lequel redescend ensuite interroger directement le serveur auto-hébergé pour récupérer le contenu réel. Le message ne transite donc pas par l’infrastructure tierce, mais le signal de réveil, si. C’est le seul point où l’auto-hébergement ntfy reste couplé au service central, et c’est une contrainte de la plateforme, pas un choix du projet.

UnifiedPush offre la porte de sortie du côté Android. ntfy implémente cette spécification en tant que distributeur et en tant que serveur push : une application compatible UnifiedPush (Element, Fediverse, etc.) peut déléguer ses notifications à ntfy plutôt qu’à Firebase, l’utilisateur choisissant librement son serveur de push. ntfy sait également se comporter en passerelle Matrix (Matrix Push Gateway), en traduisant les notifications Matrix vers le format UnifiedPush.

Web Push, enfin, sert l’application web et sa déclinaison PWA : les messages sont chiffrés puis relayés par le serveur de push de l’éditeur du navigateur (Mozilla, Google, Apple, Microsoft), ce qui autorise les notifications en arrière-plan, onglet fermé. Les clés VAPID sont générées automatiquement par le serveur.

À cela s’ajoute un canal souvent négligé : la publication par courriel. Le serveur embarque un petit serveur SMTP ; envoyer un message à ntfy-<topic>@ntfy.sh publie son contenu sur le topic correspondant. Pour les équipements qui ne savent parler que SMTP — vieux routeurs, onduleurs, NAS d’ancienne génération — c’est la passerelle idéale vers le monde du push moderne.


6. Auto-hébergement : ce que ça coûte vraiment

C’est probablement l’argument le plus fort du projet. Le serveur est un binaire Go unique, sans dépendance externe, qui embarque le service, la documentation et l’application web React compilée. Aucun asset à servir séparément, aucun runtime à installer.

# Déploiement minimal en conteneur
docker run -d \
  --name ntfy \
  -p 2586:80 \
  -v /srv/ntfy/cache:/var/cache/ntfy \
  -v /srv/ntfy/etc:/etc/ntfy \
  binwiederhier/ntfy serve

Des paquets .deb et .rpm sont publiés pour amd64, arm64 et armv6 — un Raspberry Pi fait parfaitement l’affaire — et le service tourne désormais aussi nativement sous Windows.

La configuration se concentre dans un unique server.yml :

base-url: "https://ntfy.exemple.fr"
listen-http: ":2586"
behind-proxy: true

# Cache de messages
cache-file: "/var/lib/ntfy/cache.db"
cache-duration: "12h"

# Authentification et contrôle d'accès
auth-file: "/var/lib/ntfy/user.db"
auth-default-access: "deny-all"

# Pièces jointes
attachment-cache-dir: "/var/lib/ntfy/attachments"
attachment-expiry-duration: "3h"

Le stockage repose sur SQLite par défaut — un fichier pour le cache de messages, un pour les utilisateurs et les ACL, un pour les abonnements Web Push — avec la possibilité de basculer sur PostgreSQL via database-url pour les déploiements à fort volume. L’instance publique ntfy.sh a d’ailleurs effectué cette migration ; elle a longtemps tourné sur SQLite avec des écritures groupées et une file en mémoire, ce qui en dit long sur ce que SQLite encaisse quand on l’utilise correctement.

Un mot sur la mise en production : ntfy se place derrière un reverse proxy (nginx, Caddy, Traefik) pour la terminaison TLS. Attention à la configuration du proxy : les connexions d’abonnement sont, par nature, des connexions HTTP qui ne se ferment jamais. Il faut désactiver ou allonger considérablement les timeouts de lecture en amont, et prévoir le passage de l’en-tête Upgrade pour les WebSockets. Le paramètre behind-proxy: true est également indispensable pour que ntfy applique ses limitations de débit sur l’IP réelle du client et non sur celle du proxy.


7. Modèle de sécurité : lucidité requise

C’est le point sur lequel un article technique se doit d’être explicite, car la simplicité de ntfy s’accompagne d’un modèle de menace qu’il faut comprendre.

Par défaut, le nom du topic est le secret. Sans authentification, quiconque connaît le nom d’un canal peut y lire et y écrire. La documentation le dit sans ambages : le topic joue le rôle d’un mot de passe. Un canal nommé alerts sur ntfy.sh est, en pratique, public. Un canal nommé k7Rz-prod-backups-9fQx2 ne l’est pas — mais il repose sur l’obscurité, pas sur un contrôle d’accès. Pour tout usage professionnel, cette configuration est à proscrire.

La configuration sérieuse passe par le contrôle d’accès. ntfy implémente deux rôles (user, admin) et des permissions par topic sous forme de liste de contrôle d’accès. Le pivot est auth-default-access: deny-all, qui bascule le serveur en mode « tout est interdit sauf ce qui est explicitement permis ». Les entrées s’écrivent en CLI ou, depuis les versions récentes, se déclarent directement dans le fichier de configuration (utilisateurs, ACL et jetons provisionnés de manière déclarative — un vrai confort pour une gestion par Ansible ou NixOS) :

ntfy user add --role=user superviseur
ntfy access superviseur 'alertes-*' write-only
ntfy access lecteur     'alertes-prod' read-only
ntfy token add superviseur       # produit un jeton tk_...

L’authentification se fait ensuite en HTTP Basic ou par jeton porteur :

curl -H "Authorization: Bearer tk_AbCdEf..." -d "OK" https://ntfy.exemple.fr/alertes-prod

Le caractère * sert de joker dans les motifs de topics, et l’utilisateur spécial everyone (ou *) représente les accès anonymes. Un cache ACL en mémoire, optionnel, évite un aller-retour en base à chaque autorisation sur les serveurs très sollicités.

Ce que ntfy ne fait pas. Il n’y a pas de chiffrement de bout en bout : le serveur voit le contenu des messages en clair — ce qui est structurellement nécessaire pour le rendu des gabarits, la réexpédition par courriel ou la synthèse vocale. Sur l’instance publique, cela signifie que l’exploitant du service, et le cas échéant Google via FCM, ont accès au contenu. Aucune donnée sensible ne doit transiter par un topic public. Pour un usage professionnel, l’auto-hébergement avec ACL et TLS est la seule configuration défendable — et, même là, le message reste en clair au repos dans le cache serveur.

La lutte contre l’abus occupe une part croissante du développement. Le serveur applique des limitations de débit par visiteur — messages par jour, nombre d’abonnements, création de nouveaux topics — et sait alimenter un fichier que fail2ban peut surveiller pour bannir les adresses abusives au niveau du pare-feu. Une limite spécifique sur la création de topics a été ajoutée en 2026 pour contrer les attaques d’énumération qui faisaient gonfler la table en mémoire du serveur. Ces mécanismes valent la peine d’être activés dès qu’une instance est exposée sur l’Internet public.


8. Où ntfy trouve sa place

Trois familles d’usages se dégagent nettement sur le terrain.

La supervision légère. Là où déployer une chaîne d’alerting complète est disproportionné — une PME, un laboratoire, une infrastructure de quelques dizaines de machines — ntfy fournit le dernier kilomètre à moindre coût. Une ligne ajoutée à un script de sauvegarde, une URL de webhook dans Grafana, et l’alerte arrive.

#!/bin/bash
if ! restic backup /srv/data; then
  curl -H "Priority: urgent" -H "Tags: rotating_light" \
       -d "Sauvegarde restic en échec sur $(hostname)" \
       -H "Authorization: Bearer $NTFY_TOKEN" \
       https://ntfy.exemple.fr/infra-critique
fi

Le complément d’un dispositif existant. ntfy s’insère volontiers en aval d’Alertmanager ou de Grafana, dont il consomme les webhooks via les gabarits intégrés, pour offrir un canal de secours indépendant de la messagerie d’entreprise — utile précisément le jour où c’est la messagerie qui tombe.

Le serveur domestique. C’est le terrain où ntfy est aujourd’hui le plus déployé, et il mérite un traitement à part : voir la section 9.

Face à la concurrence, ntfy occupe un créneau assez net. Gotify est plus simple encore mais sans application iOS ni service public. Apprise est une bibliothèque d’abstraction vers des dizaines de services, pas un serveur — les deux se combinent d’ailleurs très bien. Pushover offre une expérience mobile plus polie mais reste propriétaire et payant, sans auto-hébergement possible. Matrix couvre un besoin beaucoup plus vaste au prix d’une complexité opérationnelle sans commune mesure.


9. Étude de cas : ntfy dans une architecture de serveur domestique

Le homelab est devenu le principal terrain d’adoption de ntfy, et il illustre bien ce que le composant apporte réellement à une architecture. Trois bénéfices s’y dégagent, ainsi qu’un angle mort qu’il faut traiter dès la conception.

9.1 Un point de sortie unique

C’est l’argument structurant. Sans ntfy, chaque service embarque son propre canal de notification : un webhook Discord pour Watchtower, un bot Telegram pour les gestionnaires de médias, un relais SMTP pour les scripts de sauvegarde, l’application compagnon pour la domotique. Quatre configurations, quatre secrets à faire tourner, quatre points de rupture indépendants.

ntfy inverse la dépendance : chaque service ne connaît plus qu’une URL HTTP interne et un jeton. Le changement de téléphone, l’ajout d’un abonné sur le navigateur du bureau, ou l’écriture d’un consommateur qui écoute le flux JSON pour déclencher une action en aval, deviennent des modifications côté abonné uniquement. Aucun émetteur n’est touché. C’est le découplage classique du publication/abonnement, appliqué à une échelle où l’on ne pense généralement pas à l’appliquer.

9.2 Le routage par topic contre la fatigue d’alerte

C’est le problème réel de toute installation domestique un peu fournie : au bout de trois mois, on cesse de regarder les notifications, parce que « conteneur mis à jour » et « le RAID est dégradé » arrivent par le même canal, avec le même son. Le découpage en topics par criticité, associé à une configuration de son par topic dans l’application mobile, restaure la valeur du signal :

Topic Priorité Comportement Contenu
maison-critique 5 Son dédié, contournement du mode « Ne pas déranger » RAID dégradé, onduleur sur batterie, échec de sauvegarde
maison-infra 3 Notification standard Redémarrages, renouvellement de certificats, mises à jour appliquées
maison-bruit 1 Silencieux, consultable a posteriori Téléchargements terminés, tâches planifiées routinières

L’effet pratique est qu’on finit par reconnaître la gravité d’une alerte sans regarder l’écran. Cette hiérarchisation est très difficile à obtenir avec un canal unique de type webhook de messagerie.

9.3 Un coût en ressources négligeable

Un binaire Go, quelques dizaines de mégaoctets de mémoire vive, aucune dépendance à installer. ntfy cohabite sans difficulté avec une dizaine de conteneurs sur un Raspberry Pi ou un mini-PC. Rapporté au service rendu, c’est l’un des meilleurs rapports valeur/ressources qu’on puisse ajouter à une telle installation.

À cela s’ajoutent deux bénéfices dont le poids dépend du profil : le rôle de distributeur UnifiedPush, qui permet de retirer Firebase de la boucle pour les notifications des applications Android compatibles ; et le mécanisme de heartbeat, qui alerte sur l’absence de signal — précisément le cas qu’une supervision naïve laisse passer, celui où une sauvegarde n’a pas échoué mais n’a simplement jamais démarré.

9.4 L’angle mort : ntfy ne peut pas se surveiller lui-même

Un serveur ntfy auto-hébergé ne peut pas notifier la panne de la machine qui l’héberge. Si le serveur tombe, aucune alerte ne part — et le silence est indiscernable du fonctionnement nominal. C’est le piège le plus fréquent de ce type de déploiement.

La parade est simple et doit être posée dès le départ : le heartbeat de la machine hôte doit sortir vers l’extérieur. Une tâche planifiée pousse un signal toutes les quelques minutes vers un service tiers — l’instance publique ntfy.sh sur un topic au nom imprononçable, une instance ntfy amie, ou un service de type dead man’s switch — configuré pour alerter si le signal cesse. Le mainteneur du projet emploie exactement ce montage pour surveiller ntfy.sh : un script publie un message toutes les deux minutes et vérifie qu’il a bien été stocké ; l’échec de cette vérification déclenche une alerte acheminée par une instance ntfy tierce, sur un topic configuré pour sonner jusqu’à acquittement.

9.5 Quand ntfy n’apporte rien

Deux situations où l’ajout n’est pas justifié :

  • Installation de deux ou trois services. Un webhook de messagerie suffit. ntfy commence à payer à partir du moment où le nombre de sources d’alerte dépasse la demi-douzaine, c’est-à-dire quand le coût de maintenance des canaux dispersés devient supérieur au coût d’exploitation d’un service supplémentaire.
  • Home Assistant déjà en place. Son application compagnon assure déjà la notification push, et le recouvrement fonctionnel est réel. L’intérêt de ntfy devient marginal pour la domotique elle-même ; il reste entier pour tout ce qui vit en dehors — sauvegardes, conteneurs, intégration continue personnelle, scripts d’administration.

Enfin, rappelons la contrainte de plateforme décrite en section 5 : sur iPhone, la livraison instantanée depuis une instance auto-hébergée passe malgré tout par un signal de réveil relayé via ntfy.sh puis APNs. Le contenu du message ne quitte pas le réseau local, mais le couplage au service central subsiste. Sur Android, l’auto-hébergement peut être total.


10. Limites à connaître avant de s’engager

Un tableau honnête suppose de nommer les angles morts.

  • Pas de garantie de livraison. Un message publié alors qu’aucun abonné n’est connecté n’est retrouvable que dans la fenêtre du cache, et seulement si le client demande explicitement since=. Pour de l’alerting critique avec chaîne d’escalade et accusé de réception, il faut autre chose.
  • Le couplage iOS. L’auto-hébergement pur reste impossible pour les utilisateurs d’iPhone souhaitant la livraison instantanée, du fait des contraintes d’Apple.
  • Le facteur bus. Le projet repose très largement sur un mainteneur principal, malgré une communauté de contributeurs active. C’est un risque à documenter dans toute analyse de dépendance — atténué par la licence libre, la simplicité du code et la disponibilité du protocole.
  • L’absence de chiffrement de bout en bout, déjà évoquée, ferme la porte à certains contextes réglementés.
  • La montée en charge horizontale n’est pas native : l’état des abonnements vit en mémoire dans un processus. Le service public a longtemps tourné sur un unique nœud, ce qui suffit largement à la plupart des déploiements internes, mais impose de réfléchir avant d’envisager une architecture multi-instances.
  • L’impossibilité de s’auto-surveiller. Une instance ne peut pas signaler sa propre indisponibilité : toute architecture qui en dépend doit prévoir un canal de secours externe (voir section 9.4).

11. Conclusion

ntfy illustre une thèse que l’industrie oublie régulièrement : on peut résoudre un problème réel sans inventer de protocole. En refusant d’ajouter une couche de transport propriétaire, en s’en tenant à GET et POST sur une URL, le projet a obtenu ce que les architectures les plus élaborées peinent souvent à atteindre — une compatibilité universelle et une courbe d’apprentissage nulle. La complexité qu’il a fallu absorber n’est pas la sienne : elle vient des écosystèmes mobiles fermés, et ntfy la contient dans des composants clairement identifiés, que l’on peut choisir d’activer ou non.

Pour l’ingénieur qui cherche à faire remonter un signal d’une machine vers un humain, sans dépendance captive et sans budget, le rapport valeur/effort est difficile à battre. Le prix d’entrée : une commande curl. Le prix de sortie : à peu près le même, ce qui est la meilleure définition possible d’une technologie non captive.


Encadré — Démarrer en cinq minutes

# 1. Choisir un nom de topic difficile à deviner
TOPIC="essai-$(head -c9 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9')"

# 2. S'abonner depuis le navigateur : https://ntfy.sh/$TOPIC
#    ou installer l'application mobile et s'abonner au même nom

# 3. Publier
curl -d "Bonjour depuis $(hostname)" "https://ntfy.sh/$TOPIC"

# 4. Avec des métadonnées
curl -H "Title: Test" -H "Priority: high" -H "Tags: white_check_mark" \
     -d "Ça fonctionne." "https://ntfy.sh/$TOPIC"

Rappel : sur l’instance publique, le nom du topic est le mot de passe. Passez à l’auto-hébergement avec ACL avant tout usage sérieux.


Encadré — Le paramétrage à ne pas rater derrière un proxy

Trois réglages causent l’essentiel des tickets d’assistance en auto-hébergement :

  1. Les timeouts de lecture du proxy doivent être portés à plusieurs heures (ou désactivés) sur les chemins d’abonnement, sinon les connexions longues sont coupées toutes les 60 secondes.
  2. proxy_buffering off (nginx) est nécessaire, faute de quoi les messages du flux JSON restent bloqués dans le tampon du proxy.
  3. behind-proxy: true côté ntfy, associé à la transmission correcte de X-Forwarded-For, sans quoi toutes les limitations de débit s’appliqueront à l’adresse unique du proxy.

Encadré — Le canal de secours d’un serveur domestique

Le principe : la machine qui héberge ntfy doit émettre un signal vers l’extérieur, et c’est l’interruption de ce signal qui déclenche l’alerte.

#!/bin/bash
# /usr/local/bin/watchdog-sortant — à lancer toutes les 5 minutes en cron
# Publie sur l'instance LOCALE, vérifie que le message a bien été stocké,
# puis signale sa bonne santé à un service EXTERNE.

LOCAL="https://ntfy.maison.lan/watchdog"
EXTERNE="https://ntfy.sh/wd-8Kq2mNvR7pLxT4"   # nom long et non devinable

msg="ping-$(date +%s)"
curl -sf -H "Authorization: Bearer $NTFY_TOKEN" -d "$msg" "$LOCAL" >/dev/null || exit 1

# Relecture immédiate depuis le cache : le serveur a-t-il vraiment enregistré ?
curl -sf -H "Authorization: Bearer $NTFY_TOKEN" \
     "$LOCAL/json?poll=1&since=1m" | grep -q "$msg" || exit 1

# Tout va bien : on le fait savoir à l'extérieur.
curl -sf -d "ok $(hostname)" "$EXTERNE" >/dev/null

Il reste à configurer, côté externe, une surveillance de l’absence de signal — le mécanisme de heartbeat de ntfy, ou un service dédié de type dead man’s switch. Sans cette dernière étape, le montage ne sert à rien : c’est le silence qui doit produire du bruit.


Pour aller plus loin

  • Documentation officielle : https://docs.ntfy.sh
  • Code source du serveur : https://github.com/binwiederhier/ntfy
  • Notes de version : https://docs.ntfy.sh/releases/
  • Spécification UnifiedPush : https://unifiedpush.org
  • Billet d’architecture du mainteneur, « 138 lines of code » : https://blog.ntfy.sh

Les informations techniques de cet article ont été vérifiées sur la documentation officielle et les notes de version de juillet 2026 (serveur ntfy v2.26.x). Le projet évoluant rapidement, il est recommandé de confronter les détails de configuration à la documentation en vigueur.

Partager : ✉ Mail X in 🐘
Commentaires

Aucun commentaire pour l'instant. Soyez le premier !

Laisser un commentaire
Un code de vérification sera envoyé à votre adresse email.