Sommaire

Gotify : service de notifications auto-hébergée

Introduction

En consultant mes autres articles, vous constaterez que j’utilise mes services avec des notifications via Telegram. Je fais cela afin de les avoir sur mon téléphone. Je trouve cela plus pratique que d’avoir des e-mails, surtout que ce dernier est un système plutôt lourd pour de simples petits messages.

L’utilisation d’un bot Telegram dans son utilisation me satisfait pleinement. Mais le fait d’utiliser un service tiers pour mes services hébergés m’embête…
J’ai trouvé une solution auto-hebergée (et simple) avec Gotify, un service de notification disponible en Docker.

/img/2020-05-16-gotify-service-de-notifications/gotify-logo.png
Logo de Gotify

Comme le montre l’animal à l’effigie du logo, le serveur est écrit en Go.

Gotify est implémenté avec une API Rest. On pourra donc simplement envoyer des messages par le biais de simples commandes cURL.

Voici un exemple de notifications (Home Assistant) sur Telegram et sur Gotify :

/img/2020-05-16-gotify-service-de-notifications/Screenshot_1.png
Notification Telegram & Gotify

Nous allons donc voir ici comment l’installer (Docker + Apache Reverse Proxy) et comment l’on envoie des notifications pour les applications suivantes :

  • Tests “à la main” via cURL
  • Home Assistant
  • Supervision : Nagios (oui j’utilise encore ce truc) et Grafana
  • Autres intégrations : Script Git et autres (Linux)

Installation

J’ai fait une installation assez simple dans lequel je n’utilise pas de BDD externe (Gotify utilise alors une base SQLite). Pour faire autrement, je vous invite à regarder la documentation officielle.

Pour l’accès en HTTPS, j’utilise avec Apache en reverse-proxy avec un certificat Let’s Encrypt.

Certificat Let’s Encrypt

Cette partie étant déjà couvert ici et ici, je vous mets ici simplement une commande pour l’exemple de ce tutos :

1
sudo certbot certonly -d gotify.mondomaine.mu

Reverse-Proxy (Apache)

Pour le bon fonctionnement du proxy inverse, il faut activer certains modules :

1
2
3
4
sudo a2enmod proxy
sudo a2enmod proxy_wstunnel
sudo a2enmod proxy_http
sudo systemctl restart apache2

J’ai donc créé le fichier de configuration du site (/etc/apache2/sites-available/gotify-rp.conf) de la manière suivante

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<VirtualHost *:80>
    ServerName gotify.mondomaine.mu
    ServerAdmin webmaster@mondomaine.mu

    ErrorLog ${APACHE_LOG_DIR}/gotify-error.log
    CustomLog ${APACHE_LOG_DIR}/gotify-access.log combined

    RewriteEngine on
    RewriteCond %{SERVER_NAME} =gotify.mondomaine.mu
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<VirtualHost *:443>
    ServerName gotify.mondomaine.mu
    ServerAdmin webmaster@mondomaine.mu

    ErrorLog ${APACHE_LOG_DIR}/gotify-error.log
    CustomLog ${APACHE_LOG_DIR}/gotify-access.log combined

    SSLEngine On
    SSLCertificateFile /etc/letsencrypt/live/gotify.mondomaine.mu/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/gotify.mondomaine.mu/privkey.pem

    # https://gotify.net/docs/apache
    Keepalive On

    # The proxy must preserve the host because gotify verifies the host with the origin
    # for WebSocket connections
    ProxyPreserveHost On

    # Proxy web socket requests to /stream
    ProxyPass "/stream" ws://127.0.0.1:5858/stream retry=0 timeout=5

    # Proxy all other requests to /
    ProxyPass "/" http://127.0.0.1:5858/ retry=0 timeout=5

    ProxyPassReverse / http://127.0.0.1:5858/
</VirtualHost>

Pensez à adapter votre URL ainsi que le port d’écoute. Vous l’aurez compris, mon conteneur Gotify sera exposé sur le port 5858. Si vous voulez faire autrement, éditez donc ce fichier ainsi que le Docker Compose de la partie suivante.

On met donc en service cette configuration :

1
2
sudo a2enconf gotify-rp.conf
sudo systemctl reload apache2

Docker

Dans le dossier où je stocke le Docker Compose (/root/docker/gotify), j’ai crée un fichier (.env) contenant la variable d’environnement qui correspond au mot de passe du compte admin.

Voici des commandes pour faire cela automatiquement :

