To self-host Listmonk on a managed VPS is to keep your subscriber lists and campaigns on a machine of your own, which our teams keep up to date and watch day and night. Listmonk is free software under the AGPL-3.0 licence. This guide follows its official documentation: which version to choose, Docker Compose, PostgreSQL, HTTPS, sending over SMTP, bounces, consent, backups and updates.
By Simon Vasconcelos Lee
Published on 12 November 202613-minute read
pg_dump before every update.Listmonk manages your mailing lists and newsletters from a web interface. It is a single program, written in Go, whose only dependency is PostgreSQL. Its lists are one-way: you write to your subscribers, and it is not a discussion list between them.
Listmonk is published under the GNU AGPL version 3 licence. You can use it, in business too, and send your own campaigns as well as your clients’, with no licence to buy. What remains is the cost of the server and of your email delivery service.
Section 13 adds a condition specific to the AGPL: if you modify the program, your version must prominently offer everyone who uses it remotely, over a network, the chance to obtain its source code at no charge. If you distribute copies, the licence’s source-sharing obligations apply as well. Running Listmonk unmodified does not trigger this section.
One point to know before you start. On GitHub, the "Latest" label currently sits on v7.0.0-beta.2 of November 10, 2026, which the project itself presents as a beta. The latest stable version is v6.2.0, which carries security fixes for permissions. As of November 11, 2026, the Docker image latest points to this v6.2.0.
| Version | Docker image | Status |
|---|---|---|
| v6.2.0 | listmonk/listmonk:v6.2.0 | Stable: the one used in this guide |
| v7.0.0-beta.2 | listmonk/listmonk:beta | Beta: try it on a copy, with a backup |
| nightly | listmonk/listmonk:nightly | Untested, according to the project: at your own risk |
Version 7 replaces the entire admin interface, changes some of its URLs, turns the app.from_email setting into a list of addresses and changes translation keys, which affects custom templates. Read its release notes before moving to it.
The project’s Compose file runs --upgrade --yes on every start: a new image migrates the database without asking you. A migrated database cannot be read by an older version, and going back means restoring a backup. With a fixed tag such as v6.2.0, changing versions stays your decision.
The project recommends Docker Compose: its file runs Listmonk and PostgreSQL together. On a server with Docker installed, create a folder and download this file:
mkdir listmonk
cd listmonk
curl -LO https://github.com/knadh/listmonk/raw/master/docker-compose.yml
The project asks you to adapt this file to your environment. These are the only lines to change, and the rest stays as it is:
x-db-credentials: &db-credentials
POSTGRES_USER: &db-user listmonk
POSTGRES_PASSWORD: &db-password un-mot-de-passe-long
POSTGRES_DB: &db-name listmonk
services:
app:
image: listmonk/listmonk:v6.2.0
ports:
- "127.0.0.1:9000:9000"
hostname: listmonk.example.com
listmonk as a starting value. Change it before the first start, because the PostgreSQL image only reads this variable on an empty data folder.latest, for the reason above.127.0.0.1: this is our adaptation. The project’s file publishes port 9000 with no address limit, and already limits PostgreSQL to the local address. Treated the same way, Listmonk is reached only through the reverse proxy.Then start the services and create the Super Admin account in advance. These two variables are only used on the first start, and without them the account is created on the first visit to the interface: it is best to have it in place before you open your domain.
LISTMONK_ADMIN_USER=votre-identifiant LISTMONK_ADMIN_PASSWORD=votre-mot-de-passe docker compose up -d
Listmonk also runs as a standalone program, alongside your own PostgreSQL server, version 12 or later, where the database already exists.
listmonk_6.2.0_linux_amd64.tar.gz, skipping the beta shown first, and extract the binary.config.toml../listmonk --new-config
./listmonk --install
./listmonk
By default, config.toml listens on localhost:9000, which suits a reverse proxy. The repository provides a listmonk@.service file for systemd.
The project’s website cites a production instance sending a campaign of more than 7 million emails with a fraction of a single CPU core and peak memory use of 57 MB. It publishes neither a minimum nor a figure for PostgreSQL, whose volume grows with your subscribers, views and clicks. On a managed VPS, describe your usage to us and we will recommend the right size.
Your subscribers click links that point to your instance: unsubscribing, confirming, click tracking. So it is served over HTTPS on its own domain name. Create the A and AAAA records for this name pointing to your server, where visitors arrive on ports 80 and 443. The Listmonk documentation leaves the choice of proxy to you; here are two common configurations.
Caddy obtains and renews the certificate on its own:
listmonk.example.com {
reverse_proxy 127.0.0.1:9000
}
By default, Nginx rejects requests over 1 MB with a 413 error. To import a subscriber file or images, raise this limit to match your files:
server {
listen 80;
listen [::]:80;
server_name listmonk.example.com;
client_max_body_size 100m;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Certbot then installs the Let’s Encrypt certificate and the redirect to HTTPS, and renews the certificate on its own:
sudo certbot --nginx -d listmonk.example.com
Log in at https://listmonk.example.com/admin, then open "Settings":
https://listmonk.example.com. Listmonk builds the unsubscribe, confirmation and tracking links in your emails from it. Its starting value, http://localhost:9000, would not work for your subscribers./listmonk/uploads, the folder the Compose file mounts on the server.To filter access, by IP address or through an authentication proxy, the documentation divides the routes this way:
| Routes | Purpose | Access |
|---|---|---|
/admin/*, /api/*, /webhooks/bounce | The admin interface, its API and the internal bounce webhook | Private |
/subscription/*, /public/* | The subscription pages and their files | Public |
/link/*, /campaign/* | Link tracking and the tracking pixel | Public |
/webhooks/service/* | Bounces sent by your email delivery service | Public |
/uploads/* | The images in your emails | Public |
Listmonk prepares and paces your emails, then hands them to the SMTP servers you declare in "Settings", "SMTP". It does not deliver them to your subscribers’ inboxes itself: delivery quality depends on that server, your domain and your lists.
For bulk sending, choose a specialized email delivery service: it carries the reputation of your sending and the signatures of your domain, and it can report bounces back. From a Simafri VPS, email goes out through an authenticated SMTP relay on port 587: here, that of this service.
For reference, the Listmonk documentation describes bounces from Amazon SES, Azure Communication Services, SendGrid, Postmark, Forward Email and Lettermint. Compare them according to your volume and your recipients.
| Setting | Value | What to check |
|---|---|---|
| Host | The SMTP address of your service | Replaces the example value provided |
| Port | 587 | The presets on this screen often offer another port: switch back to 587 |
| TLS | STARTTLS | Goes with port 587 |
| Auth protocol | The one your service uses, often LOGIN | With the service’s SMTP username and password |
Then click "Test connection": Listmonk sends a test message and shows the server’s error if sending fails. You can declare several servers, choose one per campaign, or route sending by sender address or domain.
Set it in "Settings", "Performance", below your service’s limit:
A message that fails is retried according to the "Retries" setting, on other connections to the server. If it fails again, Listmonk logs it as an error and moves on: keep an eye on these errors during a large campaign.
Hosting the application leaves you in charge of these topics, and they decide whether your emails arrive.
Send from an address on your domain, and publish in its DNS zone the SPF and DKIM records your email delivery service gives you, along with a DMARC record. Google requires all three from senders of more than 5,000 messages a day to Gmail accounts, with a sending domain aligned with SPF or DKIM, one-click unsubscribe for marketing messages, and a spam report rate below 0.30%, ideally below 0.10%.
{{ UnsubscribeURL }} in your template’s footer. This link leads to preference management and unsubscribing.Listmonk applies the list type you choose. On a single opt-in list, a subscriber added without confirmation still receives your campaigns. On a double opt-in list, they first receive a confirmation email, and only confirmed subscribers receive your campaigns. This is the choice that best protects your sending reputation and keeps a clear record of the agreement.
The rules depend on your recipients’ country. In France, for example, the data protection authority (CNIL) requires prior consent from individuals, through a positive action such as an unchecked box, with an exception for your customers on similar products or services. Between professionals, prospecting can rest on legitimate interest if it concerns their line of work. In every case, each message identifies the sender and offers a simple way to refuse further messages.
Write only to people who are expecting your messages. A purchased or stale list drives up bounces and spam reports, and your domain bears the consequences.
The tracking pixel and click tracking touch on privacy, and the documentation asks that they be used in compliance with rules such as the GDPR. By default, this tracking is not tied to each subscriber: the "Individual subscriber tracking" option ties it, and "Disable tracking" turns it off entirely, in "Settings", "Privacy".
Continuing to write to an address that rejects your messages damages your sending reputation. Bounce processing is off from the start: turn it on in "Settings", "Bounces", then choose one of these two routes.
https://listmonk.example.com/webhooks/service/ses, with the last word changing by service. This address must stay public.For a dedicated mailbox, declare it as the return address in "Settings", "SMTP", "Custom headers":
[
{"Return-Path": "your-bounce-inbox@example.com"}
]
The starting settings are the ones the documentation gives for SES, and they make a good base:
| Bounce type | Count | Action |
|---|---|---|
| Soft (temporary) | 2 | None |
| Hard (permanent) | 1 | Blocklist: the address is blocked |
| Complaint (spam report) | 1 | Blocklist: the address is blocked |
Listmonk requires PostgreSQL 12 or later. The Compose file brings postgres:17-alpine, with its data in the Docker volume listmonk-data. Subscribers, campaigns, templates, statistics and most settings live there; only the database credentials and the listening address stay in the configuration.
To use an existing PostgreSQL server, change the LISTMONK_db__host, LISTMONK_db__port, LISTMONK_db__user, LISTMONK_db__password and LISTMONK_db__database variables of the app service.
Listmonk is built for large lists. As the database grows, it is what can slow down the interface: with millions of subscribers, the dashboard and counters can take tens of seconds to display. The project then advises two steps:
VACUUM ANALYZE on a large database, for instance once a week. The command blocks queries while it runs, generally for a few seconds.docker compose exec db psql -U listmonk -d listmonk -c 'VACUUM ANALYZE;'
Two things make up your instance: the PostgreSQL database and the uploads folder, if your images stay on disk. pg_dump produces a consistent export without stopping Listmonk or blocking other access to the database:
docker compose exec -T db pg_dump -U listmonk listmonk > listmonk-$(date +%F).sql
tar -czf listmonk-uploads-$(date +%F).tar.gz uploads
To restore, stop Listmonk, empty the database and reload the export. As the documentation points out, this wipes the existing database:
docker compose stop app
docker compose exec db psql -U listmonk -d listmonk -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'
docker compose exec -T db psql -U listmonk -d listmonk < listmonk-2026-11-01.sql
docker compose start app
docker-compose.yml.docker compose down app
docker compose pull
docker compose up app -d
With the binary, stop Listmonk, replace the binary, run ./listmonk --upgrade, then start it again. To go back to an earlier version, restore the export taken before the update, then put the old tag back.
Self-hosting means running the server as well as the application. On a Managed VPS, our teams take charge of the server and proactively monitor your instance; Listmonk remains your software, with its settings, your lists and your campaigns.
| Topic | Our teams | You |
|---|---|---|
| The server | System and security updates, server interventions included | The time that suits your business |
| Monitoring | Server watched 24/7, with intervention without waiting for your call | Following your campaigns and bounces |
| Listmonk | Proactive monitoring: errors, slowdowns and disk space spotted, fix recommended | Its installation, updates and settings, which you apply, yourself or through your AI assistant |
| Sending | A server that reaches your SMTP relay on port 587 | Your email delivery service, your DNS records, your lists and your recipients’ consent |
| Backups | Every night, encrypted and kept off the machine; restores included | The restore request, and your export before each update |
| Migration | Your current server migrated, free of charge | The time of the switchover |
If you would rather have our teams work inside the application itself, this service is billed hourly or at a fixed price, with an estimate provided before the work begins.
With a Simafri Managed VPS, our teams keep your Listmonk instance’s server up to date, monitor it day and night and step in without waiting for your call; they also proactively monitor your instance and recommend useful fixes, which you apply, yourself or through your AI assistant. Backups are encrypted every night and kept off the machine, restores are included, and migrating your current server is complimentary.
Yes. Listmonk is under the AGPL-3.0 licence: you can use it in business with no licence to buy. If you modify it, your remote users must be able to obtain the source code of your version. What remains is the cost of the server and of your email delivery service.
v6.2.0, the latest stable version as of November 11, 2026. v7.0.0-beta.2, shown first on GitHub, is a beta. In Docker Compose, pin the image to listmonk/listmonk:v6.2.0: changing versions then stays your decision, since a migrated database cannot be read by an older version.
Download the project’s docker-compose.yml file, change the database password and the image tag, then run docker compose up -d. The interface responds on port 9000, with PostgreSQL alongside it. Serve it over HTTPS behind a reverse proxy and fill in its Root URL.
Listmonk sends through the SMTP servers you configure. For bulk sending, use a specialized email delivery service, with STARTTLS on port 587, and publish SPF, DKIM and DMARC on your domain. The Listmonk documentation describes bounces from Amazon SES, SendGrid and Postmark, for example.
Turn on processing in Settings, Bounces, then connect your email delivery service’s webhook or a dedicated POP3 mailbox. The starting settings block an address after one permanent bounce or one spam report.
Export the database with pg_dump, without stopping the service, and keep the uploads folder if your images are on disk. The project asks for this export before every update, since an earlier version cannot read a database that has already been migrated.
It gives you the tools: double opt-in lists, an unsubscribe link in your templates, a List-Unsubscribe header, and data export and erasure by the subscriber. Collecting consent itself is up to you, according to the rules of your recipients’ country.
A Managed VPS covers the server: system, security, monitoring and backups. Our teams also proactively monitor your instance and recommend useful fixes, which you apply. Work inside the application is billed hourly or at a fixed price.
Simafri
Let's talk about your website
Tell us about your project in a few words: we will get back to you quickly.
Thank you! Your request has been sent. We'll get back to you shortly.
Prefer email? Write to us at support@simafri.com.