Overview
Listmonk is a high-performance, self-hosted newsletter and mailing list manager distributed as a single Go binary — a self-hosted alternative to Mailchimp, Sendy, and Mautic. This template deploys the listmonk server on port9000 — admin dashboard, campaign engine, public subscription and tracking pages, and the transactional-mail API — backed by PostgreSQL, with the database schema install and Super Admin bootstrap handled automatically on first boot.
Architecture
- Listmonk — A stateful, single-replica workload serving the admin UI, the public subscription/tracking pages, and the HTTP API on port
9000. The container boots through listmonk’s own idempotent install chain: it waits for the database, installs the schema, applies any pending migrations, then starts the server. A default install is ready in about a minute with no manual setup step, and a restart re-runs the same chain safely — it detects an already-provisioned database, skips the install, and leaves existing data untouched. - PostgreSQL (single-instance, default) — The postgres template as a subchart: the store for all lists, subscribers, campaigns, templates, and settings.
- PostgreSQL (HA, optional) — The postgres-highly-available template instead: 3× Patroni PostgreSQL with automatic failover, fronted by an HAProxy leader endpoint that listmonk connects through for writes and schema migrations.
What Gets Created
- Stateful Listmonk Workload — The listmonk server on port
9000, one replica, with configurable CPU and memory. - Database Workloads — Single mode: one stateful PostgreSQL workload. HA mode: a stateful Patroni PostgreSQL workload, a stateful etcd workload, and a standard HAProxy leader-routing workload.
- Volume Sets — A persistent uploads volume set mounted at
/listmonk/uploadsfor media uploaded through the admin UI, plus the database subchart’s data volumes (10 GiB by default; per replica in HA mode). - Secret — A dictionary secret holding the admin bootstrap username and password. The database credentials secret is created by the backing store subchart.
- Identity & Policy — An identity bound to the listmonk workload, with a policy granting
revealon exactly two secrets: the admin bootstrap secret and the active backing store’s credentials secret. - Cron Backup Workload (optional) — Created in the backing PostgreSQL store when database backups are enabled.
This template does not create a GVC. You must deploy it into an existing GVC.
Prerequisites
None for a default install — it deploys with a working PostgreSQL backend, an installed schema, a bootstrapped admin account, and an auto-assigned HTTPS endpoint. Two things are configured after install rather than at install time:- SMTP — required before any mail is delivered. Configured in listmonk’s own admin UI (see Post-Install Setup).
- Database backups (optional) — need a bucket and provider access set up beforehand (see Backing Up).
UI
Browse, install, and manage templates visually
CLI
Manage templates from your terminal
Terraform
Declare templates in your Terraform configurations
Pulumi
Declare templates in your Pulumi programs
Choosing a Database Mode
Exactly one of the two backing stores must be enabled — the chart enforces this at render. Listmonk is wired to the active database automatically, including for the first-boot schema install.
To switch to HA mode, set
postgres.enabled: false and postgresHA.enabled: true.
Configuration
Key configuration values (see the template’svalues.yaml for the complete set):
Application
image— The official listmonk image from Docker Hub.resources— CPU and memory bounds for the listmonk workload. Listmonk is a single Go binary, so the defaults suit typical installs.volumeset.capacity— Initial size in GiB (minimum 10) of the uploads volume set mounted at/listmonk/uploads. It holds images and files uploaded through the admin Media page, including generated thumbnails, and survives restarts and redeploys.timezone— The container timezone, which governs the times used for scheduled campaigns.
Admin Bootstrap
{release}-listmonk-admin dictionary secret. The chart rejects a username shorter than 3 characters or a password shorter than 8 at render time, before anything is deployed.
Access
publicAccess.enabled— Serve listmonk on the auto-assigned*.cpln.appHTTPS canonical endpoint (default). This is what makes the subscriber-facing pages — subscription forms, unsubscribe links, and tracking pixels — reachable from the internet. The admin UI and admin API on the same endpoint remain authentication-gated. Set tofalsefor an internal-only instance: external requests are then refused at the edge, and in-GVC callers still reach it perinternalAccess.internalAccess.type— Controls which workloads can reach listmonk over the internal network:
Firewall changes take up to a couple of minutes to propagate after a
helm upgrade reports success.Backing Store
Enable exactly one ofpostgres (single-instance, default) or postgresHA (HA) — see Choosing a Database Mode. In both modes, change the database password before installing (postgres.config.password / postgresHA.postgres.password); it seeds the database on first boot and cannot be changed by editing values afterwards.
The database holds everything except uploaded media: lists, subscribers, campaigns, templates, users, and all of the settings you configure in the admin UI.
Connecting
Once the workload reports ready, open
https://<canonical>.cpln.app/admin and sign in with the bootstrap credentials — the schema is already installed and the Super Admin already exists, so there is no setup wizard and no manual install step.
Post-Install Setup
Mail delivery and object-storage media are listmonk settings stored in its database, not template values. Configure them in the admin UI after installing:1
Configure SMTP
In Admin → Settings → SMTP, add your mail provider (Amazon SES, SendGrid, Mailgun, Postmark, or any SMTP relay) and save. Until a working SMTP server is configured, campaigns still run to completion but no mail is delivered.
2
Set the root URL
In Admin → Settings → General, set the root URL to your canonical
*.cpln.app endpoint, or to your custom domain once you attach one, so that links and tracking URLs inside your emails point at the right host.3
Choose a media store (optional)
Filesystem storage on the bundled uploads volume set works out of the box. To store media in S3-compatible object storage instead, switch the provider in Admin → Settings → Media.
Backing Up
Database backups are optional and disabled by default. When enabled, a scheduled backup job runs inside the backing PostgreSQL store and uploads to your bucket under the configured prefix — covering lists, subscribers, campaigns, and settings, but not the uploaded media on the listmonk volume set. Enable withpostgres.backup.enabled or postgresHA.backup.enabled (matching your database mode), and complete the storage setup for your provider before installing.
- AWS S3
- Google Cloud Storage
- S3-compatible (MinIO)
1
Create a bucket
Create an S3 bucket. Set
backup.aws.bucket and backup.aws.region to match.2
Set up a Cloud Account
If you do not have one, create a Cloud Account for your AWS account. Set
backup.aws.cloudAccountName to its name.3
Create a bucket-scoped IAM policy
Create an IAM policy granting the required S3 actions on the bucket, and set
backup.aws.policyName to its name:postgresHA.backup.mode selects logical (scheduled pg_dump) or wal-g (continuous WAL archiving). The full per-provider walkthrough lives in the backing postgres and postgres-highly-available template documentation.
Important Notes
- Single instance by design — there is no
replicasknob. Listmonk runs its campaign workers in-process, so two instances against one database would send every campaign twice. The workload is pinned to one replica and rolls out without surge: the old replica stops before the new one starts, which means an upgrade or restart causes a brief gap in availability instead of overlapping senders. Durability comes from PostgreSQL and the uploads volume set. - Change
admin.passwordand the database password before installing. Both are applied on the first boot only; editing them afterwards does not change the existing account or database. - No mail is delivered until SMTP is configured in Admin → Settings → SMTP. Before that, starting a campaign is not an error — it runs and finishes with zero messages sent.
- Keep
publicAccessenabled for subscriber-facing pages to work. Subscription forms, unsubscribe links, and tracking pixels must be reachable from the internet; the admin UI and API stay authentication-gated either way. - Use
/healthfor external health checks, not/api/health— the latter requires an authenticated session. - Volumes survive reinstalls under the same release name; uninstalling deletes them — the database volumes and the uploads volume set go with the release, taking all lists, subscribers, campaigns, and media with them. Use
postgresHAand/or enable backups for durable production data.
External References
Listmonk Documentation
Official listmonk documentation
Configuration Reference
Settings, SMTP options, and filesystem or S3 media storage
Concepts
How lists, subscribers, campaigns, and templates fit together
API Reference
Manage lists, subscribers, and campaigns over HTTP
Listmonk Template
View the source files, default values, and chart definition