SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-07

Installer Listmonk sur un VPS Ubuntu 24.04

Installez Listmonk v6.2.0 avec PostgreSQL 16, systemd et TLS sur Ubuntu 24.04, puis configurez SMTP et évaluez le vrai coût de délivrabilité.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, July 30, 2026.

Ce dont une newsletter auto-hébergée avec Listmonk a besoin

Listmonk est un gestionnaire auto-hébergé de newsletters et de listes de diffusion : un binaire Go, une base de données PostgreSQL, un fichier de configuration et une unité systemd. Un petit VPS l’exécute sans difficulté, car Listmonk stocke les abonnés et met les campagnes en file d’attente, mais n’envoie jamais les e-mails lui-même. Il transmet chaque message à un serveur SMTP (simple mail transfer protocol). Votre taux de distribution dépend donc de la réputation de ce serveur, et non de ce logiciel.

Ce guide installe Listmonk v6.2.0, la version actuelle en juillet 2026, sur Ubuntu 24.04. Vous avez besoin d’un VPS avec une adresse IP publique, d’un nom de domaine que vous contrôlez et de PostgreSQL 12 ou version ultérieure. L’installation prend environ une heure. La réputation d’envoi se construit sur plusieurs semaines. Cette partie est traitée vers la fin du guide.

Installer PostgreSQL et créer la base de données

Ubuntu 24.04 fournit PostgreSQL 16 dans son propre dépôt, une version largement supérieure à celle requise par Listmonk.

sudo apt update
sudo apt install -y postgresql curl
sudo systemctl enable --now postgresql

Créez le rôle et la base de données dans une seule session psql. -v ON_ERROR_STOP=1 force psql à quitter à la première instruction en échec. Une faute de frappe ne laisse donc pas une configuration partiellement créée qui semble terminée.

sudo -u postgres psql -v ON_ERROR_STOP=1 <<'SQL'
CREATE USER listmonk WITH PASSWORD 'pick-a-long-random-password';
CREATE DATABASE listmonk OWNER listmonk;
SQL

OWNER listmonk n’est pas décoratif. L’installation du schéma crée des tables, des types, des index et des fonctions. Le rôle doit donc posséder la base de données. Si vous indiquez à Listmonk une base appartenant à un autre rôle, l’installation s’arrête avec permission denied, même après avoir exécuté GRANT CONNECT.

Vérifiez que la base de données existe avant de continuer.

sudo -u postgres psql -tAc "SELECT datname FROM pg_database WHERE datname='listmonk';"

Cette commande affiche listmonk. Une ligne vide signifie que l’instruction CREATE n’a jamais été exécutée. Relisez donc la sortie de psql.

Installer le binaire Listmonk

Listmonk publie un binaire statique pour chaque architecture. Vérifiez d’abord la vôtre, car un binaire amd64 sur un VPS ARM est un fichier que le noyau refuse d’exécuter.

dpkg --print-architecture
cd /tmp
curl -fsSLO https://github.com/knadh/listmonk/releases/download/v6.2.0/listmonk_6.2.0_linux_amd64.tar.gz
tar -xzf listmonk_6.2.0_linux_amd64.tar.gz
sudo install -m 755 listmonk /usr/bin/listmonk
listmonk --version

Sur un VPS ARM, remplacez amd64 par arm64 dans le nom du fichier. listmonk --version afficher une chaîne de version est votre première vérification que le binaire correspond à la machine.

Générez config.toml et limitez son accès

--new-config écrit config.toml dans le répertoire de travail courant. C’est pourquoi cd se trouve dans sh -c, et non avant sudo.

sudo install -d -m 750 /etc/listmonk
sudo sh -c 'cd /etc/listmonk && listmonk --new-config'

Le fichier généré est court. Sous [app], address = "localhost:9000" lie le serveur HTTP à l’interface loopback uniquement. Le panneau d’administration n’est donc pas accessible depuis Internet tant que vous n’avez pas placé un reverse proxy devant lui. Ne modifiez pas cette ligne. Sous [db], vous trouverez host = "localhost", port = 5432, user = "listmonk", database = "listmonk" et ssl_mode = "disable". Ces valeurs par défaut correspondent déjà à la base de données que vous avez créée. Vous devez uniquement modifier le mot de passe.

ssl_mode = "disable" est correct tant que Postgres écoute sur l’interface loopback de la même machine, car ce trafic ne quitte jamais la machine. Si vous déplacez la base de données vers un autre hôte, définissez-le sur require. Sinon, le mot de passe circule sur le réseau en clair.

Modifiez la ligne du mot de passe sous [db] pour qu’elle corresponde au rôle, puis créez le compte de service et retirez le fichier à tous les autres comptes de connexion.

