Mailman 3 installieren

Aus Hostsharing Wiki
Zur Navigation springen Zur Suche springen

Die folgende Anleitung zur Installation von Mailman 3 auf Hostsharing geht davon aus, dass als Domäne lists.example.org und als Domänennutzer xyz00-lists verwendet wird. Es ist zu empfehlen, auszuführende Befehle und Konfigurationen vorab auf zu ersetzende Werte zu prüfen. Alle Befehle sind als Benutzer xyz00-lists zu starten. Damit mehrere aufeinander folgende Shell-Kommandos leichter kopiert werden können, wird nur vor das jeweils erste Kommando ein $ gesetzt. Zum Verständnis mancher der folgenden Anweisungen kann es hilfreich sein, die Mailman-Dokumentation gelesen und sich mit Pipenv beschäftigt zu haben.

Achtung: Mailman 3 benötigt zahlreiche Hintergrundprozesse, was beim Managed Webspace zusätzliche Kosten verursacht.

Datenbank

Zunächst muss eine PostgreSQL- oder MySQL-Datenbank angelegt werden. (Mailman läuft auch mit SQLite, ist aber für den Produktivbetrieb nicht empfohlen.) Je nach gewählter Datenbank unterscheiden sich manche Schritte geringfügig, was an den entsprechenden Stellen dokumentiert ist.

Mailman Core

Für die Installation von Mailman Core sind folgende Kommandos auszuführen:

$ pip3 install --user pipenv
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.profile
source ~/.profile
mkdir ~/mailman
cd ~/mailman
pipenv install mailman mailman-hyperkitty
pipenv install psycopg2-binary # Für PostgreSQL
pipenv install pymsql # Für MySQL

Anschließend wird das Verzeichnis für die Konfigurationsdatei angelegt:

$ mkdir -p ~/mailman/var/etc

Die Konfiguration wird in die Datei ~/mailman/var/etc/mailman.cfg geschrieben:

[mailman]
site_owner: admin@example.org
default_language: de

[database] # https://mailman.readthedocs.io/en/latest/src/mailman/docs/database.html
class: mailman.database.postgresql.PostgreSQLDatabase
url: postgres://myuser:mypassword@mypghost/mailman
# Fallls MySQL verwendet:
#class: mailman.database.mysql.MySQLDatabase
#url: mysql+pymysql://myuser:mypassword@mymysqlhost/mailman?charset=utf8&use_unicode=1
# SQLite ist Standard, wenn nichts konfiguriert ist

[webservice] # REST Service von Mailman. Wird von Web Frontend verwendet
port: 8001 # ändern, falls belegt
admin_user: restadmin
admin_pass: restpass

[mta]
smtp_host: xyz00.hostsharing.net
smtp_port: 4587
smtp_user: xyz00-lists
smtp_pass: secret
smtp_secure_mode: starttls
# VERP ist nicht möglich, da MTA nicht selbst konfiguriert werden kann
verp_confirm_format: $address
# https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html
# NullMTA, da MTA nicht selbst konfiguriert werden kann
incoming: mailman.mta.null.NullMTA
lmtp_port: 8024 # ändern, falls belegt

[runner.nntp]
# Runner für NNTP Gateway ausschalten 
start: no

[archiver.hyperkitty]
class: mailman_hyperkitty.Archiver
enable: yes
# $HOME muss durch den tatsächlichen Pfad zum Benutzerverzeichnis ersetzt werden
configuration: $HOME/mailman/var/etc/mailman-hyperkitty.cfg

Zugriffsrechte einschränken:

$ chmod 0600 ~/mailman/var/etc/mailman.cfg

Damit Hyperkitty als Web Frontend für das Archiv verwendet werden kann, ist in die Datei ~/mailman/var/etc/mailman-hyperkitty.cfg Foglendes zu schreiben:

[general]
base_url: https://lists.example.org/hyperkitty/
# Muss identisch mit Key in Hyperkitty sein
api_key: SecretArchiverAPIKey

Zugriffsrechte einschränken:

$ chmod 0600 ~/mailman/var/etc/mailman-hyperkitty.cfg

Kommando mailman anlegen:

$ cat <<'EOD' >~/.local/bin/mailman
#!/bin/sh

cd ~/mailman
pipenv run mailman "$@"
EOD

chmod +x ~/.local/bin/mailman

Nun kann mit mailman info nochmal die aktuelle Konfiguration geprüft werden. Danach kann Mailman gestartet werden:

$ mailman start

Web Frontend

In diesem Abschnitt wird die Installation des Web Frontends beschrieben.

Zunächst werden die Redirects aus der .htaccess gelöscht:

$ echo "" > ~/doms/lists.example.org/htdocs-ssl/.htaccess

Anschließend werden die erforderlichen Python-Pakete installiert:

$ cd ~/mailman
pipenv install whoosh postorius hyperkitty

Um Plattenplatz freizugeben, kann optional der Pip Cache gelöscht werden:

$ rm -r ~/.cache/pip*

Nun werden die Dateien geladen, mit denen Postorius und Hyperkitty konfiguriert und gestartet werden:

