Mise en place de Ntfy : un point d'entrée unique pour toutes vos notifications

Alertes éparpillées entre mails, Telegram et applis dédiées ? Un serveur Ntfy auto-hébergé réunit tout et vous laisse décider de leur destination.

Mise en place de Ntfy : un point d'entrée unique pour toutes vos notifications

Un backup qui se termine, un conteneur qui redémarre en boucle, une impression 3D finie pendant que vous êtes au bureau, un capteur qui dépasse son seuil. Chaque service sait vous prévenir, mais chacun à sa façon : un mail ici, un bot Telegram là, une appli dédiée pour un autre. Résultat, les alertes sont éparpillées, les mails importants se noient dans la boîte de réception, et on finit par ne plus rien regarder.

C’est surtout vrai dans un homelab, où les sources se multiplient au fil des installations (Proxmox, Uptime Kuma, Docker, scripts maison). Mais la domotique et les objets connectés posent exactement le même problème.

L’idée est simple : un seul point d’entrée pour envoyer, et vous décidez où ça sonne. Ntfy fait ça en auto-hébergé, et côté source, une requête HTTP suffit. Ça le rend utilisable depuis à peu près tout, d’un script cron à Home Assistant.


Présentation de Ntfy

Ntfy (prononcez « notify ») est un service de notifications qui fonctionne par simples requêtes HTTP. Vous envoyez un message depuis un script, une automatisation ou n’importe quel outil capable de faire une requête, et il arrive sur votre téléphone, dans votre navigateur ou par mail. C’est un logiciel libre, et il existe aussi bien en application qu’en serveur à installer chez soi.

ntfy.sh | Push notifications to your phone or desktop via PUT/POST
ntfy is a simple HTTP-based pub-sub notification service. It allows you to send notifications to your phone or desktop via scripts from any computer, and/or using a REST API.
GitHub - binwiederhier/ntfy: Send push notifications to your phone or desktop using PUT/POST
Send push notifications to your phone or desktop using PUT/POST - binwiederhier/ntfy

Le fonctionnement repose sur les topics, des sortes de fils de discussion à sens unique. Une source publie un message dans un topic, et tous les appareils abonnés à ce topic le reçoivent. Vous pouvez donc avoir un topic sauvegardes, un autre domotique, et décider pour chacun où il doit sonner.

Il existe un serveur public, ntfy.sh, parfait pour essayer : on installe l’appli, on s’abonne à un topic, et c’est prêt. Mais sur ce serveur, un topic est accessible à quiconque en connaît le nom. Il faut donc choisir un nom compliqué si vous voulez un minimum de discrétion, et ce n’est clairement pas fait pour des alertes d’infrastructure. C’est pour ça qu’on va installer notre propre instance : vos données et vos accès restent chez vous.

Au-delà du message simple, Ntfy sait aussi joindre un fichier ou une image, envoyer une copie par mail, jouer des sons différents ou ajouter des emojis. Si vous avez déjà utilisé Gotify, c’est le même genre de service, avec davantage de possibilités.


Installation

Ntfy démarre en 2 minutes avec la configuration par défaut, mais cette version-là ne vous servira pas longtemps : accès ouvert à tout le monde, pas de notifications navigateur en arrière-plan, historique perdu au redémarrage. On part directement sur une configuration complète et pérenne.

Ntfy doit être servi en HTTPS, avec un certificat valide : les notifications navigateur en arrière-plan ne fonctionnent pas sans. Prenez un sous-domaine dédié, du type ntfy.mondomaine.fr.

Créez un dossier pour Ntfy sur votre serveur ou utilisez votre gestionnaire de conteneurs préféré (Dockge-enhanced pour ma part) et collez-y le contenu suivant en tant que fichier compose.yaml :