1
2
3
4
sudo -i
mkdir -p /root/docker/gotify/data && cd /root/docker/gotify
echo -e "GOTIFY_DEFAULTUSER_PASS=$(pwgen -B 64 1)" > .env
mkdir -p /var/gotify/data

Le fichier docker-compose.yml :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
version: "3"

services:
  app:
    image: gotify/server
    container_name: gotify
    restart: always
    ports:
      - 127.0.0.1:5858:80
    env_file:
      - .env
    volumes:
      - "/var/gotify/data:/app/data"

Il vous faut donc créer le dossier pour les données mais si vous avez effectué les commandes bash du dessus c’est déjà fait 😉.

On “up” donc notre définition (docker-compose up -d) et on se rend sur l’adresse définie dans notre reverse-proxy :
https://gotify.mondomaine.mu

Configuration

Serveur

Une fois connecter avec votre mot de passe, on créé des tokens pour nos différentes applications. Pour cela, on va dans l’onglet “APPS” et l’on clique sur “CREATE APPLICATION". En plus du nom, on peut ajouter une description. Une fois l’entrée validée, on peut uploader une image en cliquant sur l’icône représentant un nuage pour plus de visibilité.

Pour révéler le token de l’application, il suffit de cliquer sur l’œil.
Dans la suite de l’article, je prendrais Az3rTy comme exemple de token.
Prenez soin d’utiliser celui propre à chaque “APPS” pour vos configurations.

Clients

Tests cURL

On effectue donc un test en reprenant l’un des exemples ci-dessous.

En utilisant le système de formulaire HTTP de cURL :

1
2
3
4
curl "https://gotify.mondomaine.mu/message?token=Az3rTy" \
     -F "title=Test 1" \
     -F "message=Salut 🌍" \
     -F "priority=5"
1
2
3
4
5
curl "https://gotify.mondomaine.mu/message" \
     -H "X-Gotify-Key: Az3rTy" \
     -F "title=Test 1" \
     -F "message=Salut 🌍" \
     -F "priority=5"

En utilisant le format JSON :

1
2
3
4
curl "https://gotify.mondomaine.mu/message?token=Az3rTy" \
     --header "Content-Type: application/json" \
     --request POST \
     --data '{"title":"Test 1","message":"Salut 🌍","priority":5}'

Remplacez bien l’URL ainsi que le token par les vôtres.

Pour connaitre toute l’étendue des possibilités, vous trouverez ici le lien de la documentation officielle de l’API REST écrit avec le framework Swagger.

Home Assistant

Il n’y a pas d’intégration “Gotify” sur Home Assistant mais on s’en tire sans soucis avec la plateforme de notification REST.

Voici donc la section à ajouter à votre fichier configuration.yaml :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
notify:
  - name: gotify_admin
    platform: rest
    resource: https://gotify.mondomaine.mu/message
    method: POST_JSON
    headers: 
      X-Gotify-Key: Az3rTy
    message_param_name: message
    title_param_name: title
    data:
      priority: 10

Ceci est la méthode la plus simple, moi je fais autrement.

Ma façon de faire
  • configuration.yaml :
1
2
# Notifications
notify: !include notify.yaml
  • secrets.yaml :
1
2
# Gotify (Notification)
gotify_token: Az3rTy
  • notify.yaml :
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Gotify
- name: gotify_admin
  platform: rest
  resource: https://gotify.mondomaine.mu/message
  method: POST_JSON
  headers: 
    X-Gotify-Key: !secret gotify_token
  message_param_name: message
  title_param_name: title
  data:
    priority: 10

Ensuite, après avoir vérifier la configuration et redémarrer HA, on va dans l’onglet “Outils de développement” et on test notre service de la manière suivante :

/img/2020-05-16-gotify-service-de-notifications/Screenshot_2.png
Test notification HA

Pour CTRL+C + CTRL+V :

1
2
title: "Test 2"
message: "Etat Soleil : {{ states('sun.sun') }}"

Avec ce test, vous êtes censé recevoir la position du soleil (à savoir au-dessus ou en dessous de l’horizon).

Vous pouvez donc configurer vos notifications HA avec Gotify !

Bonus : Script de MAJ d’HA !

Supervision

Nagios

Pour les notifications Nagios, j’ai écrit un script Bash disponible sur mon Github. La procédure de mise en place est décrite sur la page, je ne vais donc pas la réécrire ici.

Grafana

