Token is generated once and kept in Secret listmonk-newsletter-api. Tested: create, test-send and schedule work; subscribers/settings 403. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
77 lines
4.3 KiB
Markdown
77 lines
4.3 KiB
Markdown
# ansible-role-listmonk
|
|
|
|
Deploys [listmonk](https://listmonk.app) v6.2.0, the eom.dev newsletter, to Kubernetes.
|
|
|
|
It fits in with the rest of eom.dev:
|
|
|
|
- **Login** goes through Dex (`listmonk` static client) with the same "eom.dev account" button as the other services. Only e-mail addresses listed in `listmonk_oidc_admins` can sign in, so being a member is not enough to get into the admin UI. A password login for the `admin` user is kept as a fallback.
|
|
- **Mail** goes out through `postfix.eom.dev:587` as the LDAP account `news`, the same way Gitea, Nextcloud and PeerTube send mail.
|
|
- **Look**: the public pages (subscribe, archive, preferences, unsubscribe) use the Catppuccin Mocha/Latte palette from `dex.eom.dev`, along with the eom.dev logo and favicon.
|
|
- **Cluster conventions**: `ca-issuer` TLS, `nfs-client` volumes, and anti-affinity that keeps the pods off the ingress-nginx node.
|
|
|
|
## What it creates
|
|
|
|
| Object | Purpose |
|
|
| --- | --- |
|
|
| `Secret/listmonk` | DB password and bootstrap admin credentials |
|
|
| `StatefulSet/listmonk-db` | PostgreSQL 17 (alpine, uid 70) on `nfs-client` |
|
|
| `Deployment/listmonk` | Runs `--install --idempotent`, then `--upgrade`, then serves on :9000 |
|
|
| `PVC/listmonk-uploads` | Media uploaded for campaigns |
|
|
| `Ingress/listmonk` | `https://listmonk.eom.dev` |
|
|
|
|
listmonk keeps most of its configuration in the `settings` table, not in a config file. The role writes those settings with an idempotent SQL script (`templates/configure.sql.j2`) that it runs in the database pod. The script covers SMTP, Dex, theme, captcha, privacy, the Dex admin users and the lists in `listmonk_lists`. On the first run it also removes listmonk's sample data. listmonk is restarted only when a row actually changes.
|
|
|
|
Settings the role manages are reset on every run. Change them in `defaults/main.yml` or `listmonk_settings_extra`, not in the UI. Everything else, including templates, campaigns and subscribers, stays under the UI's control.
|
|
|
|
## Required variables (Vault)
|
|
|
|
| Variable | Notes |
|
|
| --- | --- |
|
|
| `listmonk_db_password` | 16+ chars. Only used when the volume is first initialised |
|
|
| `listmonk_admin_password` | 8+ chars, for the `admin` fallback login |
|
|
| `listmonk_smtp_password` | Password of the `news` LDAP account |
|
|
| `listmonk_oidc_client_secret` | Must match the `listmonk` client in Dex |
|
|
|
|
The eom.dev playbook maps them from the Vault names `listmonk_postgresql_password`, `listmonk_admin_password`, `listmonk_smtp_password` and `listmonk_dex_client_secret`.
|
|
|
|
## One-time setup outside this role
|
|
|
|
1. In LDAP, create the posix account `news` with `mail: news@eom.dev` and add it to `cn=Postfix Users,ou=Postfix,ou=Services,dc=eom,dc=dev`. Its password is `listmonk_smtp_password`.
|
|
2. Add the `listmonk` client to Dex (`ericomeehan.dex/playbooks/deploy-eom.yml`) and run that play.
|
|
|
|
## API users
|
|
|
|
| User | Can do | Token |
|
|
| --- | --- | --- |
|
|
| `membership` | Read and manage subscribers on `eom.dev` (signup opt-in, profile toggle) | `listmonk_api_token` (Vault); same value as `LISTMONK_API_TOKEN` in the www `membership` Secret |
|
|
| `newsletter` | Create, edit, test-send and schedule campaigns to `eom.dev`; no subscriber data or settings | Generated by the role, stored in `Secret/listmonk-newsletter-api` (`url`, `username`, `token`) |
|
|
|
|
Neither user can read settings or other lists. To rotate the newsletter token, delete its Secret and run the play again.
|
|
|
|
## Embedding a signup form
|
|
|
|
listmonk accepts a plain HTML POST, so any eom.dev page can include a form:
|
|
|
|
```html
|
|
<form method="post" action="https://listmonk.eom.dev/subscription/form">
|
|
<input type="hidden" name="nonce">
|
|
<input type="email" name="email" required placeholder="you@example.com">
|
|
<input type="hidden" name="l" value="LIST-UUID">
|
|
<button type="submit">Subscribe</button>
|
|
</form>
|
|
```
|
|
|
|
Copy the list UUID from **Lists → eom.dev → Forms** in the admin UI. The form uses double opt-in, so subscribers have to confirm by e-mail. The page at `https://listmonk.eom.dev/subscription/form` adds an Altcha proof-of-work captcha.
|
|
|
|
## Testing
|
|
|
|
```sh
|
|
ansible-playbook -i tests/inventory tests/render.yml # renders into .render/
|
|
```
|
|
|
|
This version was tested against `listmonk/listmonk:v6.2.0` and `postgres:17.11-alpine`. The SQL changes 12 settings, 1 user, 1 list and the sample data on the first run, and nothing on the second.
|
|
|
|
## License
|
|
|
|
MIT-0
|