Mailman 3 installieren: Unterschied zwischen den Versionen

Aus Hostsharing Wiki
Zur Navigation springen Zur Suche springen
(→‎Mailman Core: pip install korrigiert)
(Anleitung aktualisiert)
Zeile 13: Zeile 13:
  mkdir ~/mailman
  mkdir ~/mailman
  cd ~/mailman
  cd ~/mailman
  pipenv install mailman mailman-hyperkitty
  pipenv install mailman
  pipenv install psycopg2-binary # Für PostgreSQL
  pipenv install psycopg2-binary # Für PostgreSQL
  pipenv install pymysql # Für MySQL</code>
  pipenv install pymysql # Für MySQL
 
Hinweis: Das Kommando <code>pipenv</code> muss immer im Verzeichnis <code>~/mailman</code> ausgeführt werden.


Anschließend wird das Verzeichnis für die Konfigurationsdatei angelegt:
Anschließend wird das Verzeichnis für die Konfigurationsdatei angelegt:
  $ mkdir -p ~/mailman/var/etc
  $ mkdir -p ~/mailman/etc


Die Konfiguration wird in die Datei <code>~/mailman/var/etc/mailman.cfg</code> geschrieben:
Die Konfiguration wird in die Datei <code>~/mailman/core/etc/mailman.cfg</code> geschrieben:
  [mailman]
  [mailman]
  site_owner: admin@example.org
  site_owner: admin@example.org
  default_language: de
  default_language: de
[paths.here]
var_dir: $cwd/core
   
   
  [database] # https://mailman.readthedocs.io/en/latest/src/mailman/docs/database.html
  [database] # https://mailman.readthedocs.io/en/latest/src/mailman/docs/database.html
Zeile 44: Zeile 49:
  smtp_pass: secret
  smtp_pass: secret
  smtp_secure_mode: starttls
  smtp_secure_mode: starttls
# VERP ist nicht möglich, da [https://de.wikipedia.org/wiki/Mail_Transfer_Agent MTA] nicht selbst konfiguriert werden kann
verp_confirm_format: $address
  # https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html
  # https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html
  # NullMTA, da MTA nicht selbst konfiguriert werden kann
  # NullMTA, da MTA nicht selbst konfiguriert werden kann
Zeile 59: Zeile 62:
  enable: yes
  enable: yes
  # $HOME muss durch den tatsächlichen Pfad zum Benutzerverzeichnis ersetzt werden
  # $HOME muss durch den tatsächlichen Pfad zum Benutzerverzeichnis ersetzt werden
  configuration: $HOME/mailman/var/etc/mailman-hyperkitty.cfg
  configuration: $HOME/mailman/core/etc/mailman-hyperkitty.cfg


Zugriffsrechte einschränken:
Zugriffsrechte einschränken:
  $ chmod 0600 ~/mailman/var/etc/mailman.cfg
  $ chmod 0600 ~/mailman/core/etc/mailman.cfg


