SSD Nodes Learn 8GB RAM — $66/jaar
Gidsen Matt ConnorDoor Matt Connor · Bijgewerkt 2026-08-02

Listmonk zelf hosten op een VPS met Ubuntu 24.04

Installeer Listmonk v6.2.0 op Ubuntu 24.04 met PostgreSQL, config.toml, systemd en TLS. Koppel SMTP en ontdek wat e-mailaflevering echt kost.

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

Wat een zelfgehoste nieuwsbrief op Listmonk nodig heeft

Listmonk is een zelfgehoste nieuwsbrief- en mailinglijstbeheerder: één Go-binary, één PostgreSQL-database, één configuratiebestand en één systemd-unit. Een kleine VPS kan dit zonder problemen uitvoeren, omdat Listmonk abonnees opslaat en campagnes in de wachtrij plaatst, maar de e-mail nooit zelf aflevert. Het geeft elk bericht door aan een SMTP-server (simple mail transfer protocol). Uw afleveringspercentage wordt daarom bepaald door de reputatie van die server, niet door deze software.

In deze handleiding installeert u Listmonk v6.2.0, de actuele release in juli 2026, op Ubuntu 24.04. U hebt een VPS met een openbaar IP-adres, een domeinnaam waarover u beschikt en PostgreSQL 12 of nieuwer nodig. De installatie duurt ongeveer een uur. Het opbouwen van een verzendreputatie duurt weken. Dat onderdeel wordt verderop behandeld.

PostgreSQL installeren en de database maken

Ubuntu 24.04 levert PostgreSQL 16 in een eigen repository, ruim nieuwer dan Listmonk nodig heeft.

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

Maak de rol en de database in één psql-sessie. Met -v ON_ERROR_STOP=1 sluit psql af na de eerste mislukte instructie. Zo zorgt een typefout er niet voor dat u een gedeeltelijk voltooide installatie overhoudt die voltooid lijkt.

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 is noodzakelijk. De installatie van het schema maakt tabellen, typen, indexen en functies. Daarom moet de rol eigenaar zijn van de database. Als u Listmonk verwijst naar een database die eigendom is van een andere rol, stopt de installatie met permission denied, ook nadat u GRANT CONNECT hebt uitgevoerd.

Controleer of de database bestaat voordat u verdergaat.

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

Hiermee wordt listmonk weergegeven. Een lege regel betekent dat de CREATE-instructie niet is uitgevoerd. Bekijk de uitvoer van psql opnieuw.

De Listmonk-binary installeren

Listmonk brengt per architectuur een statisch binarybestand uit. Controleer eerst uw architectuur, omdat de kernel een amd64-binary op een ARM-VPS niet kan uitvoeren.

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

Op een ARM-VPS vervangt u amd64 door arm64 in de bestandsnaam. Als listmonk --version een versiereeks afdrukt, is dat uw eerste bewijs dat het binarybestand bij de machine past.

config.toml genereren en beveiligen

--new-config schrijft config.toml naar de huidige werkdirectory. Daarom staat cd binnen sh -c en niet vóór sudo.

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

Het gegenereerde bestand is kort. Onder [app] koppelt address = "localhost:9000" de HTTP-server alleen aan loopback. Daardoor is het beheerpaneel niet bereikbaar vanaf internet totdat u er een reverse proxy voor plaatst. Laat die regel ongewijzigd. Onder [db] vindt u host = "localhost", port = 5432, user = "listmonk", database = "listmonk" en ssl_mode = "disable". Deze standaardwaarden komen al overeen met de database die u hebt aangemaakt. U hoeft dus alleen het wachtwoord te wijzigen.

ssl_mode = "disable" is correct zolang Postgres op loopback op dezelfde host luistert, omdat dit verkeer de machine niet verlaat. Verplaatst u de database naar een andere host, stel dit dan in op require. Anders gaat het wachtwoord onversleuteld over het netwerk.

Bewerk de wachtwoordregel onder [db] zodat deze overeenkomt met de rol. Maak daarna het serviceaccount aan en zorg dat geen andere gebruiker toegang tot het bestand heeft.

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

Het serviceaccount kan het bestand nu lezen en niemand anders kan dat.

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

