Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

listmonk Deployment

Docker Compose setup for listmonk.

Prerequisites

Install Docker and Docker Compose:

curl -fsSL https://get.docker.com | sh

Quick Start

1. Clone the repository

sudo mkdir -p /opt/listmonk-docker
sudo chown -R $USER:$USER /opt/listmonk-docker
git clone https://github.com/Afkanerd/listmonk-docker.git /opt/listmonk-docker
cd /opt/listmonk-docker

2. Configure environment

cp .env.example .env
vim .env

Set your database password and, optionally, the initial super admin credentials. listmonk does not take SMTP settings as environment variables, outbound mail is configured through the web UI after first boot (step 5).

3. Set file permissions

chmod 600 .env compose.yaml
mkdir -p backups uploads && chmod 700 backups uploads

4. Deploy

docker compose up -d
docker compose ps

On first boot, the app container installs the schema, applies migrations, then starts. If LISTMONK_ADMIN_USER/LISTMONK_ADMIN_PASSWORD were set in .env before this first run, the super admin account is created automatically. Otherwise, create it from the web UI.

5. Configure SMTP

Log in at http://127.0.0.1:4000 (or your domain, see reverse proxy), go to Settings > SMTP, add your relay, and send a test email. No mail of any kind sends until this is configured.

Overridable files

The double opt-in email and its shared HTML/CSS wrapper are compiled into the listmonk binary, they can't be edited from the admin UI. compose.yaml mounts ./static-overrides into the container and passes --static-dir to listmonk, which merges these files over the built-in defaults file by file, anything you don't touch keeps working as-is.

static-overrides/
├── email-templates/
│   ├── base.html                        # shared header/footer/CSS for all emails
│   ├── subscriber-optin.html            # the double opt-in / welcome email body
│   └── subscriber-optin-campaign.html   # used when a list has a custom opt-in campaign
└── public/
    ├── templates/optin.html             # web page shown before confirming
    └── static/style.css                 # CSS for public pages (opt-in, unsubscribe, archive)

subscriber-optin.html is already reworded as a welcome message rather than a bare confirmation notice, use it as a starting point. Edit any file, then:

docker compose restart app

listmonk only reads these files at startup, so a restart is required after every edit. See templating syntax and i18n if you want translated copy instead of hardcoded text.

Per-list opt-in behavior (single/double, opt-in campaign message) is set under Lists > your list > Opt-in in the admin UI. See concepts for how lists and opt-in types work.

Nginx reverse proxy

server {
    server_name yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:4000;
        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;
    }
}

Backups and restore

Backups run on the schedule in .env (default @daily) and are saved to ./backups as pg_dumpall cluster dumps (roles and data, not just one database). Uses postgres-backup-local.

Manual backup

docker exec listmonk_backup /backup.sh

Writes to ./backups/last/, daily/, weekly/, and monthly/, each with a *-latest.sql.gz symlink to the newest file.

Restore

Cluster dumps include CREATE ROLE/CREATE DATABASE, so they must be restored into an empty Postgres volume, not layered onto a live one. This is a full point-in-time recovery, not a merge.

# stop app and db
docker compose stop app db

# wipe the postgres volume, this destroys current DB state
docker compose rm -f db
docker volume rm listmonk_db_data

# start postgres fresh, it recreates an empty listmonk role/db from .env
docker compose up -d db

# stream the dump in. two harmless errors are expected here:
# "role listmonk already exists" and "database listmonk already exists",
# since step 3 already created them. everything after that restores.
zcat ./backups/daily/listmonk-latest.sql.gz | docker exec -i listmonk_db psql -U listmonk -d listmonk

# bring the app back up
docker compose up -d app

Maintenance

# logs
docker compose logs -f

# stop
docker compose down

# update
docker compose pull && docker compose up -d

Migrations run automatically on startup, so no manual step is needed after an update.

About

Docker Compose setup for Listmonk (https://listmonk.app)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages