Mettre en place la redondance pour Mosquitto
Dans le monde de la domotique, le broker MQTT Mosquitto est devenu un élément central pour faire communiquer nos équipements. Mais que se passe-t-il si votre serveur Mosquitto tombe en panne ? Vos appareils connectés se retrouvent orphelins ! J'ai eu le cas suite à un redémarrage et un fichier corrompu qui empêchait le démarrage de Mosquitto.
Dans ce tutoriel, nous allons mettre en place une solution de haute disponibilité pour Mosquitto en utilisant Keepalived. Le principe est simple : deux serveurs Mosquitto (un en Docker, un en binaire), une IP virtuelle, et un basculement automatique en cas de panne.

Cette approche reste toutefois parfaitement adaptée à un usage domotique ou personnel, où l’objectif principal est d’éviter une indisponibilité prolongée du broker MQTT.
Architecture de la solution
Ma solution repose sur quatre éléments principaux :
- Un conteneur LXC avec Docker hébergeant Mosquitto en conteneur (serveur PRINCIPAL).
- Un Raspberry Pi (qui me sert de unipi) avec Mosquitto en installation native (serveur SECONDAIRE).
- Keepalived installé sur les deux serveurs pour gérer l'IP virtuelle.
- Une IP virtuelle (VIP) : l'adresse IP unique à laquelle se connectent tous vos clients MQTT.
Le fonctionnement est transparent pour vos équipements : ils se connectent toujours à la même IP virtuelle, et en cas de défaillance du serveur principal, le Raspberry Pi prend automatiquement le relais en 2 à 5 secondes (tolérable dans nos installations).
Architecture hybride : Cette configuration combine le meilleur des deux mondes - Docker pour la flexibilité sur le serveur principal, et une installation native sur le Raspberry Pi pour la légèreté et la stabilité.
Dans cet article, je vais utiliser l'adresse IP 192.168.1.100 à adapter selon votre réseau. Cette adresse IP sera virtuelle donc, celle-ci ne remontera pas dans le routeur. Ainsi, si celle-ci ne doit pas faire partie de votre plage DHCP où être attribué à une IP fixe d'un équipement, sinon vous allez tout casser.
Installation sur les systèmes
Sur le serveur LXC Docker, installer keepalived (mosquitto sera vu après en docker).
sudo apt update
sudo apt install keepalived
Sur le Raspberry Pi, installer mosquitto et keepalived
sudo apt update
sudo apt install mosquitto mosquitto-clients keepalived
Vérifiez que Mosquitto est bien installé et démarré :
sudo systemctl status mosquitto
Si le service n'est pas actif, démarrez-le :
sudo systemctl enable mosquitto
sudo systemctl start mosquitto
Installer et configuration de Mosquitto sur le serveur principal (LXC Docker)
Création de la structure Docker
Sur le serveur LXC Docker, créez le dossier du projet :
mkdir -p ~/mosquitto && cd "$_"Créez la structure de dossiers nécessaire :
mkdir -p config data log
Configuration de Mosquitto
Créez le fichier de configuration Mosquitto avec la commande nano config/mosquitto.conf :
# Configuration de base
listener 1883
allow_anonymous false
password_file /mosquitto/config/passwd
# Persistance des données
persistence true
persistence_location /mosquitto/data/
# Logs
log_dest file /mosquitto/log/mosquitto.log
log_dest stdout
log_type all
log_timestamp true
log_timestamp_format %Y-%m-%dT%H:%M:%S
Créez un fichier de mots de passe :
docker run -it --rm -v $(pwd)/config:/mosquitto/config eclipse-mosquitto:latest mosquitto_passwd -c /mosquitto/config/passwd votre_utilisateur
Entrez le mot de passe lorsqu'on vous le demande (Attention, vous en aurez besoin pour le Raspberry Pi).
Création du fichier Docker Compose
Créez le fichier compose.yaml avec la commande nano compose.yaml :
services:
mosquitto:
image: eclipse-mosquitto:latest
container_name: mosquitto
restart: unless-stopped
network_mode: host
volumes:
- ./config:/mosquitto/config
- ./data:/mosquitto/data
- ./log:/mosquitto/log
healthcheck:
test: ["CMD", "mosquitto_sub", "-t", "$$SYS/#", "-C", "1", "-i", "healthcheck", "-W", "3"]
interval: 10s
timeout: 5s
retries: 3
start_period: 10s
Lancez le conteneur :
docker compose up -d
Configuration de Mosquitto sur le serveur secondaire (un Raspberry Pi)
Configuration de Mosquitto
Sur le Raspberry, éditez le fichier de configuration avec la commande sudo nano /etc/mosquitto/mosquitto.conf :
# Configuration de base
listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd
# Persistance des données
persistence true
persistence_location /var/lib/mosquitto/
# Logs
log_dest file /var/log/mosquitto/mosquitto.log
log_type all
log_timestamp true
log_timestamp_format %Y-%m-%dT%H:%M:%S
Créez le même utilisateur et mot de passe que sur le serveur principal :
sudo mosquitto_passwd -c /etc/mosquitto/passwd votre_utilisateur
Important : Utilisez exactement le même nom d'utilisateur et mot de passe que sur le serveur Docker.
Redémarrez Mosquitto pour appliquer les changements :
sudo systemctl restart mosquitto
Vérifiez que le service fonctionne :
sudo systemctl status mosquitto
Script de vérification pour Keepalived
Sur le serveur LXC Docker
Créez un script qui vérifiera si le conteneur Mosquitto est bien actif avec la commande nano /usr/local/bin/check_mosquitto_docker.sh :
#!/bin/bash
# Script de vérification du conteneur Mosquitto
# Vérifier si le conteneur est running et healthy
CONTAINER_STATUS=$(docker inspect --format='{{.State.Status}}' mosquitto 2>/dev/null)
CONTAINER_HEALTH=$(docker inspect --format='{{.State.Health.Status}}' mosquitto 2>/dev/null)
if [ "$CONTAINER_STATUS" = "running" ]; then
# Si healthcheck existe, le vérifier
if [ -n "$CONTAINER_HEALTH" ]; then
if [ "$CONTAINER_HEALTH" = "healthy" ] || [ "$CONTAINER_HEALTH" = "starting" ]; then
exit 0
fi
else
# Pas de healthcheck, on vérifie juste que le conteneur tourne
exit 0
fi
fi
exit 1Rendez le script exécutable :
chmod +x /usr/local/bin/check_mosquitto_docker.sh
Testez le script :
sudo /usr/local/bin/check_mosquitto_docker.sh
echo $?
Le résultat doit être 0 si le conteneur fonctionne correctement.
Sur le Raspberry Pi
Créez un script qui vérifiera si le service Mosquitto est actif avec la commande sudo nano /usr/local/bin/check_mosquitto_native.sh :
#!/bin/bash
# Script de vérification du service Mosquitto natif avec authentification
# Identifiants MQTT
MQTT_USER="votre_utilisateur"
MQTT_PASS="votre_mot_de_passe"
# Vérifier si le processus mosquitto est en cours d'exécution
if systemctl is-active --quiet mosquitto; then
# Vérifier que le broker répond avec authentification
if timeout 2 mosquitto_sub -h localhost -t '$SYS/#' -C 1 -W 2 -u "$MQTT_USER" -P "$MQTT_PASS" >/dev/null 2>&1; then
exit 0
fi
fi
exit 1Rendez le script exécutable :
sudo chmod +x /usr/local/bin/check_mosquitto_native.sh
Testez le script :
sudo /usr/local/bin/check_mosquitto_native.sh
echo $?
Le résultat doit être 0 si Mosquitto fonctionne correctement.
Configuration de Keepalived sur le serveur principal
Sur le serveur LXC Docker, créez le fichier de configuration Keepalived avec la commande nano /etc/keepalived/keepalived.conf :
# Script de vérification du conteneur Mosquitto
vrrp_script check_mosquitto_docker {
script "/usr/local/bin/check_mosquitto_docker.sh"
interval 3
weight 2
fall 2
rise 2
}
# Instance VRRP
vrrp_instance VI_MQTT {
state MASTER
interface eth0 # Adaptez selon votre interface réseau
virtual_router_id 51
priority 101
advert_int 1
authentication {
auth_type PASS
auth_pass Mqtt2024SecurePass
}
virtual_ipaddress {
192.168.1.100/24 # L'IP virtuelle
}
track_script {
check_mosquitto_docker
}
# Notifications
notify_master "/etc/keepalived/notify.sh MASTER"
notify_backup "/etc/keepalived/notify.sh BACKUP"
notify_fault "/etc/keepalived/notify.sh FAULT"
}
Points à adapter :
interface eth0: remplacez par le nom de votre interface réseau (vérifiez avecip a)auth_pass: changez ce mot de passe par quelque chose de sécurisévirtual_ipaddress: adaptez l'IP virtuelle selon votre réseau
Configuration de Keepalived sur le Raspberry Pi
Sur le Raspberry Pi, créez le fichier de configuration Keepalived avec la commande sudo nano /etc/keepalived/keepalived.conf :
# Script de vérification du service Mosquitto natif
vrrp_script check_mosquitto_native {
script "/usr/local/bin/check_mosquitto_native.sh"
interval 3
weight 2
fall 2
rise 2
}
# Instance VRRP
vrrp_instance VI_MQTT {
state BACKUP # Serveur secondaire
interface eth0 # Adaptez selon votre interface (souvent eth0 ou wlan0)
virtual_router_id 51
priority 100 # Priorité plus faible que le MASTER
advert_int 1
authentication {
auth_type PASS
auth_pass Mqtt2024SecurePass # Doit être identique au MASTER
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_mosquitto_native
}
notify_master "/etc/keepalived/notify.sh MASTER"
notify_backup "/etc/keepalived/notify.sh BACKUP"
notify_fault "/etc/keepalived/notify.sh FAULT"
}
Sur un Raspberry Pi, l'interface peut s'appeler eth0 (câble) ou wlan0 (wifi). Vérifiez avec ip a.
Les différences avec le serveur principal sont :
state BACKUPau lieu deMASTERpriority 100au lieu de101- Script de vérification différent (
check_mosquitto_native)
Script de notification
Sur les deux serveurs, créez un script simple de notification pour être informé des changements d'état avec la commande sudo nano /etc/keepalived/notify.sh :
#!/bin/bash
STATE=$1
HOSTNAME=$(hostname)
LOG_FILE="/var/log/keepalived-state.log"
case $STATE in
"MASTER")
echo "$(date '+%Y-%m-%d %H:%M:%S') - [$HOSTNAME] Je suis maintenant MASTER" >> $LOG_FILE
;;
"BACKUP")
echo "$(date '+%Y-%m-%d %H:%M:%S') - [$HOSTNAME] Je suis maintenant BACKUP" >> $LOG_FILE
;;
"FAULT")
echo "$(date '+%Y-%m-%d %H:%M:%S') - [$HOSTNAME] Erreur détectée" >> $LOG_FILE
;;
*)
echo "$(date '+%Y-%m-%d %H:%M:%S') - [$HOSTNAME] État inconnu : $STATE" >> $LOG_FILE
;;
esac
Rendez le script exécutable sur les deux serveurs :
sudo chmod +x /etc/keepalived/notify.sh
Démarrage de Keepalived et vérification du fonctionnement
Sur les deux serveurs, activez et démarrez Keepalived :
sudo systemctl enable keepalived
sudo systemctl start keepalived
Vérifiez le statut :
sudo systemctl status keepalived
Félicitation, tout est en place, mais nous allons quand même contrôler le fonctionnement.
Vérifier l'IP virtuelle
Sur le serveur (principal), vérifiez que l'IP virtuelle est bien active :
ip addr show
Vous devriez voir l'IP virtuelle 192.168.1.100 associée à votre interface réseau.

Sur le Raspberry Pi, vous ne devriez PAS voir l'IP virtuelle (il est en BACKUP) :
ip addr show

Connexion MQTT depuis un autre ordinateur
Depuis un autre ordinateur sur votre réseau, testez la connexion à l'IP virtuelle. Je réalise cela à l'aide de MQTT Explorer. Dans mon cas mon mosquitto principal étant déjà en service avant, je vois bien les messages de celui-ci.


Félicitation, tout doit être en service maintenant. Il vous reste sur l'ensemble de vos équipements à mettre l'adresse IP virtuelle comme adresse de brocker.
Simulation de panne du serveur principal
Arrêtez le conteneur Mosquitto sur le serveur LXC Docker :
docker stop mosquitto
Attendez quelques secondes (maximum 10 secondes avec notre configuration), puis vérifiez sur le Raspberry Pi que l'IP virtuelle a basculé :
ip addr show
L'IP virtuelle devrait à présent être sur le Raspberry Pi.
Consultez les logs pour voir le basculement :
sudo tail -f /var/log/keepalived-state.log
Testez à nouveau la connexion MQTT. Elle devrait toujours fonctionner (vous devrez peut-être vous reconnecter).
Redémarrez le conteneur sur le serveur principal :
docker start mosquitto
L'IP virtuelle devrait automatiquement revenir sur le serveur LXC Docker après quelques secondes (comportement par défaut).