Het eerste commando geeft readable weer. Het tweede geeft root:listmonk 640 weer. Elk ander account zonder beheerdersrechten dat hetzelfde cat uitvoert, krijgt Permission denied. Dat is precies de bedoeling: dit bestand bevat uw databasewachtwoord in platte tekst en op een server zijn meestal meerdere gebruikers aangemeld. Dezelfde redenering geldt voor elke service die u uitvoert. Lees daarom eenmaal servicegebruikers met minimale rechten en pas dit overal toe.

Het schema maken met --install

--install maakt de tabellen en initialiseert de standaardinstellingen. Stel de eerste aanmelding van de beheerder in met omgevingsvariabelen, zodat het account bestaat voordat het paneel bereikbaar is.

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

--yes beantwoordt de bevestigingsprompt. Lees die prompt eenmaal door voordat u deze automatiseert, omdat --install de eerste keer de installer uitvoert en een bestaand Listmonk-schema verwijdert. Als u dit een tweede keer uitvoert op een live database, worden uw abonnees verwijderd. Gebruik in elk script dat mogelijk tweemaal wordt uitgevoerd --install --idempotent --yes. Deze opdracht doet niets als de tabellen al bestaan. Schemawijzigingen die in een nieuwe release worden geleverd, past u toe met --upgrade, nooit met --install.

Controleer het resultaat vanuit de database en niet vanuit de browser.

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

De eerste opdracht geeft de Listmonk-tabellen weer, waaronder subscribers, lists, campaigns, templates en bounces. De tweede opdracht geeft admin weer. Een leeg resultaat van de tweede opdracht betekent dat de omgevingsvariabelen het proces nooit hebben bereikt. Het paneel vraagt u dan in de browser om de eerste gebruiker aan te maken.

Listmonk uitvoeren onder systemd

Schrijf /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 is belangrijk omdat Listmonk relatieve paden, waaronder een bestandssysteempad voor media-uploads, hiertegen afzet. After=postgresql.service bepaalt alleen de startvolgorde. Het wacht niet totdat Postgres verbindingen accepteert. Restart=on-failure vangt daarom het geval af waarin Listmonk iets te vroeg start en geen verbinding kan maken.

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

ss moet 127.0.0.1:9000 weergeven in de LISTEN-status. Als curl een HTTP-statusregel retourneert, antwoordt de server. Als curl mislukt met Connection refused, is het proces tijdens het opstarten beëindigd. journalctl -u listmonk -n 50 --no-pager vermeldt de reden. Let op: enable --now is het deel dat een reboot overleeft. Een handmatig gestart proces is verdwenen na de volgende kernelupgrade.

Plaats nginx en TLS ervoor

Listmonk gebruikt onbeveiligde HTTP op loopback. nginx beëindigt daarom TLS (transportlaagbeveiliging) en stuurt het verzoek door.

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 moet worden verhoogd omdat imports van abonnees en media-uploads bestandsverzoeken zijn. nginx weigert standaard alles groter dan 1 MB met 413 Request Entity Too Large. Vraag het certificaat aan met certbot. certbot schrijft ook de regels listen 443 ssl en de omleiding vanaf poort 80 voor u. De stappen staan in de handleiding voor Let's Encrypt-certificaten voor nginx. Open poorten 80 en 443. Houd poort 9000 gesloten, omdat de proxy deze via loopback bereikt. Als de firewall nog niet is geconfigureerd, begint u met de basisprincipes van de ufw-firewall.

Open vervolgens het beheerpaneel en stel onder Settings de root-URL in op https://lists.example.com. Een nieuwe installatie bevat http://localhost:9000. Listmonk schrijft deze waarde in elke afmeldlink en media-URL die het in een e-mail plaatst. Als u een campagne verzendt voordat u deze waarde wijzigt, krijgt elke ontvanger links naar zijn eigen computer. Deze links werken niet voor de ontvanger. Voor een spamfilter lijken ze afkomstig van een afzender die zijn eigen domein niet kan configureren.

SMTP verbinden, dat niet in config.toml staat

Zoek in config.toml naar een SMTP-sectie. U vindt die niet. De mailinstellingen staan in de database, in de tabel settings. U bewerkt deze instellingen in het beheerpaneel onder Settings en SMTP. Daarom blijft het gegenereerde bestand zo kort. Daarom is voor een SMTP-wijziging ook geen herstart nodig.