Pour les alertes de Grafana, il suffit de choisir le type “webhook” et de mettre l’URL contenant le token :
https://gotify.mondomaine.mu/message?token=Az3rTy

/img/2020-05-16-gotify-service-de-notifications/Screenshot_3.png
Configuration des alertes Grafana

Ça ne sert à rien d’activer les images car elles ne sont pas prises en charge par Gotify. Enfin pour être plus précis, la manière dont Grafana envoie les images ne correspond pas à la méthode de Gotify.

Divers

Git

Mon NAS (Synology) a aussi le rôle de serveur Git. Afin de m’assurer que le git push est bien arrivé, j’ai fait un script hook/post-receive qui envoie une notification pour le dépôt mis à jour.

Le script en question :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/bin/bash
export LANG=en_US.UTF-8

# Gotify credential
url="https://gotify.mondomaine.mu"
token="Az3rTy"

# Get git directory name
git_repo=$(dirname $(pwd))    # Parent dirname
git_repo=${git_repo##*/}      # Remove absolut path
git_repo=${git_repo//.git/}   # Remove '.git' extension

# Processing notification content
## Title
title="🆙 "
title+="Git Push"

## Message
message="$git_repo updated"

# Finally cURLing !
curl_http_result=$(curl "${url}/message?token=${token}" -F "title=${title}" -F "message=${message}" -F "priority=8" --output /dev/null --silent --write-out %{http_code})
if [[ $? -ne 0 ]]; then
  echo "FATAL ERROR: cURL command failed !"
  exit 1
fi

# Check HTTP return code ("200" is OK)
if [[ $curl_http_result -ne 200 ]]; then
  echo -e "FATAL ERROR: API call failed ! Return code is $curl_http_result instead of 200."
  exit 2
fi

exit 0

Pour récupérer le nom du dépôt, ce script prend le nom du dossier parent au dossier où est le script (hook) et enlève l’extension “.git” de ce dernier (qui est donc le nom du dossier représentant le dépôt).

Unattended upgrades

Mes serveurs sous Ubuntu utilisent unattended-upgrades pour effectuer les MAJs de sécurités automatiquement. Le système de notification ne fonctionne que par e-mail, donc pour être notifié par Telegram et maintenant Gotify, j’avais fait un script que j’ai mis à jour pour fonctionner avec Gotify :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/bash

# Send Gotify notifications about
# ubuntu pending updates

# Gotify credential
url="https://gotify.mondomaine.mu"
token="Az3rTy"

# Server info
server_name=$(uname -n)
updates_available=$(cat /var/lib/update-notifier/updates-available | awk NF)
release=$(lsb_release -d | cut -d$'\t' -f2)


# Processing notification content
## Title
title="$server_name ($release)"

## Message
message="$updates_available"

# Finally cURLing !
curl_http_result=$(curl "${url}/message?token=${token}" -F "title=${title}" -F "message=${message}" -F "priority=5" --output /dev/null --silent --write-out %{http_code})
if [[ $? -ne 0 ]]; then
  echo "FATAL ERROR: cURL command failed !"
  exit 1
fi

# Check HTTP return code ("200" is OK)
if [[ $curl_http_result -ne 200 ]]; then
  echo -e "FATAL ERROR: API call failed ! Return code is $curl_http_result instead of 200."
  exit 2
fi

exit 0

Le crontab associé (tous les matins à 8h) :

1
0 8 * * * /usr/local/sbin/my-unattended-upgrades-notify.sh

Échecs et limites

Je n’ai pas réussi à contourner le système de notifications par SMS de mon NAS Synology pour Gotify (ça fonctionne pour Telegram 😒).

Vous pouvez voir la configuration que j’ai testée (qui fonctionne en ligne de commande mais pas sur DSM) ci-dessous :

Captures d'écran

Gotify ne permet pas de transmettre de fichiers (il est apparemment possible de faire pour des images). C’est un peu comme un serveur MQTT pour utilisateur. Du coup, mes scripts de backups dont je parle ici me demande un peu plus de travail pour les adapter.

Conclusion

J’ai trouvé en Gotify une solution efficace pour remplacer Telegram. De mon ressenti, ce système de notification est plus rapide que le bot Telegram.

La solution est simple à utiliser à gros coup de cURL. Il existe aussi une application en CLI que je n’ai pas testé vu que je me débrouille pour le push des messages. Elle semble avoir son intérêt pour le mode “watch” mais une fois de plus, je n’ai pas poussé mon analyse plus loin.