sudo useradd --system --home-dir /var/lib/listmonk --create-home --shell /usr/sbin/nologin listmonk
sudo chown -R root:listmonk /etc/listmonk
sudo chmod 640 /etc/listmonk/config.toml

Le compte de service peut maintenant lire le fichier, et personne d’autre ne le peut.

sudo -u listmonk cat /etc/listmonk/config.toml > /dev/null && echo readable
stat -c '%U:%G %a' /etc/listmonk/config.toml

La première commande affiche readable. La deuxième affiche root:listmonk 640. Tout autre compte non privilégié qui tente le même cat obtient Permission denied. C’est l’objectif : ce fichier contient le mot de passe de votre base de données en clair, et un serveur possède généralement plusieurs comptes de connexion. Le même principe s’applique à chaque service que vous exécutez. Lisez donc les comptes de service avec le privilège minimal et appliquez ce principe partout.

Créer le schéma avec --install

--install crée les tables et initialise les paramètres par défaut. Définissez les identifiants de la première connexion administrateur avec des variables d’environnement afin que le compte existe avant que le panneau soit accessible.

sudo -u listmonk env LISTMONK_ADMIN_USER=admin \
  LISTMONK_ADMIN_PASSWORD='another-long-random-password' \
  listmonk --config /etc/listmonk/config.toml --install --yes

--yes répond à la demande de confirmation. Lisez cette demande une fois avant de l’automatiser, car --install est l’installateur initial et supprime un schéma Listmonk existant. Une seconde exécution sur une base de données en production détruit vos abonnés. Dans tout script susceptible d’être exécuté deux fois, utilisez --install --idempotent --yes, qui ne fait rien lorsque les tables existent déjà. Les modifications du schéma incluses dans une nouvelle release s’appliquent avec --upgrade, jamais avec --install.

Vérifiez le résultat depuis la base de données plutôt que depuis le navigateur.

sudo -u postgres psql -d listmonk -c '\dt'
sudo -u postgres psql -d listmonk -tAc "SELECT username FROM users;"

La première commande liste les tables Listmonk, notamment subscribers, lists, campaigns, templates et bounces. La seconde affiche admin. Un résultat vide pour la seconde commande signifie que les variables d’environnement ne sont jamais parvenues au processus. Le panneau vous demandera alors de créer le premier utilisateur dans le navigateur.

Exécuter Listmonk avec systemd

Écrivez /etc/systemd/system/listmonk.service.

[Unit]
Description=Listmonk newsletter and mailing list manager
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
Type=simple
User=listmonk
Group=listmonk
WorkingDirectory=/var/lib/listmonk
ExecStart=/usr/bin/listmonk --config /etc/listmonk/config.toml
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true

[Install]
WantedBy=multi-user.target

WorkingDirectory est important, car Listmonk résout les chemins relatifs, notamment le chemin du système de fichiers utilisé pour les uploads multimédias, par rapport à ce répertoire. After=postgresql.service définit uniquement l’ordre de démarrage. Il n’attend pas que Postgres accepte les connexions. Restart=on-failure couvre donc le cas où Listmonk démarre un peu trop tôt et ne peut pas se connecter.

sudo systemctl daemon-reload
sudo systemctl enable --now listmonk
ss -ltnp | grep 9000
curl -sI http://127.0.0.1:9000/

ss doit afficher 127.0.0.1:9000 dans l’état LISTEN. Si curl renvoie une ligne d’état HTTP, le serveur répond. Si curl échoue avec Connection refused, le processus s’est arrêté pendant le démarrage. journalctl -u listmonk -n 50 --no-pager en indiquera la cause. Notez que enable --now est la partie qui survit à un redémarrage : un processus démarré manuellement disparaît après la prochaine mise à niveau du kernel.

Placer nginx et TLS en frontal

Listmonk utilise HTTP en clair sur loopback. nginx termine donc TLS (transport layer security) et transmet la requête.