Voor de SMTP-server zelf zijn er twee reële opties. U kunt uw eigen server gebruiken. Dan beheert u de reputatie volledig zelf. Dat is op zichzelf een volwaardig project: uw eigen mailserver met Mailcow uitvoeren behandelt wat daarbij komt kijken. U kunt Listmonk ook naar een transactionele relay laten verwijzen. Dan beheert een andere partij de IP-reputatie.

Gebruik in beide gevallen poort 587 met STARTTLS, of poort 465 met impliciete TLS. Plan geen uitgaand verkeer via poort 25. De meeste VPS-providers blokkeren deze poort standaard bij nieuwe accounts. Een geblokkeerde poort 25 lijkt precies op een verbinding die blijft hangen, omdat de pakketten worden verwijderd in plaats van geweigerd. De client wacht daardoor op een time-out in plaats van direct te stoppen.

Test de configuratie voordat u erop vertrouwt. Maak een lijst en voeg uw eigen adres als abonnee toe. Verstuur een campagne naar één ontvanger. Open het ontvangen bericht en lees de volledige headers. De header Authentication-Results die door de ontvangende kant is toegevoegd, laat zien of SPF en DKIM zijn geslaagd.

Bezorgbaarheid is het volledige doel

Listmonk stelt het bericht samen, houdt de lijst bij en geeft de e-mail door. Elke beslissing over de vraag of die e-mail de inbox bereikt, wordt genomen door de ontvangende provider. Daarbij gebruikt deze het verzendende IP-adres en het verzendende domein. Een nieuw VPS-IP-adres heeft helemaal geen reputatie. Elke grote mailboxprovider beschouwt het ontbreken van een reputatie als enigszins verdacht.

Vier zaken zijn verplicht:

  • Een SPF (sender policy framework)-TXT-record waarin de host wordt vermeld die namens uw domein mag verzenden.
  • Een DKIM (domainkeys identified mail)-sleutel die als TXT-record is gepubliceerd. De mailserver moet de ondertekening uitvoeren, niet Listmonk.
  • Een DMARC (domain based message authentication, reporting and conformance)-record dat ontvangers vertelt wat ze moeten doen wanneer de eerste twee controles mislukken.
  • Een mailbox voor bounces die Listmonk uitleest. Adressen die e-mail weigeren, worden dan van de lijst verwijderd in plaats van eindeloos opnieuw te worden geprobeerd.

Verstuur in het begin langzaam. Een domein dat nog nooit e-mail heeft verzonden en plotseling tienduizend berichten in een uur aflevert, ziet er precies uit als een gehackt account. Daarom wordt het op dezelfde manier gefilterd. Begin met uw meest betrokken abonnees en verhoog het volume verspreid over meerdere dagen.

Elke template heeft ook een werkende afmeldingslink nodig. In een Listmonk-template is dat {{ UnsubscribeURL }}. De inhoud van de campagne wordt geplaatst op de positie van {{ template "content" . }}. Deze marker moet in elke template precies eenmaal voorkomen. Een campagne zonder afmeldingslink leidt tot spamklachten in plaats van afmeldingen. Klachten zijn de snelste manier om de verzendreputatie te verliezen die u in weken hebt opgebouwd.

Back-ups en wat een herstel daadwerkelijk vereist

Twee zaken moeten de server verlaten: de database-dump en config.toml. Voeg de mediadirectory toe als u afbeeldingen naar campagnes uploadt.

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

Die dump bevat abonnees, campagnes, sjablonen en alle instellingen, inclusief de SMTP-inloggegevens. Versleutel de dump daarom en bewaar deze niet op deze server. Het plannen daarvan is opgelost: zie versleutelde restic-back-ups naar externe opslag. config.toml bestaat uit enkele regels, maar bevat het databasewachtwoord. Behandel dit bestand daarom op dezelfde manier.

Voer upgrades in deze volgorde uit. Stop de service, maak een dump, vervang het binaire bestand in /usr/bin, voer listmonk --config /etc/listmonk/config.toml --upgrade uit en start de service vervolgens. Schemamigraties worden alleen vooruit uitgevoerd. Die dump is daarom uw enige weg terug.

Waarom kan Listmonk niet starten?

