mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-29 15:06:26 +02:00
Huge role refactoring/cleanup. Other commits will propably follow. Because some bugs will exist. Still important for longrun and also for auto docs/help/slideshow generation
This commit is contained in:
14
roles/web-app-listmonk/Installation.md
Normal file
14
roles/web-app-listmonk/Installation.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Installation and Configuration
|
||||
|
||||
## Initial Database Setup
|
||||
After the first setup, run the following command to initialize the Listmonk database:
|
||||
```bash
|
||||
docker compose run --rm application ./listmonk --install
|
||||
```
|
||||
|
||||
## Start Services
|
||||
|
||||
Use the following command to start Listmonk services:
|
||||
```bash
|
||||
docker-compose -p listmonk up -d --force-recreate
|
||||
```
|
25
roles/web-app-listmonk/README.md
Normal file
25
roles/web-app-listmonk/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Listmonk
|
||||
|
||||
## Description
|
||||
|
||||
Elevate your email marketing with Listmonk, a high-performance, self-hosted newsletter and mailing list manager featuring a modern, intuitive dashboard. Listmonk empowers you with advanced analytics, efficient subscriber segmentation, and streamlined campaign management—all configurable via a flexible TOML configuration file.
|
||||
|
||||
## Overview
|
||||
|
||||
This role deploys Listmonk using Docker, ensuring a robust and scalable setup for your newsletter management needs. Listmonk’s architecture supports a dedicated PostgreSQL database and integration with an NGINX reverse proxy for secure access. To configure and manage your instance, use the provided configuration files:
|
||||
- [Installation.md](./Installation.md)
|
||||
- [Upgrade.md](./Upgrade.md)
|
||||
|
||||
## Features
|
||||
|
||||
- **High Performance:** Optimized for handling large-scale mailing lists and newsletters with rapid processing.
|
||||
- **Modern Dashboard:** Enjoy a sleek, user-friendly interface for managing campaigns and analyzing performance.
|
||||
- **Advanced Analytics:** Gain insights through detailed reporting on campaign metrics and subscriber behavior.
|
||||
- **Flexible Configuration:** Easily customize settings such as database connections, admin credentials, and server configurations via a TOML file.
|
||||
- **Robust Infrastructure:** Seamlessly integrates with PostgreSQL for reliable data management and supports deployment behind a reverse proxy.
|
||||
|
||||
## Further Resources
|
||||
|
||||
- [Listmonk Official Website](https://listmonk.app/)
|
||||
- [Listmonk Installation Documentation](https://listmonk.app/docs/installation/)
|
||||
- [Listmonk GitHub Repository](https://github.com/knadh/listmonk/)
|
5
roles/web-app-listmonk/Upgrade.md
Normal file
5
roles/web-app-listmonk/Upgrade.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Upgrade
|
||||
|
||||
```bash
|
||||
docker compose run application ./listmonk --upgrade
|
||||
```
|
3
roles/web-app-listmonk/files/deactivate-public-api.conf
Normal file
3
roles/web-app-listmonk/files/deactivate-public-api.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
location /api/public/subscription {
|
||||
return 403;
|
||||
}
|
25
roles/web-app-listmonk/meta/main.yml
Normal file
25
roles/web-app-listmonk/meta/main.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
galaxy_info:
|
||||
author: "Kevin Veen-Birkenbach"
|
||||
description: "Elevate your email marketing with Listmonk, a high-performance, self-hosted newsletter and mailing list manager featuring a modern dashboard, advanced analytics, and flexible configuration options."
|
||||
license: "CyMaIS NonCommercial License (CNCL)"
|
||||
license_url: "https://s.veen.world/cncl"
|
||||
company: |
|
||||
Kevin Veen-Birkenbach
|
||||
Consulting & Coaching Solutions
|
||||
https://www.veen.world
|
||||
galaxy_tags:
|
||||
- listmonk
|
||||
- docker
|
||||
- newsletter
|
||||
- email marketing
|
||||
- self-hosted
|
||||
repository: "https://s.veen.world/cymais"
|
||||
issue_tracker_url: "https://s.veen.world/cymaisissues"
|
||||
documentation: "https://s.veen.world/cymais"
|
||||
logo:
|
||||
class: "fa-solid fa-list"
|
||||
run_after:
|
||||
- web-app-matomo
|
||||
- web-app-keycloak
|
||||
- web-app-mailu
|
15
roles/web-app-listmonk/meta/schema.yml
Normal file
15
roles/web-app-listmonk/meta/schema.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
credentials:
|
||||
administrator_password:
|
||||
description: "Initial password for the Listmonk administrator account"
|
||||
algorithm: "sha256"
|
||||
validation: "^[a-f0-9]{64}$"
|
||||
|
||||
hcaptcha_site_key:
|
||||
description: "Public site key used by Listmonk to render hCaptcha"
|
||||
algorithm: "plain"
|
||||
validation: "^[0-9a-zA-Z_-]{32,}$"
|
||||
|
||||
hcaptcha_secret:
|
||||
description: "Private hCaptcha secret key for server-side verification"
|
||||
algorithm: "plain"
|
||||
validation: "^[0-9a-zA-Z_-]{32,}$"
|
11
roles/web-app-listmonk/meta/users.yml
Normal file
11
roles/web-app-listmonk/meta/users.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
users:
|
||||
administrator:
|
||||
username: "administrator"
|
||||
bounce:
|
||||
username: "bounce"
|
||||
roles:
|
||||
- mail-bot
|
||||
newsletter:
|
||||
username: "newsletter"
|
||||
roles:
|
||||
- mail-bot
|
79
roles/web-app-listmonk/tasks/main.yml
Normal file
79
roles/web-app-listmonk/tasks/main.yml
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
- name: "include service-rdbms-central"
|
||||
include_role:
|
||||
name: service-rdbms-central
|
||||
|
||||
- name: Set nginx_docker_reverse_proxy_extra_configuration based on applications[application_id].public_api_activated
|
||||
set_fact:
|
||||
nginx_docker_reverse_proxy_extra_configuration: >-
|
||||
{% if not applications[application_id].public_api_activated %}
|
||||
{{ lookup('file', '{{ role_path }}/files/deactivate-public-api.conf') }}
|
||||
{% else %}
|
||||
""
|
||||
{% endif %}
|
||||
|
||||
- name: "include role webserver-proxy-domain for {{application_id}}"
|
||||
include_role:
|
||||
name: webserver-proxy-domain
|
||||
vars:
|
||||
domain: "{{ domains | get_domain(application_id) }}"
|
||||
http_port: "{{ ports.localhost.http[application_id] }}"
|
||||
|
||||
- name: add config.toml
|
||||
template:
|
||||
src: "config.toml.j2"
|
||||
dest: "{{docker_compose.directories.config}}config.toml"
|
||||
notify: docker compose up
|
||||
|
||||
- name: Check if listmonk database is already initialized
|
||||
command: docker compose exec -T {{database_host}} psql -U {{database_username}} -d {{database_name}} -c "\dt"
|
||||
register: db_tables
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Run Listmonk setup only if DB is empty
|
||||
command:
|
||||
cmd: docker compose run -T --rm application sh -c "yes | ./listmonk --install"
|
||||
chdir: "{{docker_compose.directories.instance}}"
|
||||
when: "'No relations found.' in db_tables.stdout"
|
||||
|
||||
- name: Build OIDC settings JSON
|
||||
set_fact:
|
||||
oidc_settings_json: >-
|
||||
{{ {
|
||||
"enabled": True,
|
||||
"client_id": oidc.client.id,
|
||||
"provider_url": oidc.client.issuer_url,
|
||||
"client_secret": oidc.client.secret
|
||||
} | to_json }}
|
||||
|
||||
- name: Update administrator email and password login in Listmonk
|
||||
shell: |
|
||||
docker exec -i {{ database_host }} psql \
|
||||
-U {{ database_username }} \
|
||||
-v ON_ERROR_STOP=1 \
|
||||
-d {{ database_name }} << 'EOSQL'
|
||||
UPDATE users
|
||||
SET email = '{{ users.administrator.email }}',
|
||||
password_login = {{ 'false' if applications[application_id].features.oidc else 'true' }}
|
||||
WHERE username = 'administrator';
|
||||
EOSQL
|
||||
args:
|
||||
executable: /bin/bash
|
||||
|
||||
- name: Apply all Listmonk settings
|
||||
shell: |
|
||||
docker exec -i {{ database_host }} psql \
|
||||
-U {{ database_username }} \
|
||||
-v ON_ERROR_STOP=1 \
|
||||
-d {{ database_name }} << 'EOSQL'
|
||||
UPDATE settings
|
||||
SET value = '{{ item.value }}'::jsonb
|
||||
WHERE key = '{{ item.key }}';
|
||||
EOSQL
|
||||
args:
|
||||
executable: /bin/bash
|
||||
loop: "{{ listmonk_settings }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
when: item.when is not defined or item.when
|
24
roles/web-app-listmonk/templates/config.toml.j2
Normal file
24
roles/web-app-listmonk/templates/config.toml.j2
Normal file
@@ -0,0 +1,24 @@
|
||||
[app]
|
||||
# Interface and port where the application will run its webserver. The default value
|
||||
# of localhost will only listen to connections from the current machine. To
|
||||
# listen on all interfaces use '0.0.0.0'. To listen on the default web address
|
||||
# port, use port 80 (this will require running with elevated permissions).
|
||||
address = "0.0.0.0:{{ container_port }}"
|
||||
|
||||
# Database.
|
||||
[db]
|
||||
host = "{{database_host}}"
|
||||
port = {{database_port}}
|
||||
user = "{{database_username}}"
|
||||
password = "{{database_password}}"
|
||||
|
||||
# Ensure that this database has been created in Postgres.
|
||||
database = "{{database_name}}"
|
||||
|
||||
ssl_mode = "disable"
|
||||
max_open = 25
|
||||
max_idle = 25
|
||||
max_lifetime = "300s"
|
||||
|
||||
# Optional space separated Postgres DSN params. eg: "application_name=listmonk gssencmode=disable"
|
||||
params = ""
|
16
roles/web-app-listmonk/templates/docker-compose.yml.j2
Normal file
16
roles/web-app-listmonk/templates/docker-compose.yml.j2
Normal file
@@ -0,0 +1,16 @@
|
||||
{% include 'roles/docker-compose/templates/base.yml.j2' %}
|
||||
application:
|
||||
{% set container_healthcheck = 'health' %}
|
||||
{% include 'roles/docker-container/templates/base.yml.j2' %}
|
||||
image: "{{ applications[application_id].images.listmonk }}"
|
||||
ports:
|
||||
- "127.0.0.1:{{ports.localhost.http[application_id]}}:{{ container_port }}"
|
||||
volumes:
|
||||
- {{docker_compose.directories.config}}config.toml:/listmonk/config.toml
|
||||
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
|
||||
{% include 'roles/docker-container/templates/healthcheck/wget.yml.j2' %}
|
||||
|
||||
{% include 'roles/docker-compose/templates/volumes-just-database.yml.j2' %}
|
||||
|
||||
{% include 'roles/docker-compose/templates/networks.yml.j2' %}
|
6
roles/web-app-listmonk/templates/env.j2
Normal file
6
roles/web-app-listmonk/templates/env.j2
Normal file
@@ -0,0 +1,6 @@
|
||||
TZ={{ HOST_TIMEZONE }}
|
||||
|
||||
# Administrator setup
|
||||
|
||||
LISTMONK_ADMIN_USER={{ applications[application_id].users.administrator.username }}
|
||||
LISTMONK_ADMIN_PASSWORD={{ applications[application_id].credentials.administrator_password }}
|
17
roles/web-app-listmonk/vars/configuration.yml
Normal file
17
roles/web-app-listmonk/vars/configuration.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
images:
|
||||
listmonk: "listmonk/listmonk:latest"
|
||||
public_api_activated: False # Security hole. Can be used for spaming
|
||||
version: "latest" # Docker Image version
|
||||
features:
|
||||
matomo: true
|
||||
css: false
|
||||
portfolio_iframe: true
|
||||
central_database: true
|
||||
oidc: true
|
||||
domains:
|
||||
canonical:
|
||||
- "newsletter.{{ primary_domain }}"
|
||||
docker:
|
||||
services:
|
||||
database:
|
||||
enabled: true
|
221
roles/web-app-listmonk/vars/main.yml
Normal file
221
roles/web-app-listmonk/vars/main.yml
Normal file
@@ -0,0 +1,221 @@
|
||||
application_id: "listmonk"
|
||||
database_type: "postgres"
|
||||
container_port: "9000"
|
||||
|
||||
listmonk_settings:
|
||||
- key: "app.root_url"
|
||||
value: '"{{ domains | get_url(application_id, web_protocol) }}"'
|
||||
|
||||
- key: "app.notify_emails"
|
||||
value: "{{ [ users.administrator.email ] | to_json }}"
|
||||
|
||||
# OIDC integration (conditional)
|
||||
- key: "security.oidc"
|
||||
value: >-
|
||||
{{ {
|
||||
"enabled": True,
|
||||
"client_id": oidc.client.id,
|
||||
"provider_url": oidc.client.issuer_url,
|
||||
"client_secret": oidc.client.secret
|
||||
} | to_json }}
|
||||
when: applications | is_feature_enabled('oidc',application_id)
|
||||
|
||||
# hCaptcha toggles and credentials
|
||||
- key: "security.enable_captcha"
|
||||
value: 'true'
|
||||
|
||||
- key: "security.captcha_key"
|
||||
value: '"{{ applications[application_id].credentials.hcaptcha_site_key }}"'
|
||||
|
||||
- key: "security.captcha_secret"
|
||||
value: '"{{ applications[application_id].credentials.hcaptcha_secret }}"'
|
||||
|
||||
# SMTP servers
|
||||
- key: "smtp"
|
||||
value: >-
|
||||
{{ [
|
||||
{
|
||||
"host": system_email.host,
|
||||
"port": system_email.port,
|
||||
"enabled": system_email.smtp,
|
||||
"username": "no-reply",
|
||||
"password": users['no-reply'].email,
|
||||
"tls_type": (
|
||||
system_email.tls
|
||||
| ternary("TLS",
|
||||
system_email.start_tls
|
||||
| ternary("STARTTLS","NONE")
|
||||
)
|
||||
),
|
||||
"email_headers": [],
|
||||
"hello_hostname": "",
|
||||
"max_conns": 10,
|
||||
"idle_timeout": "15s",
|
||||
"wait_timeout": "5s",
|
||||
"auth_protocol": "login",
|
||||
"max_msg_retries": 2,
|
||||
"tls_skip_verify": false
|
||||
}
|
||||
] | to_json }}
|
||||
when: system_email.smtp | bool
|
||||
|
||||
|
||||
- key: "app.lang"
|
||||
value: '"{{ HOST_LL }}"'
|
||||
|
||||
# - key: "messengers"
|
||||
# value: '[]'
|
||||
|
||||
- key: "app.logo_url"
|
||||
value: '"{{ service_provider.platform.logo }}"'
|
||||
when: service_provider.platform.logo | bool
|
||||
|
||||
- key: "app.site_name"
|
||||
value: '"{{ service_provider.company.titel }} Mailing list"'
|
||||
|
||||
# Enable the bounce module
|
||||
- key: "bounce.enabled"
|
||||
value: 'true'
|
||||
|
||||
# Configure POP3 mailbox for processing bounces
|
||||
- key: "bounce.mailboxes"
|
||||
value: >-
|
||||
{{ [
|
||||
{
|
||||
"host": system_email.host,
|
||||
"port": system_email.port,
|
||||
"type": "pop",
|
||||
"uuid": "471fd0e9-8c33-4e4a-9183-c4679699faca",
|
||||
"enabled": true,
|
||||
"username": users.bounce.email,
|
||||
"password": users.bounce.mailu_token,
|
||||
"return_path": users.bounce.email,
|
||||
"tls_enabled": system_email.tls,
|
||||
"auth_protocol": "userpass",
|
||||
"scan_interval": "15m",
|
||||
"tls_skip_verify": false
|
||||
}
|
||||
] | to_json }}
|
||||
|
||||
#
|
||||
# - key: "upload.max_file_size"
|
||||
# value: '5000'
|
||||
#
|
||||
# - key: "upload.s3.aws_secret_access_key"
|
||||
# value: '""'
|
||||
#
|
||||
# - key: "app.batch_size"
|
||||
# value: '1000'
|
||||
|
||||
- key: "app.from_email"
|
||||
value: '"{{ service_provider.company.titel }} Newsletter <{{ users["no-reply"].email }}>"'
|
||||
|
||||
# - key: "bounce.actions"
|
||||
# value: >-
|
||||
# {"hard": {"count": 1, "action": "blocklist"}, "soft": {"count": 2, "action": "none"}, "complaint": {"count": 1, "action": "blocklist"}}
|
||||
#
|
||||
# - key: "app.concurrency"
|
||||
# value: '10'
|
||||
|
||||
- key: "app.favicon_url"
|
||||
value: '"{{ service_provider.platform.favicon }}"'
|
||||
when: service_provider.platform.favicon | bool
|
||||
|
||||
# - key: "bounce.postmark"
|
||||
# value: '{"enabled": false, "password": "", "username": ""}'
|
||||
#
|
||||
# - key: "upload.provider"
|
||||
# value: '"filesystem"'
|
||||
|
||||
# - key: "app.message_rate"
|
||||
# value: '10'
|
||||
#
|
||||
# - key: "bounce.mailboxes"
|
||||
# value: >-
|
||||
# [{"host": "pop.yoursite.com", "port": 995, "type": "pop", "uuid": "471fd0e9-8c33-4e4a-9183-c4679699faca", "enabled": false, "password": "password", "username": "username", "return_path": "bounce@listmonk.yoursite.com", "tls_enabled": true, "auth_protocol": "userpass", "scan_interval": "15m", "tls_skip_verify": false}]
|
||||
|
||||
# - key: "upload.s3.url"
|
||||
# value: '"https://ap-south-1.s3.amazonaws.com"'
|
||||
#
|
||||
# - key: "upload.s3.bucket"
|
||||
# value: '""'
|
||||
#
|
||||
# - key: "upload.s3.expiry"
|
||||
# value: '"167h"'
|
||||
|
||||
- key: "app.check_updates"
|
||||
value: 'true'
|
||||
|
||||
|
||||
# - key: "upload.extensions"
|
||||
# value: '["jpg", "jpeg", "png", "gif", "svg", "*"]'
|
||||
#
|
||||
# - key: "bounce.ses_enabled"
|
||||
# value: 'false'
|
||||
#
|
||||
# - key: "privacy.allow_wipe"
|
||||
# value: 'true'
|
||||
#
|
||||
# - key: "privacy.exportable"
|
||||
# value: '["profile", "subscriptions", "campaign_views", "link_clicks"]'
|
||||
#
|
||||
# - key: "app.max_send_errors"
|
||||
# value: '1000'
|
||||
#
|
||||
# - key: "bounce.forwardemail"
|
||||
# value: '{"key": "", "enabled": false}'
|
||||
#
|
||||
# - key: "bounce.sendgrid_key"
|
||||
# value: '""'
|
||||
#
|
||||
# - key: "privacy.allow_export"
|
||||
# value: 'true'
|
||||
#
|
||||
# - key: "upload.s3.public_url"
|
||||
# value: '""'
|
||||
#
|
||||
# - key: "upload.s3.bucket_path"
|
||||
# value: '"/"'
|
||||
#
|
||||
# - key: "upload.s3.bucket_type"
|
||||
# value: '"public"'
|
||||
#
|
||||
# - key: "app.cache_slow_queries"
|
||||
# value: 'false'
|
||||
#
|
||||
# - key: "bounce.sendgrid_enabled"
|
||||
# value: 'false'
|
||||
#
|
||||
# - key: "bounce.webhooks_enabled"
|
||||
# value: 'false'
|
||||
#
|
||||
# - key: "privacy.domain_blocklist"
|
||||
# value: '[]'
|
||||
#
|
||||
# - key: "privacy.allow_blocklist"
|
||||
# value: 'true'
|
||||
#
|
||||
# - key: "privacy.record_optin_ip"
|
||||
# value: 'false'
|
||||
#
|
||||
# - key: "app.enable_public_archive"
|
||||
# value: 'true'
|
||||
#
|
||||
# - key: "privacy.allow_preferences"
|
||||
# value: 'true'
|
||||
#
|
||||
# - key: "app.message_sliding_window"
|
||||
# value: 'false'
|
||||
#
|
||||
# - key: "app.message_sliding_window_rate"
|
||||
# value: '10000'
|
||||
#
|
||||
# - key: "app.enable_public_subscription_page"
|
||||
# value: 'true'
|
||||
#
|
||||
# - key: "app.message_sliding_window_duration"
|
||||
# value: '"1h"'
|
||||
|
||||
- key: "app.enable_public_archive_rss_content"
|
||||
value: 'true'
|
||||
|
Reference in New Issue
Block a user