$ git clone https://gitlab.com/mailman/mailman-suite.git

Zur Konfiguration von Hyperkitty wird die IP-Adresse benötigt, von der die Anfragen von Mailman Core kommen. Diese kann wie folgt ermittelt werden:

$ cat <<EOD >~/doms/lists.example.org/htdocs-ssl/ip.php
<?php
echo \$_SERVER['REMOTE_ADDR'] . "\n";
EOD
curl https://lists.example.org/ip.php
rm ~/doms/lists.example.org/htdocs-ssl/ip.php

Die Konfiguration wird nun in Die Datei ~/mailman/mailman-suite/mailman-suite_project/settings_local.py geschrieben:

SECRET_KEY = 'change-this-on-your-production-server'
Debug = False
ADMINS = (
     ('Mailman Suite Admin', 'admin@example.org'),
)
ALLOWED_HOSTS = [
    'lists.example.org',
]
MAILMAN_REST_API_URL = 'http://localhost:8001'
MAILMAN_REST_API_USER = 'restadmin'
MAILMAN_REST_API_PASS = 'restpass'
MAILMAN_ARCHIVER_KEY = 'SecretArchiverAPIKey'
MAILMAN_ARCHIVER_FROM = ('<IP von Mailman Core>')

# Authentifizierung über externe Dienste ausschalten (s. django-allauth)
from settings import INSTALLED_APPS
INSTALLED_APPS = filter(lambda app: not app.startswith('allauth.socialaccount.') and app != 'django_mailman3.lib.auth.fedora', INSTALLED_APPS)
INSTALLED_APPS = (
    'hyperkitty',
    'postorius',
    'django_mailman3',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'django_gravatar',
    'compressor',
    'haystack',
    'django_extensions',
    'django_q',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
)

# Standardkonfiguration verwendet SQLite
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Für MySQL: django.db.backends.mysql
        'HOST': 'localhost',
        'NAME': 'database_name',
        'USER': 'database_user',
        'PASSWORD': 'database_password',
    }
}

LANGUAGE_CODE = 'de-de'
TIME_ZONE = 'Europe/Berlin'
DEFAULT_FROM_EMAIL = 'mailing-lists@example.org'
SERVER_EMAIL = 'mailing-lists@example.org'
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'xyz00.hostsharing.net'
EMAIL_PORT = 4587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'xyz00-lists'
EMAIL_HOST_PASSWORD = 'secret'
EMAIL_TIMEOUT = 60

ACCOUNT_DEFAULT_HTTP_PROTOCOL = 'https'

COMPRESS_PRECOMPILERS = (
   ('text/less', 'lessc {infile} {outfile}'),
   ('text/x-scss', 'sass -t compressed {infile} {outfile}'),
   ('text/x-sass', 'sass -t compressed {infile} {outfile}'),
)
COMPRESS_OFFLINE = True

# Workeranzahl reduzieren (optional)
Q_CLUSTER = {
    'workers': 1,
    'timeout': 300,
    'save_limit': 100,
    'orm': 'default',
}

Hinweis: Die Einstellungen in settings_local.py überschreiben solche in settings.py. Zwar kann settings.py auch direkt angepasst werden, auf diese Weise werden jedoch mögliche Konflikte beim Update vermieden. settings.py sollte dennoch dahingehend geprüft werden, ob man ggf. weitere Optionen ändern möchte.

Das Mailman Web Frontend nutzt das Framework Django. Einige der Einstellungen sind in der Dokumentation von Django beschrieben, andere konfigurieren eine der in INSTALLED_APPS definierten Anwendungen.

Damit per Django verfügbare Kommandos leicht ausgeführt werden können, wird der Befehl mailman-django eingerichtet:

$ cat <<'EOD' >~/.local/bin/mailman-django
#!/bin/sh

cd ~/mailman
pipenv run mailman-suite/mailman-suite_project/manage.py "$@"
EOD

chmod +x ~/.local/bin/mailman-django

Anschließend können folgende Kommandos ausgeführt werden:

$ mailman-django migrate
mailman-django collectstatic
mailman-django compress
mailman-django createsuperuser

Nun müssen die statischen Dateien für das Web Frontend noch per HTTPS verfügbar gemacht werden:

$ ln -s ~/mailman/mailman-suite/mailman-suite_project/static ~/doms/lists.example.org/htdocs-ssl/

Damit das Web Frontend per Phusion Passenger geladen werden kann:

$ cat <<EOD >~/doms/lists.example.org/app-ssl/passenger_wsgi.py
import os
import subprocess
import sys

os.environ['LANG'] = 'C.UTF-8'
os.environ['LC_ALL'] = 'C.UTF-8'

HOME = os.getenv('HOME')
PIPENV = os.path.join(HOME, '.local', 'bin', 'pipenv')
PIPFILE_DIR = os.path.join(HOME, 'mailman')
INTERP = subprocess.check_output([PIPENV, 'run', 'which', 'python'], cwd=PIPFILE_DIR).strip().decode('utf-8')
if sys.executable != INTERP:
    os.execl(INTERP, INTERP, *sys.argv)

