---
name: ntfy
description: Envoyer des notifications ntfy depuis le VPS : serveur local 127.0.0.1:8080, topic vps-admin, récupération du token à l'exécution (opencode ou root via runuser), options d'envoi (title, tags, priority), pièges (403 sans token, PATH de cron), cas d'usage documentés (SSH/PAM, mise à jour OpenCode).
---

# Alerte ntfy sur le VPS

## Quand charger ce skill

Toute demande d'envoi d'une **notification ntfy** (alerte, rappel, résultat d'une tâche) depuis un script ou une commande du VPS.

## Instance & conventions

| Élément | Valeur |
|---|---|
| Serveur | `http://127.0.0.1:8080` (local — pas de reverse proxy/TLS) |
| Topic par défaut | `vps-admin` (protégé : **token obligatoire**) |
| Binaire serveur | `/var/www/ntfy/ntfy` (absent du PATH) |
| Token (source de vérité) | coffre `pass` → `opencode/ntfy-token` |

Toujours publier sur l'**URL locale** `127.0.0.1:8080` : pas de dépendance au reverse proxy/TLS.

## Récupérer le token — à l'exécution, jamais en dur

Le token se lit **à l'exécution** (jamais en clair dans un script, jamais exporté dans l'environnement — `at` recopie l'environnement en clair).

- **En tant qu'`opencode`** (cron, scripts de l'utilisateur) — `pass` absent du PATH de cron :
  ```bash
  T="$(/var/lib/opencode/.local/bin/pass show opencode/ntfy-token)" || exit 1
  ```
- **En tant que `root`** (scripts `/usr/local/sbin/…`) : root **ne peut pas déchiffrer** le store GPG (clé dans le trousseau d'opencode) → passer par `runuser` :
  ```bash
  T="$(runuser -u opencode -- /var/lib/opencode/.local/bin/pass show opencode/ntfy-token)" || exit 1
  ```

## Envoyer un message

### Message simple
```bash
curl -s -H "Authorization: Bearer $T" \
  -d "VPS : contenu du message" http://127.0.0.1:8080/vps-admin
```

### Message enrichi (titre, tags, priorité)
```bash
curl -s -H "Authorization: Bearer $T" \
  -H "Title: Titre de l'alerte" \
  -H "Tags: warning" \
  -H "Priority: high" \
  -d "corps du message" http://127.0.0.1:8080/vps-admin
```

| Header | Usage | Exemples |
|---|---|---|
| `Title:` | titre de la notification | `Mise à jour OpenCode` |
| `Tags:` | tags ntfy | `warning`, `error`, `ok`, `tada`, `skull`, `rotating_light` |
| `Priority:` | priorité | `min`, `low`, `default`, `high`, `urgent` |
| `Click:` | URL ouverte au clic | — |

## Pièges (leçons apprises)

1. **403 sans token → notification perdue en silence** : le script continue (rc=0) alors que rien n'est parti. Vérifier le token avant envoi, ou le code retour.
2. **PATH absent de cron** : `pass: command not found` → token vide → 403. Toujours le chemin absolu `/var/lib/opencode/.local/bin/pass`.
3. **`seteuid` / root casse l'accès au coffre** : `pam_exec` avec `seteuid` exécute le script en tant qu'utilisateur connecté (accès refusé au store) ; root ne peut pas déchiffrer le store GPG → `runuser -u opencode`.
4. **Ne jamais ralentir/bloquer le processus parent** : dans un hook (PAM, redémarrage de service), envoyer en tâche de fond et `exit 0` systématique — une panne d'alerte ne doit jamais bloquer la connexion ni le service.

## Cas d'usage documentés

- Connexion SSH (PAM + ntfy) : [[04_NOTES/VPS-IA_SSH-Alerte-Ntfy-PAM-2026-10-19]]
- Plan de sécurisation VPS (supervision, item 9c) : [[04_NOTES/OVH/VPS-OVH_Securisation_20261016]]
- Mise à jour OpenCode (succès / échec) : [[04_NOTES/VPS-IA_Installation-OpenCode]]
- Programmer un envoi (cron, oneshot, sentinel, fuseau) : [[80_CONFIG/IA_SKILLS/Planification-Taches]]