server {
    listen 443 ssl;
    server_name lists.example.com;

    client_max_body_size 25m;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

client_max_body_size doit être augmenté, car les imports d’abonnés et les téléversements de médias sont des envois de fichiers. Par défaut, nginx rejette tout fichier de plus de 1 MB avec 413 Request Entity Too Large. Émettez le certificat avec certbot. Celui-ci écrit également les lignes listen 443 ssl et la redirection du port 80. Les étapes sont décrites dans le guide des certificats Let's Encrypt pour nginx. Ouvrez les ports 80 et 443. Laissez le port 9000 fermé, car le proxy y accède via loopback. Si le pare-feu n’est pas encore configuré, commencez par les bases du pare-feu ufw.

Ouvrez ensuite le panneau d’administration et définissez l’URL racine dans Settings sur https://lists.example.com. Une installation neuve contient http://localhost:9000. Listmonk insère cette valeur dans chaque lien de désabonnement et chaque URL de média présents dans un e-mail. Si vous envoyez une campagne avant de la modifier, chaque destinataire reçoit des liens qui pointent vers sa propre machine. Ces liens ne fonctionnent pas pour le destinataire. Pour un filtre antispam, ils donnent aussi l’impression que l’expéditeur ne sait pas configurer son propre domaine.

Connecter SMTP, qui ne figure pas dans config.toml

Recherchez une section SMTP dans config.toml : vous n’en trouverez aucune. Les paramètres de messagerie sont stockés dans la base de données, dans la table settings, et se modifient dans le panneau d’administration, sous Settings puis SMTP. C’est pourquoi le fichier généré reste aussi court. C’est également pourquoi une modification de la configuration SMTP ne nécessite aucun redémarrage.

Pour le serveur SMTP lui-même, deux options sont réalistes. Vous pouvez gérer votre propre serveur. Vous contrôlez alors entièrement sa réputation, mais cela constitue un véritable projet à part entière : gérer votre propre serveur de messagerie avec Mailcow explique ce que cela implique. Vous pouvez aussi configurer Listmonk pour utiliser un relay transactionnel et laisser son opérateur gérer la réputation de l’adresse IP.

Dans les deux cas, utilisez le port 587 avec STARTTLS, ou le port 465 avec TLS implicite. Ne prévoyez pas d’utiliser le port sortant 25. La plupart des fournisseurs de VPS le bloquent par défaut sur les nouveaux comptes. Un port 25 bloqué ressemble exactement à une connexion qui se bloque, car les paquets sont ignorés au lieu d’être refusés. Le client attend donc l’expiration du délai au lieu d’échouer immédiatement.

Testez la configuration avant de lui faire confiance. Créez une liste, ajoutez votre propre adresse comme subscriber, puis envoyez une campagne à un seul destinataire. Ouvrez le message reçu et consultez l’intégralité des en-têtes. L’en-tête Authentication-Results ajouté par le serveur destinataire indique si SPF et DKIM ont réussi.

La délivrabilité est l’objectif principal

Listmonk construit le message, gère la liste et transmet le mail. Le fournisseur qui reçoit le message décide entièrement s’il atteindra une boîte de réception, en fonction de l’adresse IP d’envoi et du domaine d’envoi. Une nouvelle adresse IP de VPS n’a aucun historique. Tous les grands fournisseurs de messagerie considèrent l’absence d’historique comme un signe légèrement suspect.

Quatre éléments sont indispensables :

  • Un enregistrement TXT SPF (sender policy framework) qui indique l’hôte autorisé à envoyer pour votre domaine.
  • Une clé DKIM (domainkeys identified mail) publiée dans un enregistrement TXT. La signature doit être effectuée par le serveur de messagerie, et non par Listmonk.
  • Un enregistrement DMARC (domain based message authentication, reporting and conformance), qui indique aux serveurs destinataires quoi faire lorsque les deux premiers contrôles échouent.
  • Une boîte aux lettres destinée aux bounces, que Listmonk consulte. Les adresses qui refusent les mails sont ainsi retirées de la liste au lieu de faire l’objet de nouvelles tentatives indéfinies.

Commencez ensuite par envoyer lentement. Un domaine qui n’a jamais envoyé de mail et qui distribue soudainement dix mille messages en une heure ressemble exactement à un compte compromis. Il est donc filtré comme tel. Commencez par vos abonnés les plus actifs, puis augmentez le volume sur plusieurs jours.

Chaque template doit également contenir un lien de désabonnement fonctionnel. Dans un template Listmonk, il s’agit de {{ UnsubscribeURL }}. Le corps de la campagne est inséré à l’emplacement de {{ template "content" . }}, qui doit apparaître exactement une fois dans chaque template. Une campagne sans lien de désabonnement génère des signalements de spam plutôt que des désabonnements. Ces signalements sont le moyen le plus rapide de perdre une réputation d’envoi que vous avez mis des semaines à établir.

Sauvegardes : ce qu’une restauration nécessite réellement

Deux éléments doivent sortir du serveur : le dump de la base de données et config.toml. Ajoutez le répertoire des médias si vous téléversez des images dans les campagnes.

sudo -u postgres pg_dump -Fc listmonk > listmonk-$(date +%F).dump

Ce dump contient les abonnés, les campagnes, les modèles et tous les paramètres, y compris les identifiants SMTP. Chiffrez-le et conservez-le en dehors de ce serveur. La planification est un problème résolu : consultez les sauvegardes restic chiffrées vers un stockage distant. config.toml ne contient que quelques lignes, mais il contient le mot de passe de la base de données. Traitez-le donc de la même manière.

Les mises à niveau suivent un ordre précis. Arrêtez le service, créez un dump, remplacez le binaire dans /usr/bin, exécutez listmonk --config /etc/listmonk/config.toml --upgrade, puis démarrez le service. Les migrations de schéma s’exécutent uniquement vers l’avant. Ce dump est donc votre seul moyen de revenir en arrière.

Pourquoi Listmonk refuse-t-il de démarrer ?

Consultez d’abord le journal avec journalctl -u listmonk -n 50 --no-pager. Presque chaque échec au démarrage se résume à une ligne dans le bloc [db].

pq: password authentication failed for user "listmonk" signifie que le mot de passe dans [db] ne correspond pas au rôle Postgres. Le préfixe pq indique que le driver Postgres signale le refus du serveur. La configuration a donc été correctement lue, mais les identifiants sont incorrects. Réinitialisez le rôle avec sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';" et placez la même chaîne dans le fichier.

pq: database "listmonk" does not exist signifie que la valeur de database dans [db] ne désigne pas une base de données réelle. sudo -u postgres psql -l liste les bases réellement présentes sur le serveur, y compris l’orthographe utilisée par erreur.

permission denied pendant --install signifie que le rôle peut se connecter, mais qu’il n’est pas propriétaire de la base de données et ne peut donc pas y créer de tables. Corrigez cela avec sudo -u postgres psql -c "ALTER DATABASE listmonk OWNER TO listmonk;", puis relancez l’installation.

Le service ne démarre jamais et le journal indique le fichier de configuration. Un processus exécuté sous listmonk ne peut pas ouvrir un config.toml laissé avec root:root et le mode 600. stat -c '%U:%G %a' /etc/listmonk/config.toml doit afficher root:listmonk 640, et le répertoire parent doit être root:listmonk 750.

Le panneau fonctionne, mais aucun e-mail n’arrive. Ce n’est pas un problème de démarrage. Vérifiez d’abord Settings et SMTP, puis consultez le journal de la campagne dans le panneau d’administration. Il enregistre l’erreur renvoyée par le serveur de messagerie pour chaque tentative.

FAQ

Ai-je besoin de mon propre serveur de messagerie pour utiliser Listmonk ?

Non. Listmonk n’est pas un serveur de messagerie. Il a besoin des identifiants SMTP d’un serveur qui accepte vos messages et les distribue. Il peut s’agir d’un relais transactionnel ou d’un serveur de messagerie que vous administrez vous-même. Renseignez ces identifiants dans Settings puis SMTP, dans le panneau d’administration, et non dans config.toml, car les paramètres de messagerie sont stockés dans la base de données. Utilisez le port 587 avec STARTTLS ou le port 465 avec TLS implicite, car la plupart des fournisseurs de VPS bloquent le port sortant 25 sur les nouveaux comptes.

Pourquoi les liens de ma campagne pointent-ils vers localhost:9000 ?

Le paramètre de l’URL racine utilise encore sa valeur par défaut d’installation, http://localhost:9000. Listmonk écrit cette valeur dans les liens de désinscription et les URL des médias au moment de l’envoi d’une campagne. Ouvrez Settings dans le panneau d’administration, définissez l’URL racine sur votre véritable adresse HTTPS, puis enregistrez. Les messages déjà distribués ne peuvent pas être corrigés. Envoyez donc une campagne de test à votre propre adresse et cliquez sur son lien de désinscription avant d’envoyer un message à une liste réelle.

Relancer --install supprimera-t-il mes abonnés ?

Oui. --install est l’installateur initial et il supprime le schéma Listmonk existant. --yes supprime l’invite qui vous aurait averti. Dans tout script susceptible d’être exécuté deux fois, utilisez --install --idempotent --yes. Cette option ne fait rien lorsque les tables existent déjà. Pour appliquer les modifications du schéma dans une nouvelle release, arrêtez le service, créez un pg_dump, puis exécutez --upgrade.

Pourquoi Listmonk indique-t-il que l’authentification par mot de passe a échoué pour l’utilisateur listmonk ?

Le mot de passe du bloc [db] dans /etc/listmonk/config.toml ne correspond pas à celui du rôle Postgres portant le même nom. La ligne du journal est pq: password authentication failed for user "listmonk". pq est le driver Postgres qui transmet le rejet du serveur, ce qui signifie que le fichier de configuration a été trouvé et lu. Réinitialisez le mot de passe du rôle avec sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';", écrivez la même chaîne dans le fichier de configuration, puis exécutez sudo systemctl restart listmonk.