services:
  ntfy:
    image: binwiederhier/ntfy
    container_name: ntfy
    restart: unless-stopped
    command: serve
    environment:
      NTFY_BASE_URL: https://ntfy.mondomaine.fr
      NTFY_BEHIND_PROXY: true
      NTFY_CACHE_FILE: /var/lib/ntfy/cache.db
      NTFY_AUTH_FILE: /var/lib/ntfy/auth.db
      NTFY_AUTH_DEFAULT_ACCESS: deny-all
      NTFY_ENABLE_LOGIN: true
      NTFY_ATTACHMENT_CACHE_DIR: /var/lib/ntfy/attachments
      NTFY_ATTACHMENT_FILE_SIZE_LIMIT: 100M
      NTFY_WEB_PUSH_PUBLIC_KEY: <Copiez ici la clé publique générée>
      NTFY_WEB_PUSH_PRIVATE_KEY: <Copiez ici la clé privée générée>
      NTFY_WEB_PUSH_FILE: /var/lib/ntfy/webpush.db
      NTFY_WEB_PUSH_EMAIL_ADDRESS: <Renseignez votre adresse mail>
      NTFY_UPSTREAM_BASE_URL: https://ntfy.sh # Uniquement pour les appareils iOS, à supprimer sinon
      TZ: Europe/Paris
    volumes:
      - ./data:/var/lib/ntfy
    ports:
      - 2586:80

Quelques explications sur les variables :

  • NTFY_BEHIND_PROXY : sans lui, Ntfy voit toutes les requêtes comme venant de l’IP de votre proxy et applique ses limites de débit à un seul « visiteur ». Résultat : vos propres alertes peuvent se retrouver bridées. Avec ce paramètre, Ntfy lit l’adresse réelle dans l’en-tête X-Forwarded-For.
  • NTFY_CACHE_FILE : par défaut, l’historique ne vit qu’en mémoire (12 heures) et disparaît au redémarrage. Avec un fichier cache défini, un téléphone qui a perdu sa connexion retrouve les messages manqués.
  • NTFY_AUTH_DEFAULT_ACCESS : deny-all : c’est ce qui transforme l’instance en instance privée. Dès le premier lancement, personne ne peut lire ni écrire.
  • NTFY_ATTACHMENT_FILE_SIZE_LIMIT : par défaut, les pièces jointes sont limitées à 15 Mo par fichier et les fichiers sont supprimés au bout de 3 heures.
  • NTFY_UPSTREAM_BASE_URL : si vous avez des appareils iOS, Apple limite le travail en arrière-plan, donc Ntfy ne peut pas pousser les notifications instantanément tout seul. Il faut ajouter cette ligne qui prévient le serveur public ntfy.sh qu’un message est arrivé. Le contenu de vos messages ne part pas chez eux : ils ne reçoivent que l’identifiant du message et une empreinte de l’URL du topic, l’appli va ensuite chercher le vrai message sur votre serveur. Sans cette ligne, les notifications finissent par arriver, mais avec un délai qui peut aller jusqu’à plusieurs heures. Si vous n’avez aucun appareil iOS, retirez-la : elle ne sert à rien pour Android ni pour le navigateur.

Côté reverse proxy, créez un Proxy Host dans Nginx Proxy Manager comme d’habitude : votre sous-domaine, schéma http, l’IP de la machine Docker et le port défini dans votre compose. Activez le support Websockets, dont Ntfy dépend, puis demandez un certificat dans l’onglet SSL et cochez "Force SSL". Dans l’onglet de configuration avancée, ajoutez :

# Pas de mise en mémoire tampon : les messages doivent arriver tout de suite
proxy_buffering off;
proxy_request_buffering off;

# Les connexions des clients restent ouvertes longtemps
proxy_connect_timeout 3m;
proxy_send_timeout 3m;
proxy_read_timeout 3m;

# Pas de limite de taille, pour les pièces jointes
client_max_body_size 0;

Pour que les navigateurs reçoivent les notifications même quand l’onglet est fermé, Ntfy utilise Web Push. Il faut donc générer une paire de clés. Cette opération est à réaliser une seule fois :

docker exec -it ntfy ntfy webpush keys

Reportez les 2 clés générées dans le fichier compose.yaml et relancez la stack avec la nouvelle configuration :