Damit Hyperkitty als [[#Web_Frontend|Web Frontend]] für das Archiv verwendet werden kann, ist in die Datei <code>~/mailman/var/etc/mailman-hyperkitty.cfg</code> Foglendes zu schreiben:
Damit Hyperkitty als [[#Web_Frontend|Web Frontend]] für das Archiv verwendet werden kann, ist in die Datei <code>~/mailman/var/etc/mailman-hyperkitty.cfg</code> Foglendes zu schreiben:
  [general]
  [general]
  base_url: <nowiki>https://lists.example.org/hyperkitty/</nowiki>
  base_url: <nowiki>https://lists.example.org/hyperkitty/</nowiki>
  # Muss identisch mit Key in Hyperkitty sein
  # Muss identisch mit Key in Hyperkitty sein (s.u.)
  api_key: SecretArchiverAPIKey
  api_key: SecretArchiverAPIKey


Zeile 77: Zeile 80:
  #!/bin/sh
  #!/bin/sh
   
   
export MAILMAN_CONFIG_FILE=$HOME/mailman/core/etc/mailman.cfg
  cd ~/mailman
  cd ~/mailman
  pipenv run mailman "$@"
  pipenv run mailman "$@"
Zeile 82: Zeile 86:
   
   
  chmod +x ~/.local/bin/mailman
  chmod +x ~/.local/bin/mailman
Hinweis: Da in <code>mailman</code> das Verzeichnis gewechselt wird, funktionieren relative Pfadangaben als Argument nicht bzw. nur, wenn man sich bereits in <code>~/mailman</code> befindet.


Nun kann mit <code>mailman info</code> nochmal die aktuelle Konfiguration geprüft werden.
Nun kann mit <code>mailman info</code> nochmal die aktuelle Konfiguration geprüft werden.
Zeile 95: Zeile 101:
Anschließend werden die erforderlichen Python-Pakete installiert:
Anschließend werden die erforderlichen Python-Pakete installiert:
  $ cd ~/mailman
  $ cd ~/mailman
  pipenv install whoosh postorius hyperkitty
  pipenv install mailman-web


Um Plattenplatz freizugeben, kann optional der Pip Cache gelöscht werden:
Um Plattenplatz freizugeben, kann optional der Pip Cache gelöscht werden:
  $ rm -r ~/.cache/pip*
  $ pipenv --clear
 
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:
Zur Konfiguration von Hyperkitty wird die IP-Adresse benötigt, von der die Anfragen von Mailman Core kommen. Diese kann wie folgt ermittelt werden:
Zeile 111: Zeile 114:
  rm ~/doms/lists.example.org/htdocs-ssl/ip.php
  rm ~/doms/lists.example.org/htdocs-ssl/ip.php


Die Konfiguration wird nun in Die Datei <code>~/mailman/mailman-suite/mailman-suite_project/settings_local.py</code> geschrieben:
Die Konfiguration wird nun in Die Datei <code>~/mailman/web/settings.py</code> geschrieben:
  SECRET_KEY = 'change-this-on-your-production-server'
  # See https://mailman-web.readthedocs.io/en/latest/settings.html
  Debug = False
from mailman_web.settings.base import *
from mailman_web.settings.mailman import *
BASE_DIR = os.path.join(os.environ['HOME'], 'mailman', 'web')
# Default path where static files will be placed.
# 'collectstatic' command will copy all the static files here.
# Alias this location from your webserver to `/static`
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
# Make sure that the directory is created or Django will fail on start.
LOGGING['handlers']['file']['filename'] = os.path.join(BASE_DIR, 'logs', 'mailmanweb.log')
# Change path of Whoosh index
HAYSTACK_CONNECTIONS['default']['PATH'] = os.path.join(BASE_DIR, 'whoosh_index')
# django-compressor
# https://pypi.python.org/pypi/django_compressor
COMPRESS_PRECOMPILERS = (
    ('text/x-scss', 'sass -t compressed {infile} {outfile}'),
    ('text/x-sass', 'sass -t compressed {infile} {outfile}'),
)
# https://django-q.readthedocs.io/en/latest/configure.html
# 1 worker is probably enough. (Default is 3.)
  Q_CLUSTER['workers'] = 1
# Default list of admins who receive the emails from error logging.
# https://docs.djangoproject.com/en/dev/ref/settings/#admins
  ADMINS = (
  ADMINS = (
      ('Mailman Suite Admin', 'admin@example.org'),
    ('Mailman Admin', 'admin@example.org'),
  )
  )
# Database setup.
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
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',
    }
}
# Hosts/domain names that are valid for this site; required if DEBUG is False.
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
  ALLOWED_HOSTS = [
  ALLOWED_HOSTS = [
     'lists.example.org',
     'lists.example.org',
  ]
  ]
# A secret key for a particular Django installation. This is used to provide
# cryptographic signing, and should be set to a unique, unpredictable value.
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
SECRET_KEY = 'change-this-on-your-production-server'
# Mailman Core default API Path
  MAILMAN_REST_API_URL = '<nowiki>http://localhost:8001</nowiki>'
  MAILMAN_REST_API_URL = '<nowiki>http://localhost:8001</nowiki>'
# Mailman Core API user
  MAILMAN_REST_API_USER = 'restadmin'
  MAILMAN_REST_API_USER = 'restadmin'
# Mailman Core API user's password.
  MAILMAN_REST_API_PASS = 'restpass'
  MAILMAN_REST_API_PASS = 'restpass'
# Mailman Core Shared archiving key. This value is set in the
# mailman-hyperkitty's configuration file.
  MAILMAN_ARCHIVER_KEY = 'SecretArchiverAPIKey'
  MAILMAN_ARCHIVER_KEY = 'SecretArchiverAPIKey'
# Host for Mailman Core, from where Hyperkitty will accept connections
# for archiving.
  MAILMAN_ARCHIVER_FROM = ('<IP von Mailman Core>')
  MAILMAN_ARCHIVER_FROM = ('<IP von Mailman Core>')
   
   
  # Authentifizierung über externe Dienste ausschalten (s. django-allauth)
  # Base URL where Django/Mailman-web would be listening for requests. Used by
  from settings import INSTALLED_APPS
  # Mailman Core for fetching templates.
  INSTALLED_APPS = filter(lambda app: not app.startswith('allauth.socialaccount.') and app != 'django_mailman3.lib.auth.fedora', INSTALLED_APPS)
  POSTORIUS_TEMPLATE_BASE_URL = 'https://lists.example.org'
  INSTALLED_APPS = (
   
    'hyperkitty',
# Sender in emails sent out by Postorius.
    'postorius',
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-DEFAULT_FROM_EMAIL
    'django_mailman3',
DEFAULT_FROM_EMAIL = 'postorius@lists.example.org'
    # 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
  # If you enable email reporting for error messages, this is where those emails
  DATABASES = {
  # will appear to be coming from. Make sure you set a valid domain name,
    'default': {
# otherwise the emails may get rejected.
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Für MySQL: django.db.backends.mysql
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SERVER_EMAIL
        'HOST': 'localhost',
SERVER_EMAIL = 'django@lists.example.org'
        'NAME': 'database_name',
        'USER': 'database_user',
        'PASSWORD': 'database_password',
    }
}
   
   
  LANGUAGE_CODE = 'de-de'
  # Configuration used to send emails.
  TIME_ZONE = 'Europe/Berlin'
  # https://docs.djangoproject.com/en/dev/ref/settings/#email-host
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_HOST = 'xyz00.hostsharing.net'
  EMAIL_PORT = 4587
  EMAIL_PORT = 4587
Zeile 177: Zeile 208:
  EMAIL_TIMEOUT = 60
  EMAIL_TIMEOUT = 60
   
   
  ACCOUNT_DEFAULT_HTTP_PROTOCOL = 'https'
  # A string representing the time zone for this installation.
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TIME_ZONE
TIME_ZONE = 'Europe/Berlin'
# A string representing the language code for this installation.
# https://docs.djangoproject.com/en/dev/ref/settings/#language-code
LANGUAGE_CODE = 'de-de'
   
   
  COMPRESS_PRECOMPILERS = (
  # Disable support for gravatars in HyperKitty and Postorius.
    ('text/less', 'lessc {infile} {outfile}'),
# https://docs.mailman3.org/projects/hyperkitty/en/latest/install.html#customization
    ('text/x-scss', 'sass -t compressed {infile} {outfile}'),
  HYPERKITTY_ENABLE_GRAVATAR = False
    ('text/x-sass', 'sass -t compressed {infile} {outfile}'),
)
  COMPRESS_OFFLINE = True
   
   
  # Workeranzahl reduzieren (optional)
  # Hinweis: In der derzeit aktuellen Version (1.3.5) der Komponente
  Q_CLUSTER = {
# django-mailman3 wird obige Variable nicht berücksichtigt. Deshalb kann die
    'workers': 1,
  # folgende Direktive nur mit dem Entwicklungsstand aus git einkommentiert werden.
    'timeout': 300,
# django_gravatar is not required, anymore.
    'save_limit': 100,
#INSTALLED_APPS.remove('django_gravatar')
    'orm': 'default',
 
  }
Zugriffsrechte einschränken:
  $ chmod 600 ~/mailman/web/settings.py


Hinweis: Die Einstellungen in <code>settings_local.py</code> überschreiben solche in <code>settings.py</code>. Zwar kann <code>settings.py</code> auch direkt angepasst werden, auf diese Weise werden jedoch mögliche Konflikte beim Update vermieden. <code>settings.py</code> sollte dennoch dahingehend geprüft werden, ob man ggf. weitere Optionen ändern möchte.
Hinweis: Wird die Konfiguration geändert, nachdem das Web Frontend aufgerufen wurde, muss es neu gestartet werden:
$ mkdir -p ~/doms/lists.example.org/app-ssl/tmp
touch ~/doms/lists.example.org/app-ssl/tmp/restart.txt


Das Mailman Web Frontend nutzt das Framework Django. Einige der Einstellungen sind in der [https://docs.djangoproject.com/en/2.2/ref/settings/ Dokumentation von Django] beschrieben, andere konfigurieren eine der in <code>INSTALLED_APPS</code> definierten Anwendungen.
Das für Logs definierte Verzeichnis anlegen:
$ mkdir -p ~/mailman/web/logs


Damit per Django verfügbare Kommandos leicht ausgeführt werden können, wird der Befehl ''mailman-django'' eingerichtet:
Damit per Django verfügbare Kommandos leicht ausgeführt werden können, wird der Befehl ''mailman-web'' eingerichtet:
  $ cat <<'EOD' >~/.local/bin/mailman-django
  $ cat <<'EOD' >~/.local/bin/mailman-web
  #!/bin/sh
  #!/bin/sh
   
   
export MAILMAN_WEB_CONFIG=$HOME/mailman/web/settings.py
  cd ~/mailman
  cd ~/mailman
  pipenv run mailman-suite/mailman-suite_project/manage.py "$@"
  pipenv run mailman-web "$@"
  EOD
  EOD
   
   
  chmod +x ~/.local/bin/mailman-django
  chmod +x ~/.local/bin/mailman-web


Anschließend können folgende Kommandos ausgeführt werden:
Anschließend wird das Datenbankschema eingerichtet:
  $ mailman-django migrate
  $ mailman-web migrate
mailman-django collectstatic
 
mailman-django compress
Mit dem folgenden Kommando werden statische Daten für das Web Frontend ins konfiguriete Verzeichnis geschrieben:
  mailman-django createsuperuser
  $ mailman-web collectstatic


Nun müssen die statischen Dateien für das Web Frontend noch per HTTPS verfügbar gemacht werden:
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/
  $ ln -s ~/mailman/mailman-suite/mailman-suite_project/static ~/doms/lists.example.org/htdocs-ssl/
Zum Anlegen des Administrators des Web Frontends wird dieser Befehl ausgeführt:
$ mailman-web createsuperuser
Da die Übersetzungsdateien nur in Mailman Core, jedoch nicht bei den Web Frontend Komponenten im Binärformat enthalten sind, muss die Konvertierung nachgeholt werden:
$ for pofile in $(find $(pipenv --venv) -path '*/locale/*/LC_MESSAGES/*.po'); do
    mofile=${pofile/.po/.mo}
    if [ ! -f $mofile ] || [ $pofile -nt $mofile ]; then
      echo $pofile
      msgfmt $pofile -o $mofile -v
    fi
done


Damit das Web Frontend per [[Phusion_Passenger|Phusion Passenger]] geladen werden kann:
Damit das Web Frontend per [[Phusion_Passenger|Phusion Passenger]] geladen werden kann:
Zeile 226: Zeile 277:
  os.environ['LC_ALL'] = 'C.UTF-8'
  os.environ['LC_ALL'] = 'C.UTF-8'
   
   
  HOME = os.getenv('HOME')
  HOME = os.environ['HOME']
  PIPENV = os.path.join(HOME, '.local', 'bin', 'pipenv')
  PIPENV = os.path.join(HOME, '.local', 'bin', 'pipenv')
  PIPFILE_DIR = os.path.join(HOME, 'mailman')
  PIPFILE_DIR = os.path.join(HOME, 'mailman')
  INTERP = subprocess.check_output([PIPENV, 'run', 'which', 'python'], cwd=PIPFILE_DIR).strip().decode('utf-8')
  PIPENV_PYTHON = subprocess.check_output([PIPENV, '--py'], cwd=PIPFILE_DIR).strip().decode('utf-8')
  if sys.executable != INTERP:
  if sys.executable != PIPENV_PYTHON:
     os.execl(INTERP, INTERP, *sys.argv)
     os.execl(PIPENV_PYTHON, PIPENV_PYTHON, *sys.argv)
   
   
  WSGI_DIR = os.path.join(HOME, 'mailman', 'mailman-suite', 'mailman-suite_project')
  os.environ['MAILMAN_WEB_CONFIG'] = os.path.join(HOME, 'mailman', 'web', 'settings.py')
  sys.path.append(WSGI_DIR)
  from mailman_web.wsgi import application
from wsgi import application
  EOD
  EOD


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


== Cron Jobs ==
== Mails an Mailman weiterleiten ==
Es sind verschiedene Cron Jobs erforderlich. Hierzu <code>crontab -e</code> ausführen und Folgendes eintragen:
Da die MTA-Konfiguration nicht direkt angepasst werden kann, ist ein Hilfskonstrukt erforderlich: Mittels ''.forward-Datei'' werden eingehende Mails an das Programm <code>msmtp</code> weitergeleitet, welches diese per [https://de.wikipedia.org/wiki/Local_Mail_Transfer_Protocol LMTP] bei Mailman abliefert. msmtp ist auf den Managed Servern vorinstalliert.
  # An die in MAILTO eingetragene Adressen werden Ausgaben der Cron Jobs gesendet (optional)
 
  #MAILTO=admin@example.org
  $ MM_LMTP_PORT=8024 # In Mailman Core konfigurierter Port
  PATH=$HOME/.local/bin:$PATH
cat <<'EOD' >.forward+mailman
"|/usr/bin/msmtp --host=localhost --port=$MM_LMTP_PORT --protocol=lmtp --read-envelope-from \$(echo \$ORIGINAL_RECIPIENT | sed 's/+.\+@/@/')"
EOD
 
Der <code>sed</code> Befehl ist erforderlich, damit Mails mit ''Plus Addressing'' mit der eigentlichen Empfängeradresse bei Mailman ankommen.
 
Für die Domain <code>lists.example.org</code> wird in HSAdmin oder per <code>hssscript</code> eine Catchall-Adresse mit <code>xyz00-lists+mailman</code> als Ziel eingerichtet. Bei einer Catchall-Adresse wird als <code>localpart</code> ein leerer String angegeben.
 
== Dienste starten und überwachen ==
Für die beiden benötigten Dienste kann ''monit'' wie folgt konfiguriert werden:
$ mkdir monit
cat <<EOD >~/.monitrc
set daemon 60
    with start delay 90
set httpd unixsocket $HOME/monit/monit.sock
    permission 600
    allow mailman:monit
set mailserver localhost
set mail-format { from: monit@lists.example.org }
  set alert admin@example.org
  set logfile $HOME/monit/monit.log
set idfile $HOME/monit/monit.id
set pidfile $HOME/monit/monit.pid
set statefile $HOME/monit/monit.state
   
   
  @reboot mailman start
  check process mailman
    pidfile $HOME/mailman/core/master.pid
    start program = "$HOME/.local/bin/mailman start"
    stop program = "$HOME/.local/bin/mailman stop"
    restart program = "$HOME/.local/bin/mailman restart"
   
   
  # Send periodic digests.
  check process mailman-web-qcluster
@daily mailman digests --send
    matching "mailman-web qcluster"
    start program = "/bin/bash -c 'nohup $HOME/.local/bin/mailman-web qcluster >>$HOME/mailman/web/logs/qcluster.log 2>&1 &'"
@reboot mailman-django qcluster
    stop program = "/usr/bin/pkill -f 'mailman-web qcluster'"
# Alternativ qcluster minütlich ausführen
    depends on mailman
# * * * * * mailman-django qcluster --run-once
  EOD
* * * * * 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'' <code>@reboot</code> verwendet. Besser wäre der Einsatz von monit. Beim Einsatz von monit würde sich auch der Neustart der Dienste nach einem [[#Update|Update]] ändern. (Anleitung gerne anpassen, sollte jemand monit einrichten.)
Dienste starten:
$ monit


== Mails an Mailman weiterleiten ==
Für <code>mailman-web qcluster</code> kann alternativ ein minütlich laufender Cron Job verwendet werden.
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 [https://de.wikipedia.org/wiki/Local_Mail_Transfer_Protocol 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
== Logrotation ==
  "|/usr/bin/procmail -p"
Die Rotation der Logdateien kann so konfiguriert werden:
$ cat <<EOD >~/logrotate.conf
compress
delaycompress
missingok
notifempty
dateext
$HOME/monit/monit.log {
    rotate 1
    weekly
    maxsize 1M
}
$HOME/mailman/core/logs/*.log {
    rotate 6
    daily
    sharedscripts
    postrotate
        $HOME/.local/bin/mailman reopen >/dev/null ||:
    endscript
}
$HOME/mailman/web/logs/mailmanweb.log {
    rotate 6
    daily
}
$HOME/mailman/web/logs/qcluster.log {
    rotate 1
    size 100k
    postrotate
        /usr/bin/monit restart mailman-web-qcluster >/dev/null ||:
    endscript
}
EOD


  ~$ cat .procmailrc
Hinweis: <code>qcluster.log</code> wird hier nur bei Überschreiten der definierten Größe rotiert, um regelmäßige Mails von ''monit'' zu vermeiden.
  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
 
  :0
  { EXITCODE 67 }


== Cron Jobs ==
Für Mailman sind verschiedene Cron Jobs erforderlich. Zudem sollen nach einem Neustart die <code>monit</code> Dienste gestartet werden und täglich eine Logrotation erfolgen. Die Einrichtung kann so erfolgen (eine bereits existierende crontab wird überschrieben):
$ cat <<EOD | crontab -
MAILTO=admin@example.org
HOME=$HOME
PATH=$HOME/.local/bin:/usr/bin:/bin:/usr/sbin
@reboot rm -f \$HOME/monit/monit.pid \$HOME/mailman/core/master.pid && monit
@daily logrotate -s \$HOME/.logrotate_state \$HOME/logrotate.conf
# Send periodic digests.
@daily mailman digests --send
* * * * * mailman-web runjobs minutely
2,17,32,47 * * * * mailman-web runjobs quarter_hourly
@hourly  mailman-web runjobs hourly
@daily  mailman-web runjobs daily
@weekly  mailman-web runjobs weekly
@monthly mailman-web runjobs monthly
@yearly  mailman-web runjobs yearly
EOD


Die Mailadresse wird als Catchall-Adresse in HSAdmin angelegt. Bei einer Catchall-Adresse wird als "localpart" ein leerer String angegeben.
Soll eine existierende crontab nicht überschrieben werden, muss das Kommando <code>crontab -e</code> ausgeführt und die crontab entsprechend angepasst werden. (Dabei <code>\$HOME</code> mit <code>$HOME</code> und <code>$HOME</code> mit dem Pfad des Benutzerverzeichnisses ersetzen.)


== Liste anlegen ==
== Liste anlegen ==
Damit Mailman tatsächlich genutzt werden kann, muss natürlich eine Liste eingerichtet werden.
Damit Mailman tatsächlich genutzt werden kann, muss natürlich eine Liste eingerichtet werden.
 
  $ mailman create meine-erste-liste@lists.example.org # Alternativ über Web Frontend
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 ==
== Update ==
Zeile 317: Zeile 419:


Ggf. Pip Cache löschen:
Ggf. Pip Cache löschen:
  $ rm -r ~/.cache/pip*
  $ pipenv --clear


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:
Abschließend die Dienste neu starten:
  $ cd mailman-suite
  $ monit restart mailman
  git fetch origin
  monit restart mailman-web-qcluster
git log master..origin/master # Zeigt Commit logs
git diff master..origin/master # Zeigt Änderungen


Änderungen übernehmen:
Übersetzungen aktualisieren:
  $ git merge origin/master
  $ for pofile in $(find $(pipenv --venv) -path '*/locale/*/LC_MESSAGES/*.po'); do
 
    mofile=${pofile/.po/.mo}
Abschließend die verschiedenen Dienste neu starten:
    if [ ! -f $mofile ] || [ $pofile -nt $mofile ]; then
$ mailman restart
      echo $pofile
 
      msgfmt $pofile -o $mofile -v
qcluster neu starten, wenn als Dienst und nicht als Cron Job gestartet:
    fi
$ pkill --oldest --full 'mailman-suite_project/manage.py qcluster$'
  done
  mailman-django qcluster &disown


Web Frontend neu starten:
Web Frontend neu starten:
  $ mkdir -p ~/doms/<domain>/app-ssl/tmp
  $ mkdir -p ~/doms/lists.example.org/app-ssl/tmp
  touch ~/doms/<domain>/app-ssl/tmp/restart.txt
  touch ~/doms/lists.example.org/app-ssl/tmp/restart.txt
 
Zur Aktualisierung von msmtp können die Schritte zur Installation (mit angepasster Versionsnummer) wiederholt werden.


[[Kategorie:HSDoku]]
[[Kategorie:HSDoku]]

Version vom 11. März 2021, 21:50 Uhr

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
pipenv install psycopg2-binary # Für PostgreSQL
pipenv install pymysql # Für MySQL

Hinweis: Das Kommando pipenv muss immer im Verzeichnis ~/mailman ausgeführt werden.

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

$ mkdir -p ~/mailman/etc

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

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

[paths.here]
var_dir: $cwd/core

[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
# 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/core/etc/mailman-hyperkitty.cfg

Zugriffsrechte einschränken:

$ chmod 0600 ~/mailman/core/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 (s.u.)
api_key: SecretArchiverAPIKey

Zugriffsrechte einschränken:

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

Kommando mailman anlegen:

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

export MAILMAN_CONFIG_FILE=$HOME/mailman/core/etc/mailman.cfg
cd ~/mailman
pipenv run mailman "$@"
EOD

chmod +x ~/.local/bin/mailman

Hinweis: Da in mailman das Verzeichnis gewechselt wird, funktionieren relative Pfadangaben als Argument nicht bzw. nur, wenn man sich bereits in ~/mailman befindet.

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 mailman-web

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

$ pipenv --clear

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/web/settings.py geschrieben:

# See https://mailman-web.readthedocs.io/en/latest/settings.html

from mailman_web.settings.base import *
from mailman_web.settings.mailman import *

BASE_DIR = os.path.join(os.environ['HOME'], 'mailman', 'web')

# Default path where static files will be placed.
# 'collectstatic' command will copy all the static files here.
# Alias this location from your webserver to `/static`
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

# Make sure that the directory is created or Django will fail on start.
LOGGING['handlers']['file']['filename'] = os.path.join(BASE_DIR, 'logs', 'mailmanweb.log')

# Change path of Whoosh index
HAYSTACK_CONNECTIONS['default']['PATH'] = os.path.join(BASE_DIR, 'whoosh_index')

# django-compressor
# https://pypi.python.org/pypi/django_compressor
COMPRESS_PRECOMPILERS = (
   ('text/x-scss', 'sass -t compressed {infile} {outfile}'),
   ('text/x-sass', 'sass -t compressed {infile} {outfile}'),
)

# https://django-q.readthedocs.io/en/latest/configure.html
# 1 worker is probably enough. (Default is 3.)
Q_CLUSTER['workers'] = 1

# Default list of admins who receive the emails from error logging.
# https://docs.djangoproject.com/en/dev/ref/settings/#admins
ADMINS = (
    ('Mailman Admin', 'admin@example.org'),
)
# Database setup.
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
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',
    }
}

# Hosts/domain names that are valid for this site; required if DEBUG is False.
# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts
ALLOWED_HOSTS = [
    'lists.example.org',
]

# A secret key for a particular Django installation. This is used to provide
# cryptographic signing, and should be set to a unique, unpredictable value.
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
SECRET_KEY = 'change-this-on-your-production-server'

# Mailman Core default API Path
MAILMAN_REST_API_URL = 'http://localhost:8001'
# Mailman Core API user
MAILMAN_REST_API_USER = 'restadmin'
# Mailman Core API user's password.
MAILMAN_REST_API_PASS = 'restpass'
# Mailman Core Shared archiving key. This value is set in the
# mailman-hyperkitty's configuration file.
MAILMAN_ARCHIVER_KEY = 'SecretArchiverAPIKey'
# Host for Mailman Core, from where Hyperkitty will accept connections
# for archiving.
MAILMAN_ARCHIVER_FROM = ('<IP von Mailman Core>')

# Base URL where Django/Mailman-web would be listening for requests. Used by
# Mailman Core for fetching templates.
POSTORIUS_TEMPLATE_BASE_URL = 'https://lists.example.org'

# Sender in emails sent out by Postorius.
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-DEFAULT_FROM_EMAIL
DEFAULT_FROM_EMAIL = 'postorius@lists.example.org'

# If you enable email reporting for error messages, this is where those emails
# will appear to be coming from. Make sure you set a valid domain name,
# otherwise the emails may get rejected.
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SERVER_EMAIL
SERVER_EMAIL = 'django@lists.example.org'

# Configuration used to send emails.
# https://docs.djangoproject.com/en/dev/ref/settings/#email-host
EMAIL_HOST = 'xyz00.hostsharing.net'
EMAIL_PORT = 4587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'xyz00-lists'
EMAIL_HOST_PASSWORD = 'secret'
EMAIL_TIMEOUT = 60

# A string representing the time zone for this installation.
# https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TIME_ZONE
TIME_ZONE = 'Europe/Berlin'

# A string representing the language code for this installation.
# https://docs.djangoproject.com/en/dev/ref/settings/#language-code
LANGUAGE_CODE = 'de-de'

# Disable support for gravatars in HyperKitty and Postorius.
# https://docs.mailman3.org/projects/hyperkitty/en/latest/install.html#customization
HYPERKITTY_ENABLE_GRAVATAR = False

# Hinweis: In der derzeit aktuellen Version (1.3.5) der Komponente
# django-mailman3 wird obige Variable nicht berücksichtigt. Deshalb kann die
# folgende Direktive nur mit dem Entwicklungsstand aus git einkommentiert werden.
# django_gravatar is not required, anymore.
#INSTALLED_APPS.remove('django_gravatar')

Zugriffsrechte einschränken:

$ chmod 600 ~/mailman/web/settings.py

Hinweis: Wird die Konfiguration geändert, nachdem das Web Frontend aufgerufen wurde, muss es neu gestartet werden:

$ mkdir -p ~/doms/lists.example.org/app-ssl/tmp
touch ~/doms/lists.example.org/app-ssl/tmp/restart.txt

Das für Logs definierte Verzeichnis anlegen:

$ mkdir -p ~/mailman/web/logs

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

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

export MAILMAN_WEB_CONFIG=$HOME/mailman/web/settings.py
cd ~/mailman
pipenv run mailman-web "$@"
EOD

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

Anschließend wird das Datenbankschema eingerichtet:

$ mailman-web migrate

Mit dem folgenden Kommando werden statische Daten für das Web Frontend ins konfiguriete Verzeichnis geschrieben:

$ mailman-web collectstatic

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/

Zum Anlegen des Administrators des Web Frontends wird dieser Befehl ausgeführt:

$ mailman-web createsuperuser

Da die Übersetzungsdateien nur in Mailman Core, jedoch nicht bei den Web Frontend Komponenten im Binärformat enthalten sind, muss die Konvertierung nachgeholt werden:

$ for pofile in $(find $(pipenv --venv) -path '*/locale/*/LC_MESSAGES/*.po'); do
    mofile=${pofile/.po/.mo}
    if [ ! -f $mofile ] || [ $pofile -nt $mofile ]; then
      echo $pofile
      msgfmt $pofile -o $mofile -v
    fi
done

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.environ['HOME']
PIPENV = os.path.join(HOME, '.local', 'bin', 'pipenv')
PIPFILE_DIR = os.path.join(HOME, 'mailman')
PIPENV_PYTHON = subprocess.check_output([PIPENV, '--py'], cwd=PIPFILE_DIR).strip().decode('utf-8')
if sys.executable != PIPENV_PYTHON:
    os.execl(PIPENV_PYTHON, PIPENV_PYTHON, *sys.argv)

os.environ['MAILMAN_WEB_CONFIG'] = os.path.join(HOME, 'mailman', 'web', 'settings.py')
from mailman_web.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.

Mails an Mailman weiterleiten

Da die MTA-Konfiguration nicht direkt angepasst werden kann, ist ein Hilfskonstrukt erforderlich: Mittels .forward-Datei werden eingehende Mails an das Programm msmtp weitergeleitet, welches diese per LMTP bei Mailman abliefert. msmtp ist auf den Managed Servern vorinstalliert.

$ MM_LMTP_PORT=8024 # In Mailman Core konfigurierter Port
cat <<'EOD' >.forward+mailman
"|/usr/bin/msmtp --host=localhost --port=$MM_LMTP_PORT --protocol=lmtp --read-envelope-from \$(echo \$ORIGINAL_RECIPIENT | sed 's/+.\+@/@/')"
EOD

Der sed Befehl ist erforderlich, damit Mails mit Plus Addressing mit der eigentlichen Empfängeradresse bei Mailman ankommen.

Für die Domain lists.example.org wird in HSAdmin oder per hssscript eine Catchall-Adresse mit xyz00-lists+mailman als Ziel eingerichtet. Bei einer Catchall-Adresse wird als localpart ein leerer String angegeben.

Dienste starten und überwachen

Für die beiden benötigten Dienste kann monit wie folgt konfiguriert werden:

$ mkdir monit
cat <<EOD >~/.monitrc
set daemon 60
    with start delay 90
set httpd unixsocket $HOME/monit/monit.sock
    permission 600
    allow mailman:monit
set mailserver localhost
set mail-format { from: monit@lists.example.org }
set alert admin@example.org
set logfile $HOME/monit/monit.log
set idfile $HOME/monit/monit.id
set pidfile $HOME/monit/monit.pid
set statefile $HOME/monit/monit.state

check process mailman
    pidfile $HOME/mailman/core/master.pid
    start program = "$HOME/.local/bin/mailman start"
    stop program = "$HOME/.local/bin/mailman stop"
    restart program = "$HOME/.local/bin/mailman restart"

check process mailman-web-qcluster
    matching "mailman-web qcluster"
    start program = "/bin/bash -c 'nohup $HOME/.local/bin/mailman-web qcluster >>$HOME/mailman/web/logs/qcluster.log 2>&1 &'"
    stop program = "/usr/bin/pkill -f 'mailman-web qcluster'"
    depends on mailman
EOD

Dienste starten:

$ monit

Für mailman-web qcluster kann alternativ ein minütlich laufender Cron Job verwendet werden.

Logrotation

Die Rotation der Logdateien kann so konfiguriert werden:

$ cat <<EOD >~/logrotate.conf
compress
delaycompress
missingok
notifempty
dateext

$HOME/monit/monit.log {
    rotate 1
    weekly
    maxsize 1M
}

$HOME/mailman/core/logs/*.log {
    rotate 6
    daily
    sharedscripts
    postrotate
        $HOME/.local/bin/mailman reopen >/dev/null ||:
    endscript
}

$HOME/mailman/web/logs/mailmanweb.log {
    rotate 6
    daily
}

$HOME/mailman/web/logs/qcluster.log {
    rotate 1
    size 100k
    postrotate
        /usr/bin/monit restart mailman-web-qcluster >/dev/null ||:
    endscript
}
EOD

Hinweis: qcluster.log wird hier nur bei Überschreiten der definierten Größe rotiert, um regelmäßige Mails von monit zu vermeiden.

Cron Jobs

Für Mailman sind verschiedene Cron Jobs erforderlich. Zudem sollen nach einem Neustart die monit Dienste gestartet werden und täglich eine Logrotation erfolgen. Die Einrichtung kann so erfolgen (eine bereits existierende crontab wird überschrieben):

$ cat <<EOD | crontab -
MAILTO=admin@example.org
HOME=$HOME
PATH=$HOME/.local/bin:/usr/bin:/bin:/usr/sbin

@reboot rm -f \$HOME/monit/monit.pid \$HOME/mailman/core/master.pid && monit

@daily logrotate -s \$HOME/.logrotate_state \$HOME/logrotate.conf

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

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

Soll eine existierende crontab nicht überschrieben werden, muss das Kommando crontab -e ausgeführt und die crontab entsprechend angepasst werden. (Dabei \$HOME mit $HOME und $HOME mit dem Pfad des Benutzerverzeichnisses ersetzen.)

Liste anlegen

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

$ mailman create meine-erste-liste@lists.example.org # 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:

$ pipenv --clear

Abschließend die Dienste neu starten:

$ monit restart mailman
monit restart mailman-web-qcluster

Übersetzungen aktualisieren:

$ for pofile in $(find $(pipenv --venv) -path '*/locale/*/LC_MESSAGES/*.po'); do
    mofile=${pofile/.po/.mo}
    if [ ! -f $mofile ] || [ $pofile -nt $mofile ]; then
      echo $pofile
      msgfmt $pofile -o $mofile -v
    fi
done

Web Frontend neu starten:

$ mkdir -p ~/doms/lists.example.org/app-ssl/tmp
touch ~/doms/lists.example.org/app-ssl/tmp/restart.txt