Simulation de panne complète du serveur principal
Pour simuler une panne totale du serveur LXC Docker, arrêtez Keepalived :
sudo systemctl stop keepalived
Le Raspberry Pi devrait prendre le relais en moins de 5 secondes. Vos clients MQTT se reconnecteront automatiquement.
Configuration de vos clients MQTT
Désormais que votre infrastructure est prête, configurez tous vos clients MQTT (Home Assistant, Node-RED, Jeedom, Shelly, etc.) pour se connecter à l'IP virtuelle : 192.168.1.100.
Si vous souhaitez aller encore plus loin dans la redondance, vous pouvez ajouter un 3ᵉ serveur Mosquitto. Cela permet d'améliorer la tolérance aux pannes.
Architecture avec 3 nœuds
Serveur 1 (LXC Docker) → MASTER (priorité 101)
Serveur 2 (Raspberry UniPi) → BACKUP (priorité 100)
Serveur 3 (NAS/VM/Pi) → BACKUP (priorité 99)
Principe de fonctionnement
- En temps normal, le serveur 1 (LXC Docker) gère l'IP virtuelle
- Si le serveur 1 tombe, le serveur 2 (Raspberry) prend le relais
- Si les serveurs 1 et 2 sont tous les deux en panne, le serveur 3 prend le relais
- Dès qu'un serveur de priorité supérieure revient, il reprend la main (comportement par défaut)
Configuration du 3ᵉ nœud
La configuration est identique aux autres serveurs, seuls changent :
- Le
state: toujours enBACKUP - La
priority:99(inférieure aux deux autres) - L'installation : au choix Docker ou natif selon votre matériel
Exemple de configuration Keepalived pour le 3ᵉ nœud :
vrrp_instance VI_MQTT {
state BACKUP
interface eth0
virtual_router_id 51
priority 99 # Priorité la plus basse
advert_int 1
authentication {
auth_type PASS
auth_pass MqttHA2024SecurePass # Identique aux autres
}
virtual_ipaddress {
192.168.1.100/24
}
track_script {
check_mosquitto_xxx # Selon votre installation (docker ou native)
}
}
Utiliser un NAS Synology peut-être possible, mais l'installation de Keepalived peut poser des soucis ou ne pas être persistant donc voilà pourquoi je n'ai pas pris en compte cette option dans mon installation
Pour la plupart des installations domotiques que nous avons, deux nœuds suffisent largement.
Utilisation avancée
Empêcher le retour automatique sur le principal
Si vous ne souhaitez pas que l'IP virtuelle revienne automatiquement sur le serveur principal après une panne, ajoutez cette ligne dans la configuration Keepalived des deux serveurs :
nopreempt
Et changez le state du serveur principal en BACKUP. Avec cette configuration, le serveur qui devient MASTER le reste jusqu'à sa prochaine panne.
Notifications par Telegram
J'ai rajouté un envoi vers Telegram pour connaitre l'état de mon mosquitto et pouvoir le dépanner au besoin. Modifier le script /etc/keepalived/notify.sh pour envoyer des notifications via Telegram, n'oublié pas de personnaliser vos paramètres du bot Telegram et du hostname de votre serveur principal.
#!/bin/bash
STATE=$1
HOSTNAME=$(hostname)
LOG_FILE="/var/log/keepalived-state.log"
# Configuration Telegram
TELEGRAM_BOT_TOKEN="votre_token_bot"
TELEGRAM_CHAT_ID="votre_chat_id"
# Déterminer si c'est le serveur principal ou secondaire
# Adaptez ces noms selon vos serveurs
if [[ "$HOSTNAME" == "lxc-docker" ]] || [[ "$HOSTNAME" == "votre-nom-serveur-principal" ]]; then
IS_PRIMARY=true
else
IS_PRIMARY=false
fi
# Message selon l'état
case $STATE in
"MASTER")
MESSAGE="✅ Mosquitto - Le serveur $HOSTNAME est maintenant ACTIF"
MQTT_STATUS="ACTIVE"
echo "$(date '+%Y-%m-%d %H:%M:%S') - [$HOSTNAME] Je suis maintenant MASTER" >> $LOG_FILE
;;
"BACKUP")
if [ "$IS_PRIMARY" = true ]; then
MESSAGE="🚨 Mosquitto - Le serveur principal $HOSTNAME est EN PANNE"
MQTT_STATUS="FAULT"
else
MESSAGE="⚠️ Mosquitto - Le serveur secondaire $HOSTNAME est en veille"
MQTT_STATUS="STANDBY"
fi
echo "$(date '+%Y-%m-%d %H:%M:%S') - [$HOSTNAME] Je suis maintenant BACKUP" >> $LOG_FILE
;;
"FAULT")
MESSAGE="🚨 Mosquitto - ERREUR CRITIQUE détectée sur le serveur $HOSTNAME"
MQTT_STATUS="ERROR"
echo "$(date '+%Y-%m-%d %H:%M:%S') - [$HOSTNAME] Erreur détectée" >> $LOG_FILE
;;
*)
MESSAGE="❓ Mosquitto - État inconnu sur $HOSTNAME : $STATE"
MQTT_STATUS="UNKNOWN"
echo "$(date '+%Y-%m-%d %H:%M:%S') - [$HOSTNAME] État inconnu : $STATE" >> $LOG_FILE
;;
esac
# Envoi de la notification Telegram
curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \
-d chat_id="$TELEGRAM_CHAT_ID" \
-d text="$MESSAGE" \
-d parse_mode="HTML" > /dev/null 2>&1

