# Listmonk

Newsletter and mailing list manager written in Go, shipped as a single binary with a web dashboard.

- Replaces: [Mailchimp](https://openlogs.fyi/alternatives/mailchimp)
- Summary: Paid email newsletter services, such as Mailchimp.
- Stack: Go (language), PostgreSQL (database)
- Deployment: docker_compose
- License: AGPL-3.0 (osi) [source](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/LICENSE)
- Business model: unknown. The README at the pinned commit does not state a business model, so it stays unknown. ([source](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/README.md), read 2026-10-22)
- Difficulty: medium. 2 services (1 database or broker: postgres), 2 volume mounts, no env values to set, no elevated host access. Heuristic score 3 of 11: medium.
- Requirements: not stated
- Repository: [knadh/listmonk](https://github.com/knadh/listmonk)

## Install

1. Docker with the Compose plugin ([source](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/docker-compose.yml))

   ```text
   A host with Docker and the Docker Compose plugin. This entry runs from a compose file.
   ```

2. Save the compose file as docker-compose.yml ([source](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/docker-compose.yml))

   ```yaml
   # All LISTMONK_* env variables also support the LISTMONK_*_FILE pattern for loading secrets from files with Docker secrets and Podman
   # eg: LISTMONK_ADMIN_USER -> LISTMONK_ADMIN_USER_FILE=/path/to/file_with_value
   
   x-db-credentials: &db-credentials                             # Use the default POSTGRES_ credentials if they're available or simply default to "listmonk"
     POSTGRES_USER: &db-user listmonk                            # for database user, password, and database name
     POSTGRES_PASSWORD: &db-password listmonk
     POSTGRES_DB: &db-name listmonk
   
   services:
     # listmonk app
     app:
       image: listmonk/listmonk:latest
       container_name: listmonk_app
       restart: unless-stopped
       ports:
         - "9000:9000"                                           # To change the externally exposed port, change to: $custom_port:9000
       networks:
         - listmonk
       hostname: listmonk.example.com                            # Recommend using FQDN for hostname
       depends_on:
         - db
       command: [sh, -c, "./listmonk --install --idempotent --yes --config '' && ./listmonk --upgrade --yes --config '' && ./listmonk --config ''"]
                                                                 # --config (file) param is set to empty so that listmonk only uses the env vars (below) for config.
                                                                 # --install --idempotent ensures that DB installation happens only once on an empty DB, on the first ever start.
                                                                 # --upgrade automatically runs any DB migrations when a new image is pulled.
   
       environment:                                              # The same params as in config.toml are passed as env vars here.
         LISTMONK_app__address: 0.0.0.0:9000
         LISTMONK_db__user: *db-user
         LISTMONK_db__password: *db-password
         LISTMONK_db__database: *db-name
         LISTMONK_db__host: db
         LISTMONK_db__port: 5432
         LISTMONK_db__ssl_mode: disable
         LISTMONK_db__max_open: 25
         LISTMONK_db__max_idle: 25
         LISTMONK_db__max_lifetime: 300s
         TZ: Etc/UTC
         LISTMONK_ADMIN_USER: ${LISTMONK_ADMIN_USER:-}           # If these (optional) are set during the first `docker compose up`, then the Super Admin user is automatically created.
         LISTMONK_ADMIN_PASSWORD: ${LISTMONK_ADMIN_PASSWORD:-}   # Otherwise, the user can be setup on the web app after the first visit to http://localhost:9000
       volumes:
         - ./uploads:/listmonk/uploads:rw                        # Mount an uploads directory on the host to /listmonk/uploads inside the container.
                                                                 # To use this, change directory path in Admin -> Settings -> Media to /listmonk/uploads
   
     # Postgres database
     db:
       image: postgres:17-alpine
       container_name: listmonk_db
       restart: unless-stopped
       ports:
         - "127.0.0.1:5432:5432"                                 # Only bind on the local interface. To connect to Postgres externally, change this to 0.0.0.0
       networks:
         - listmonk
       environment:
         <<: *db-credentials
       healthcheck:
         test: ["CMD-SHELL", "pg_isready -U listmonk"]
         interval: 10s
         timeout: 5s
         retries: 6
       volumes:
         - type: volume
           source: listmonk-data
           target: /var/lib/postgresql/data
   
   networks:
     listmonk:
   
   volumes:
     listmonk-data:
   ```

3. Start it ([source](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/docker-compose.yml))

   ```bash
   docker compose up -d
   ```

4. Open the app ([source](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/docker-compose.yml))

   ```text
   Open http://localhost:9000. The compose file publishes host port 9000 for the app service.
   ```

Compose file check: config_ok on 2026-10-22.

## Gotchas and maintenance

### Gotchas

- Some images use the latest tag or no tag: Images without a pinned version: app: listmonk/listmonk:latest. A later pull can get a different version. ([source](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/docker-compose.yml), checked 2026-10-22)
- The compose file publishes host ports: Host ports: 9000 (app), 127.0.0.1:5432 (db). A port without a host address listens on all host network interfaces. ([source](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/docker-compose.yml), checked 2026-10-22)
- The compose file mounts host folders: Host paths mounted into containers: ./uploads at /listmonk/uploads (app). ([source](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/docker-compose.yml), checked 2026-10-22)

### Signals

Computed from a GitHub snapshot taken 2026-10-22.

- Open issues and pull requests: 59
- Stars: 23908, forks: 2711
- Last push: 2026-10-22 (0 days ago)
- Latest release: v7.0.0-beta.1 on 2026-10-20 (1 days ago)

## Sources

- [Repository: https://github.com/knadh/listmonk](https://github.com/knadh/listmonk)
- [License: https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/LICENSE](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/LICENSE)
- [Business model: https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/README.md](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/README.md)
- [Compose file: https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/docker-compose.yml](https://github.com/knadh/listmonk/blob/9351a3ef86e2c06aacdd98ca5ae839ef888f0f9e/docker-compose.yml)

---
Canonical: https://openlogs.fyi/tools/listmonk  
Last updated: 2026-10-22