docker compose up -d
⚠️
Ne changez plus ces clés par la suite : le navigateur n’accepte qu’une identité de serveur par origine, et un changement vous obligerait à réinitialiser les autorisations de notifications. Gardez aussi le fichier webpush.db (il est dans ./data), il contient les abonnements des navigateurs.

Pour vérifier que tout fonctionne, ouvrez sur votre navigateur préféré l'adresse https://ntfy.mondomaine.fr. L’interface s’affiche, mais l’accès est fermé et c’est normal. Le compte administrateur, on le crée dans la partie suivante.


Sécuriser l’instance

Avec deny-all, personne n’a accès, vous y compris. On commence donc par créer un compte avec les droits administrateur :

docker exec -it ntfy ntfy user add --role=admin admin

Vous pouvez maintenant vous connecter à l’interface web et vous abonner à un premier topic test. Ouvrez le menu avec les 3 points et choisissez "Envoyer une notification de test". Si elle s’affiche bien, le proxy, les WebSockets et l’authentification fonctionnent.

Évitez de mettre ce compte dans vos scripts : un token donne accès à tout le compte auquel il appartient, et les tokens à droits limités n’existent pas encore. Créez plutôt un compte par usage, avec juste les droits nécessaires, puis un token :

# Compte dédié au script de sauvegarde, autorisé à écrire (et seulement écrire) sur le topic "sauvegardes"
docker exec -it ntfy ntfy user add sauvegardes
docker exec -it ntfy ntfy access sauvegardes sauvegardes write-only

# Token pour ce compte : notez-le, il commence par tk_
docker exec -it ntfy ntfy token add --label="script sauvegardes" sauvegardes

Les droits possibles sont rw ou read-write (lecture et écriture), ro ou read-only (lecture seule), wo ou write-only (écriture seule) et deny. Le nom du topic accepte un astérisque, par exemple domotique-*. Pour consulter ou révoquer les tokens, ntfy token list et ntfy token remove font le travail.

Testez depuis n’importe quelle machine :

curl -i -d "Test sans token" https://ntfy.mondomaine.fr/sauvegardes

Sans token : refusé, c'est le résultat attendu.

curl -H "Authorization: Bearer tk_valeur_du_token" \
     -H "Title: Sauvegarde terminée" \
     -d "Backup Proxmox OK" \
     https://ntfy.mondomaine.fr/sauvegardes

Avec le token : la notification doit arriver.


Recevoir les notifications

Le serveur tourne, il reste à décider où les alertes atterrissent. Je m’en tiens ici au téléphone et au navigateur, qui couvrent la plupart des besoins. Ntfy sait aussi relayer par e-mail, et il existe des clients pour le poste de travail, en ligne de commande ou via des projets communautaires. Je ne les détaille pas, la documentation officielle et la page des intégrations vous mèneront plus loin.

Sur Android, installez l’application depuis Google Play, F-Droid ou GitHub. Appuyez sur le bouton +, activez l’option pour utiliser un autre serveur, puis saisissez l’adresse de votre instance, le topic et les identifiants d’un compte autorisé à le lire. Avec une instance auto-hébergée, Firebase n’intervient pas : l’appli garde une connexion ouverte vers votre serveur, d’où la notification permanente. Android crée aussi un canal par priorité, ce qui permet de régler un son différent, ou de passer outre Ne pas déranger, pour les alertes urgentes seulement.

Sur iOS, l’ordre des étapes compte. Définissez d’abord votre instance comme serveur par défaut dans les réglages de l’appli, avec l’URL exacte de NTFY_BASE_URL, puis abonnez-vous aux topics. Si les notifications arrivent avec « New message » et rien d’autre, l’iPhone n’arrive pas à joindre votre serveur : revérifiez l’URL.