État par MQTT
Modifier le script /etc/keepalived/notify.sh pour y ajouter cela sans oublier de modifier les valeurs de connexion de mosquitto.
# Configuration MQTT
MQTT_BROKER="192.168.1.100" # IP virtuelle ou IP d'un autre broker
MQTT_PORT="1883"
MQTT_USER="votre_utilisateur"
MQTT_PASS="votre_mot_de_passe"
MQTT_TOPIC="mosquitto/status"
# Créer un payload JSON pour MQTT
MQTT_PAYLOAD=$(cat <<EOF
{
"hostname":"$HOSTNAME",
"server_type":"$SERVER_TYPE",
"state":"$STATE",
"status":"$MQTT_STATUS",
"timestamp":"$(date '+%Y-%m-%d %H:%M:%S')"
}
EOF
)
# Publication MQTT
mosquitto_pub -h "$MQTT_BROKER" -p "$MQTT_PORT" \
-u "$MQTT_USER" -P "$MQTT_PASS" \
-t "$MQTT_TOPIC/$HOSTNAME" \
-m "$MQTT_PAYLOAD" \
-r # Retained message pour garder le dernier étatInstallation le paquet mosquitto_pub sur le serveur LXC Docker, celui-ci doit déjà être installé sur le Raspberry avec l'installation native de mosquitto.
apt install -y mosquitto-clientsLe script publiera sur mosquitto/status/"hostname" les statuts suivants :
ACTIVE→ Le serveur gère actuellement l'IP virtuelleFAULT→ Le serveur principal est en panneSTANDBY→ Le serveur secondaire est en attenteERROR→ Erreur critique détectée
Intégration dans Jeedom :
- Dans le plugin JMQTT, créez un équipement
- Abonnez-vous au topic
mosquitto/status/# - Utilisez ces infos dans vos scénarios


Intégration dans Home Assistant :
Modifier configuration.yaml pour y ajouter cette ligne
mqtt: !include mosquitto.yamlCréer le fichier mosquitto.yaml dans le même répertoire que configuration.yaml et adapté vos hostname :
sensor:
- name: "Mosquitto Principal"
state_topic: "mosquitto/status/[hostname principal]"
value_template: "{{ value_json.status }}"
json_attributes_topic: "mosquitto/status/[hostname principal]"
json_attributes_template: "{{ value_json | tojson }}"
icon: mdi:server-network
- name: "Mosquitto Secondaire"
state_topic: "mosquitto/status/[hostname secondaire]"
value_template: "{{ value_json.status }}"
json_attributes_topic: "mosquitto/status/[hostname secondaire]"
json_attributes_template: "{{ value_json | tojson }}"
icon: mdi:server-network-off
binary_sensor:
- name: "Mosquitto Principal Actif"
state_topic: "mosquitto/status/[hostname principal]"
value_template: "{{ value_json.status == 'ACTIVE' }}"
payload_on: true
payload_off: false
device_class: connectivity
- name: "Mosquitto Secondaire Actif"
state_topic: "mosquitto/status/[hostname secondaire]"
value_template: "{{ value_json.status == 'ACTIVE' }}"
payload_on: true
payload_off: false
device_class: connectivity


Conclusion
Nous avons mis en place une solution de redondance assez simple pour Mosquitto. Cette solution peut être mise en place pour d'autre service IP. Il est bien sûr possible de partir avec l'installation principale et de simplement ajouter le secondaire et la partie Keepalived donc voici la documentation.
Cette solution est peu gourmande en ressource et peut permettre de maintenir une installation en service pour l'ensemble de la famille et vous permettre de dépanner tranquillement. Cette solution peut être pratique également pour les opérations de maintenance.
N'hésitez pas à partager vos déploiements ou venir chercher de l'aide avec la communauté sur le groupe Telegram ou bien en commentaire !