WSGI_DIR = os.path.join(HOME, 'mailman', 'mailman-suite', 'mailman-suite_project')
sys.path.append(WSGI_DIR)

from wsgi import application
EOD

Nun steht das Web Frontend unter https://lists.example.org/ zur Verfügung. Über die Django Administration sollte unter https://lists.example.org/admin/sites/site/1/change/ die Domäne angepasst werden.

Cron Jobs

Es sind verschiedene Cron Jobs erforderlich. Hierzu crontab -e ausführen und Folgendes eintragen:

# An die in MAILTO eingetragene Adressen werden Ausgaben der Cron Jobs gesendet (optional)
#MAILTO=admin@example.org
PATH=$HOME/.local/bin:$PATH

@reboot mailman start

# Send periodic digests.
@daily mailman digests --send

@reboot mailman-django qcluster
# Alternativ qcluster minütlich ausführen
# * * * * * mailman-django qcluster --run-once

* * * * * mailman-django runjobs minutely
2,17,32,47 * * * * mailman-django runjobs quarter_hourly
@hourly  mailman-django runjobs hourly
@daily   mailman-django runjobs daily
@weekly  mailman-django runjobs weekly
@monthly mailman-django runjobs monthly
@yearly  mailman-django runjobs yearly

Hinweis: Der Einfachheit halber wird hier für mailman start und qcluster @reboot verwendet. Besser wäre der Einsatz von monit. Beim Einsatz von monit würde sich auch der Neustart der Dienste nach einem Update ändern. (Anleitung gerne anpassen, sollte jemand monit einrichten.)

Mails an Mailman weiterleiten

Da die MTA-Konfiguration nicht direkt angepasst werden kann, ist ein Hilfskonstrukt erforderlich: Mittels .forward-Dateien und .promailrc werden eingehende Mails an das Programm msmtp weitergeleitet, welches diese per LMTP bei Mailman abliefert. msmtp ist auf den Managed Servern vorinstalliert. Dazu lege ich im $HOME des Users zwei Dateien an: '.forward' bekommt die Mails vom Postfix-Mailserver übergeben und leitet weiter an procmail, das über die Datei '.procmailrc' konfiguriert wird.

 ~$ cat .forward 
 "|/usr/bin/procmail -p"
 ~$ cat .procmailrc 
 SHELL=/bin/sh
 HOMEDIR=/home/pacs/xyz00/users/lists
 MAILDIR=/home/pacs/xyz00/users/lists/Maildir
 PMDIR=/home/pacs/xyz00/users/lists
 VERBOSE=yes
 LOGFILE=/home/pacs/xyz00/users/lists/var/procmail.log
 DEFAULT
 
 :0:
 * ^X-Original-To: ()\/[^@+]+
 |/usr/bin/msmtp --host=127.0.0.1 --port=8024 --protocol=lmtp --read-envelope-from ${MATCH}@lists.example.org

Die Mailadresse wird als Catchall-Adresse in HSAdmin angelegt. Bei einer Catchall-Adresse wird als "localpart" ein leerer String angegeben.

Liste anlegen

Damit Mailman tatsächlich genutzt werden kann, muss natürlich eine Liste eingerichtet werden.

Mit den folgenden Kommandos werden eine Liste in Mailman erstellt, E-Mail-Adressen angelegt sowie Weiterleitungen konfiguriert:

$ LISTNAME=test
DOMAIN_ADMIN=xyz00
DOMAIN_USER=xyz00-lists
DOMAIN=lists.example.org
LMTP_PORT=8024 # In Mailman Core konfigurierter Port

mailman create $LISTNAME@$DOMAIN # Alternativ über Web Frontend

Update

Mailman lässt sich wie im Folgenden beschrieben aktualisieren.

Python-Pakete für die Aktualisierungen vorliegen ausgeben:

$ cd ~/mailman
pipenv update --outdated

Vor dem eigentlichen Update empfiehlt es sich, die Release Notes (zumindest von Mailman) zu lesen und auf relevante Änderungen zu prüfen.

Update der Pakete:

$ pipenv update

Ggf. Pip Cache löschen:

$ rm -r ~/.cache/pip*

Anschließend werden die Dateien aus dem mailman-suite Git-Repository aktualisiert. Vor dem Übernehmen der Änderungen (merge), sollten die Commit Logs und die Änderungen begutachtet werden, um festzustellen, ob ggf. die Konfiguration anzupassen ist:

$ cd mailman-suite
git fetch origin
git log master..origin/master # Zeigt Commit logs
git diff master..origin/master # Zeigt Änderungen

Änderungen übernehmen:

$ git merge origin/master

Abschließend die verschiedenen Dienste neu starten:

$ mailman restart

qcluster neu starten, wenn als Dienst und nicht als Cron Job gestartet:

$ pkill --oldest --full 'mailman-suite_project/manage.py qcluster$'
mailman-django qcluster &disown

Web Frontend neu starten:

$ mkdir -p ~/doms/<domain>/app-ssl/tmp
touch ~/doms/<domain>/app-ssl/tmp/restart.txt

Zur Aktualisierung von msmtp können die Schritte zur Installation (mit angepasster Versionsnummer) wiederholt werden.