Dans un navigateur, ouvrez l’adresse de votre instance, connectez-vous, abonnez-vous au topic et autorisez les notifications. Activez les notifications en arrière-plan dans les réglages pour les recevoir sans onglet ouvert : elles reposent sur la configuration Web Push du compose. Vous pouvez aussi installer l’appli web (PWA) avec le bouton « Installer » de Chrome, ou « Ajouter au Dock » et « Sur l’écran d’accueil » dans Safari (macOS 14 et iOS 16.4 minimum). Vous obtenez une fenêtre dédiée, une icône et un badge de messages non lus. Sur ordinateur, le navigateur ou l’appli doit rester lancé.


Côté sources : brancher les services

Ntfy se contente d’une requête HTTP, donc à peu près tout peut lui envoyer un message. Vous croiserez trois cas : l’outil gère Ntfy nativement, il sait appeler un webhook, ou vous passez par un script. Pour chaque source, utilisez un compte dédié avec son token, comme vu dans la partie sécurité, en ne lui donnant que les droits dont elle a besoin.

Scripts et tâches cron

C’est le cas le plus simple : on chaîne la requête à la commande, et le message dépend du résultat.

# Sauvegarde, puis notification selon le résultat
rsync -a /donnees/ /sauvegardes/ \
  && curl -H "Authorization: Bearer tk_valeur_du_token" \
          -H "Priority: low" \
          -d "Sauvegarde terminée" \
          https://ntfy.mondomaine.fr/sauvegardes \
  || curl -H "Authorization: Bearer tk_valeur_du_token" \
          -H "Priority: high" \
          -H "Tags: warning" \
          -d "Sauvegarde en échec" \
          https://ntfy.mondomaine.fr/sauvegardes

Le succès passe en priorité basse, l’échec en priorité haute avec une icône d’avertissement. Vous aurez ainsi l’un sans bruit et l’autre qui sonne.

Uptime Kuma

Uptime Kuma gère Ntfy nativement. Dans les réglages, ouvrez Notifications, configurez une nouvelle notification et choisissez le type ntfy.

  1. Renseignez l’adresse de votre instance, sans le topic, puis le nom du topic.
  2. Fixez la priorité. Un second champ permet de régler à part celle des alertes DOWN.
  3. Dans la méthode d’authentification, choisissez Access Token et collez le token du compte.
  4. Testez, puis rattachez la notification aux moniteurs voulus.

Proxmox

Proxmox n’a pas de cible Ntfy toute faite, mais ses cibles de type webhook font le travail. Tout se passe dans Datacenter, Notifications.

  1. Ajoutez une cible Webhook avec la méthode POST et l’URL https://ntfy.mondomaine.fr/{{ secrets.channel }}.
  2. Ajoutez deux en-têtes : Markdown: Yes et Authorization: Bearer {{ secrets.token }}.
  3. Mettez {{ message }} dans le corps. L’exemple de la doc Proxmox l’entoure de triples accents graves pour un rendu en bloc de code.
  4. Déclarez deux secrets : channel avec le nom du topic, et token avec la valeur du token. Ils sont stockés dans un fichier lisible uniquement par root.
  5. Créez une règle (matcher) qui envoie vers cette cible. Une règle sur la sévérité error suffit pour ne remonter que les échecs de sauvegarde et les incidents de cluster.

Home Assistant

Home Assistant a une intégration officielle depuis la version 2025.5. Dans Paramètres, Appareils et services, ajoutez l’intégration ntfy, indiquez l’adresse de votre instance et les identifiants d’un compte : Home Assistant génère lui-même un token d’accès. Ajoutez ensuite un topic, ce qui crée une entité de notification.

# Action à placer dans une automatisation
action: notify.send_message
data:
  message: "Porte du garage ouverte depuis 10 minutes"
target:
  # Entité créée pour le topic domotique, nom à adapter
  entity_id: notify.domotique

Pour la priorité, les tags, un lien ou une pièce jointe, l’action ntfy.publish expose ces options. Le compte utilisé doit avoir accès au topic.

Et le reste

Radarr, Prowlarr et Sonarr (en version 4) proposent Ntfy directement dans Paramètres, Connexions. Pour le reste, la page des intégrations et la page d’exemples de la doc recensent des dizaines d’outils, de Gatus à changedetection.io en passant par Healthchecks.


