diff --git a/public/templates/listmonk.png b/public/templates/listmonk.png new file mode 100644 index 000000000..cd6f5618e Binary files /dev/null and b/public/templates/listmonk.png differ diff --git a/templates/listmonk/docker-compose.yml b/templates/listmonk/docker-compose.yml new file mode 100644 index 000000000..e17b76577 --- /dev/null +++ b/templates/listmonk/docker-compose.yml @@ -0,0 +1,56 @@ +services: + db: + image: postgres:13 + ports: + - 5432 + networks: + - dokploy-network + environment: + - POSTGRES_PASSWORD=listmonk + - POSTGRES_USER=listmonk + - POSTGRES_DB=listmonk + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "pg_isready -U listmonk"] + interval: 10s + timeout: 5s + retries: 6 + volumes: + - listmonk-data:/var/lib/postgresql/data + + setup: + image: listmonk/listmonk:v3.0.0 + networks: + - dokploy-network + volumes: + - ./config.toml:/listmonk/config.toml + depends_on: + - db + command: [sh, -c, "sleep 3 && ./listmonk --install --idempotent --yes --config config.toml"] + + app: + restart: unless-stopped + image: listmonk/listmonk:v3.0.0 + ports: + - "${LISTMONK_PORT}" + networks: + - dokploy-network + environment: + - TZ=Etc/UTC + depends_on: + - db + - setup + volumes: + - ./config.toml:/listmonk/config.toml + labels: + - "traefik.enable=true" + - "traefik.http.routers.${HASH}.rule=Host(`${LISTMONK_HOST}`)" + - "traefik.http.services.${HASH}.loadbalancer.server.port=${LISTMONK_PORT}" + +volumes: + listmonk-data: + driver: local + +networks: + dokploy-network: + external: true diff --git a/templates/listmonk/index.ts b/templates/listmonk/index.ts new file mode 100644 index 000000000..e9df62223 --- /dev/null +++ b/templates/listmonk/index.ts @@ -0,0 +1,52 @@ +import { + generateHash, + generateRandomDomain, + type Template, + type Schema, + generatePassword, +} from "../utils"; + +export function generate(schema: Schema): Template { + const mainServiceHash = generateHash(schema.projectName); + const randomDomain = generateRandomDomain(schema); + const adminPassword = generatePassword(32); + + const envs = [ + `LISTMONK_HOST=${randomDomain}`, + "LISTMONK_PORT=9000", + `HASH=${mainServiceHash}`, + `# login with admin:${adminPassword}`, + "# check config.toml in Advanced / Volumes for more options", + ]; + + const mounts: Template["mounts"] = [ + { + mountPath: "./config.toml", + content: `[app] +address = "0.0.0.0:9000" + +admin_username = "admin" +admin_password = "${adminPassword}" + +[db] +host = "db" +port = 5432 +user = "listmonk" +password = "listmonk" +database = "listmonk" + +ssl_mode = "disable" +max_open = 25 +max_idle = 25 +max_lifetime = "300s" + +params = "" +`, + }, + ]; + + return { + envs, + mounts, + }; +} diff --git a/templates/templates.ts b/templates/templates.ts index 687576ddc..b41a2028b 100644 --- a/templates/templates.ts +++ b/templates/templates.ts @@ -332,6 +332,20 @@ export const templates: TemplateData[] = [ tags: ['chat'], load: () => import('./open-webui/index').then((m) => m.generate), }, + { + id: 'listmonk', + name: 'Listmonk', + version: 'v3.0.0', + description: 'High performance, self-hosted, newsletter and mailing list manager with a modern dashboard.', + logo: 'listmonk.png', + links: { + github: 'https://github.com/knadh/listmonk', + website: 'https://listmonk.app/', + docs: 'https://listmonk.app/docs/', + }, + tags: ['email', 'newsletter', 'mailing-list'], + load: () => import('./listmonk/index').then((m) => m.generate), + }, { id: 'doublezero', name: 'Double Zero',