Lees eerst het journal met journalctl -u listmonk -n 50 --no-pager. Bij vrijwel elke startfout staat de oorzaak op één regel in het blok [db].

pq: password authentication failed for user "listmonk" betekent dat het wachtwoord in [db] niet overeenkomt met de Postgres-rol. Het voorvoegsel pq geeft aan dat de Postgres-driver de afwijzing van de server meldt. Het configuratiebestand is dus correct gelezen, maar de inloggegevens waren onjuist. Stel de rol opnieuw in met sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';" en plaats exact dezelfde tekenreeks in het bestand.

pq: database "listmonk" does not exist betekent dat de waarde database in [db] geen bestaande database aanduidt. sudo -u postgres psql -l geeft weer welke databases daadwerkelijk op de server staan, inclusief de schrijfwijze die u per ongeluk hebt gebruikt.

permission denied tijdens --install betekent dat de rol verbinding kan maken, maar geen eigenaar van de database is. Daarom kan de rol er geen tabellen in maken. Los dit op met sudo -u postgres psql -c "ALTER DATABASE listmonk OWNER TO listmonk;" en voer de installatie opnieuw uit.

De service start nooit en het journal vermeldt het configuratiebestand. Een proces dat als listmonk draait, kan een bestand met config.toml niet openen als dit bestand de eigenaar root:root heeft en mode 600 gebruikt. stat -c '%U:%G %a' /etc/listmonk/config.toml moet root:listmonk 640 afdrukken. De bovenliggende directory moet root:listmonk 750 zijn.

Het paneel werkt, maar er komt geen e-mail aan. Dit is geen startprobleem. Controleer eerst Settings en SMTP. Controleer daarna het eigen logboek van de campagne in het beheerpaneel. Daarin staat welke fout de mailserver voor elke poging heeft geretourneerd.

FAQ

Heb ik mijn eigen mailserver nodig om Listmonk te gebruiken?

Nee. Listmonk is geen mailserver. Het programma heeft SMTP-inloggegevens nodig voor een server die uw e-mail accepteert en aflevert. Dat kan een transactionele relay zijn of een mailserver die u zelf beheert. Stel deze gegevens in onder Settings en SMTP in het beheerpaneel, niet in config.toml, omdat de mailinstellingen in de database staan. Gebruik poort 587 met STARTTLS of poort 465 met impliciete TLS, omdat de meeste VPS-providers uitgaand verkeer op poort 25 bij nieuwe accounts blokkeren.

De instelling voor de root-URL staat nog op de installatiestandaardwaarde http://localhost:9000. Listmonk schrijft deze waarde in afmeldingslinks en media-URL's op het moment dat een campagne wordt verzonden. Open Settings in het beheerpaneel, stel de root-URL in op uw echte HTTPS-adres en sla de wijziging op. Reeds afgeleverde berichten kunnen niet worden gecorrigeerd. Stuur daarom een testcampagne naar uzelf en klik daarin op de afmeldingslink voordat u een echte lijst mailt.

Verwijdert het opnieuw uitvoeren van --install mijn abonnees?

Ja. --install is het installatieprogramma voor de eerste keer en verwijdert het bestaande Listmonk-schema. --yes verwijdert de vraag die u hiervoor zou hebben gewaarschuwd. Gebruik in elk script dat mogelijk twee keer wordt uitgevoerd --install --idempotent --yes. Deze opdracht doet niets als de tabellen al bestaan. Als u de schemawijzigingen in een nieuwe release wilt toepassen, stopt u de service, maakt u een pg_dump en voert u daarna --upgrade uit.

Waarom meldt Listmonk dat de wachtwoordverificatie voor gebruiker listmonk is mislukt?

Het wachtwoord in het blok [db] van /etc/listmonk/config.toml komt niet overeen met de Postgres-rol met dezelfde naam. De regel in het journal is pq: password authentication failed for user "listmonk". pq is de Postgres-driver die de afwijzing van de server doorgeeft. Dit betekent dat het configuratiebestand is gevonden en gelezen. Stel het wachtwoord van de rol opnieuw in met sudo -u postgres psql -c "ALTER USER listmonk WITH PASSWORD 'new-password';", schrijf exact dezelfde tekenreeks naar het configuratiebestand en voer daarna sudo systemctl restart listmonk uit.