Organiser ses topics

Au bout de quelques semaines, un piège guette : tout envoyer dans un seul topic. L’alerte qui compte se noie entre une sauvegarde réussie et une mise à jour d’image. Deux leviers règlent ça : le topic décide où le message arrive et qui a le droit de l’écrire ou de le lire, la priorité décide du bruit qu’il fait.

Nommer ses topics

Un topic correspond plutôt à un usage qu’à une source : sauvegardes, domotique, alertes-critiques. Uptime Kuma et Proxmox peuvent très bien écrire dans le même alertes-critiques. Les noms acceptent les lettres, les chiffres, les tirets et les soulignés, 64 caractères au maximum, sans accents. Sur votre propre instance, le nom n’a plus besoin d’être alambiqué : ce sont les droits d’accès qui protègent. Pensez aussi aux préfixes (domotique-garage, domotique-chauffage), qui se règlent d’un coup avec un joker comme domotique-*.

Priorités

Il y a cinq niveaux, de 1 (min) à 5 (urgent). Le niveau 3 est celui par défaut, avec son et vibration. Les niveaux 4 et 5 ajoutent une fenêtre qui s’affiche par-dessus tout, avec des vibrations plus longues pour le 5. Les niveaux 1 et 2 ne font ni son ni vibration, et le 1 se range sous « Autres notifications ». Comme vu plus haut, Android crée un canal par priorité : c’est là que vous réglez le son ou le passage outre Ne pas déranger.

Un message lisible d’un coup d’œil

Par défaut, le titre est l’adresse du topic, ce qui ne dit pas grand-chose. L’en-tête Title règle ça. Les tags se transforment en emoji quand ils correspondent à un nom connu (warning, rotating_light, heavy_check_mark…). Les autres s’affichent sous le message, ce qui est pratique pour y mettre un nom de machine. Click ouvre une adresse au toucher de la notification, et Icon affiche une icône (JPEG ou PNG).

# Alerte complète : titre, priorité, tags et lien cliquable
curl -H "Authorization: Bearer tk_valeur_du_token" \
     -H "Title: Mouvement détecté dans le garage" \
     -H "Priority: high" \
     -H "Tags: rotating_light,garage" \
     -H "Click: https://ha.mondomaine.fr/lovelace/securite" \
     -d "Détection à 14h32" \
     https://ntfy.mondomaine.fr/domotique

Si les accents du titre s’affichent en points d’interrogation, c’est votre client HTTP qui les gère mal dans les en-têtes. La doc propose alors un encodage alternatif (RFC 2047).

Pièces jointes et envoi différé

Vous pouvez joindre une image ou un fichier de deux façons : envoyer le fichier lui-même, ou donner l’adresse d’un fichier déjà hébergé avec Attach. La limite de taille est celle de la variable NTFY_ATTACHMENT_FILE_SIZE_LIMIT du compose.

# Envoi d'une image locale en pièce jointe
curl -H "Authorization: Bearer tk_valeur_du_token" \
     -H "Filename: garage.jpg" \
     -T garage.jpg \
     https://ntfy.mondomaine.fr/domotique

L’envoi différé se règle avec In (In: 30min) ou At (At: tomorrow, 8am). Le délai va de 10 secondes à 3 jours, et il demande que le cache soit actif, ce qui est le cas avec NTFY_CACHE_FILE.

Pour aller plus loin (boutons d’action, Markdown, modèles de message pour les webhooks), la page de publication de la doc fait le tour.


Conclusion

Ntfy tourne chez moi depuis quelques semaines, et je suis convaincu. Il fait exactement ce qu’on lui demande : recevoir des notifications de n’importe quelle source, simplement, et les centraliser au même endroit. Fini les alertes éparpillées entre mails, bot Telegram et applis dédiées.

Et vous, qu’avez-vous branché sur votre instance ? Racontez-le en commentaires, ou sur la communauté Telegram.