Hetzner-Server mit Ubuntu 24.04
So langsam ist mein bisheriger Server in die Jahre gekommen, wobei das eigentlich hauptsächlich das PHP und die Datenbank betrifft. Ich habe mich dafür entschieden einen neuen Server einzurichten und mich wieder für einen aus der Hetzner Server-Börse entschieden. Eigentlich hatte ich mich über Hetzner geärgert, weil die im Zusammenhang mit der Energiekrise den Preis für den Server nachträglich erhöht haben, nach der Senkung der Strompreise in den Folgejahren aber nicht wieder gesenkt haben.
Naja der neue Server ist etwas besser und trotzdem 1€ preiswerter.
Ich mache ungern Aktualisierungen auf dem vorhandenen Server. Eine klassische Aktualisierung funktioniert bei Ubuntu in der Regel problemlos, doch man schleppt eventuell Altlasten mit. Wenn dann doch Probleme auftauchen, dann ist man einige Zeit offline und im Stress.
Der gesamte Bestellprozess hat bis zur Übergabe der Rechners 15 Minuten gedauert.
Der Server hat folgende Eigenschaften:
- Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz
- 6800 Bogomips
- 64 GByte Hauptspeicher
- 2x4 GByte HD
Grundinstallation
Startet man im Rescue-System das Programm installimage, so muss man zuerst das Betriebssystem auswählen, welches man installieren möchte. Ich habe mich für Ubuntu 20.04 entschieden. Nach dieser Auswahl landet man in einem Editor, indem man vor allem die Partitionierung der Festplatten festlegt. Die vorgegebene Datei ist gut dokumentiert, sodass hier eigentlich keine Probleme auftauchen sollten. Ich habe mich für folgende Aufteilung entschieden:
/dev/md1 1G /boot /dev/md2 50G / /dev/md3 5G /tmp /dev/md4 800G /var /dev/md5 980G /home (der gesamte Rest)
Schwierig kann es sein, den Editor ordnungsgemäß zu verlassen. Die Funktionstaste F10 wirkt bei mir nicht auf den Hetzner-Editor, sondern auf das Terminal. Hetzner schlägt im Wiki vor ESC und dann 0 zu drücken.
Im nächsten Schritt dann
apt update apt upgrade
Das Upgrade dauert leicht einmal mehr als 30 Minuten.
Ich habe mir dann noch gleich ein paar nützliche Hilfsmittel eingerichtet:
apt install synaptic apt-xapian-index update-apt-xapian-index -vf
Installiert das grafische Tool zur Paketverwaltung. Dann kann ich leichter nach Paketen suchen.
Auch grafische Tools lassen sich per ssh aufrufen, wenn man beim Start der Verbindung den Parameter -X mit angibt:
ssh -X root@mein-server.domain
Da ich schon häufiger Probleme mit den Festplatten hatte, sind mir die Smartmontools wichtig:
apt install smartmontools
Der Aufruf von
smartctl -A /dev/sda
bzw.
smartctl -A /dev/sdb
Liefert mir die Information, dass die Festplatten schon viele Stunden gelaufen sind.
Im Netzwerk benötigt man dann oft auch whois Informationen
apt install whois
Mit folgendem Paket kann ich die Netzwerk-Geschwindigkeit überprüfen.
apt install speedtest-cli
Für die Nutzung ruft man auf:
speedtest-cli --secure
Das --secure ist wichtig, da http-Anfragen nicht mehr funktionieren und hiermit auf https umgestellt wird.
Firewall
Gleich nach der ersten Übersicht ist mir aufgefallen, dass keinerlei Firewall aktiv ist. Bei Ubuntu ist dafür ufw installiert und muss noch aktiviert werden. Bei ufw kann man relativ komfortabel Ports sperren oder freigeben, teilweise sogar über vorkonfigurierte Pakete. Wichtig ist, dass man Port 22 freigibt, bevor man die Firewall aktiviert (https://ubuntu.com/server/docs/security-firewall, https://help.ubuntu.com/community/UFW):
ufw allow OpenSSH ufw allow "Apache Full"
Wer kommt auf die blöde Idee, einen Bezeichner mit Leerzeichen zu wählen?? Nun kann man die Firewall aktivieren mittels:
ufw enable
Würde es die App OpenSSH nicht geben, so würde man Port 22 freigeben mittels:
ufw allow 22
oder
ufw allow ssh
Die Apache-App steht erst zur Verfügung, wenn man den Webserver installiert hat. Die Liste der aktuell verfügbaren Apps kann man abrufen mittels:
ufw app list
Um nicht die syslog-Datei mit den ganzen Firewall-Meldungen zu füllen, habe ich noch die Datei /etc/rsyslog.d/20-ufw.conf editiert.
# Log kernel generated UFW log messages to file
:msg,contains,"[UFW " /var/log/ufw.log
# Uncomment the following to stop logging anything that matches the last rule.
# Doing this will stop logging kernel generated UFW log messages to the file
# normally containing kern.* messages (eg, /var/log/kern.log)
& stop
Die letzte Zeile beginnt normalerweise mit einem Kommentarzeichen, das nach Anweisung weg muss.
Inzwischen nutze ich ufw auch, um lästige IP-Adressbereiche zu blockieren:
ufw deny from 185.222.xxx.0/24 to any
Die Liste aller aktuellen Regeln kann man abfragen mit:
ufw status
Interessant ist auch die Version
ufw status numbered
Hier wird jeder Regel eine Nummer vorangestellt
Status: Aktiv
Zu Aktion Von
-- ------ ---
[ 1] Apache Full ALLOW IN Anywhere
[ 2] OpenSSH ALLOW IN Anywhere
[ 3] mosh ALLOW IN Anywhere
[ 4] Postfix ALLOW IN Anywhere
[ 5] Dovecot POP3 ALLOW IN Anywhere
[ 6] 21/tcp ALLOW IN Anywhere
[ 7] 143 ALLOW IN Anywhere
[ 8] 993 ALLOW IN Anywhere
[ 9] 53/udp ALLOW IN Anywhere
[10] Dovecot Secure POP3 ALLOW IN Anywhere
[11] 5349/tcp ALLOW IN Anywhere
[12] 5349/udp ALLOW IN Anywhere
[13] Anywhere DENY IN 185.222.xxx.0/24
[14] Apache Full (v6) ALLOW IN Anywhere (v6)
[15] OpenSSH (v6) ALLOW IN Anywhere (v6)
[16] mosh (v6) ALLOW IN Anywhere (v6)
[17] Postfix (v6) ALLOW IN Anywhere (v6)
[18] Dovecot POP3 (v6) ALLOW IN Anywhere (v6)
[19] 21/tcp (v6) ALLOW IN Anywhere (v6)
[20] 143 (v6) ALLOW IN Anywhere (v6)
[21] 993 (v6) ALLOW IN Anywhere (v6)
[22] 53/udp (v6) ALLOW IN Anywhere (v6)
[23] Dovecot Secure POP3 (v6) ALLOW IN Anywhere (v6)
[24] 5349/tcp (v6) ALLOW IN Anywhere (v6)
[25] 5349/udp (v6) ALLOW IN Anywhere (v6)
Über diese Nummer kann man sie auch wieder löschen
ufw delete 13
würde also obige Regel wieder löschen.
An der Liste sieht man schon, dass man die Reihenfolge berücksichtigen muss. Viele Dienste sind schon erlaubt, bevor die Sperregel kommt. Also besser immer an Position 1 schieben mittels:
ufw insert 1 deny from 185.222.xxx.0/24 to any
Ob sich etwas tut, kann man abfragen mittels:
iptables -v -n -L ufw-user-input
Bei mir sieht das Ergebnis folgendermaßen aus:
Chain ufw-user-input (1 references) pkts bytes target prot opt in out source destination 100 6000 DROP all -- * * 185.222.xxx.0/24 0.0.0.0/0 649 34606 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 multiport dports 80,443 /* 'dapp_Apache%20Full' */ 85 4980 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 /* 'dapp_OpenSSH' */ 0 0 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 multiport dports 60000:61000 /* 'dapp_mosh' */ 157 9380 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:25 /* 'dapp_Postfix' */ ...
Es wurden also 10 Pakete mit insgesamt 6000 Byte von der Regel blockiert.
Anpassungen
Die Spracheinstellungen anpassen. Bei mir war die benötigte Locale nicht vorhanden, wie der Aufruf von
locale -a
zeigte. Alles erst erzeugen mittels:
locale-gen de_DE.UTF-8
dann
update-locale LANG=de_DE.UTF-8
Danach neu anmelden, um den Effekt zu sehen.
~ # locale LANG=de_DE.UTF-8 LANGUAGE= LC_CTYPE="de_DE.UTF-8" LC_NUMERIC="de_DE.UTF-8" LC_TIME="de_DE.UTF-8" LC_COLLATE="de_DE.UTF-8" LC_MONETARY="de_DE.UTF-8" LC_MESSAGES="de_DE.UTF-8" LC_PAPER="de_DE.UTF-8" LC_NAME="de_DE.UTF-8" LC_ADDRESS="de_DE.UTF-8" LC_TELEPHONE="de_DE.UTF-8" LC_MEASUREMENT="de_DE.UTF-8" LC_IDENTIFICATION="de_DE.UTF-8" LC_ALL=
Noch ein paar zusätzliche Pakete:
apt install bind9-host whois nmap lsof man-db apt install arj bzip2 cabextract cpio file gzip nomarch pax rar unrar unzip zip lhasa p7zip ssl-cert lrzip lzop rpm2cpio unrar-free p7zip p7zip-rar apt install gnupg logwatch
Danach habe ich dann einen Reboot veranlasst.
Nachdem der Server wieder erreichbar war (hat recht lange gedauert), habe ich den Rechnernamen angepasst. Das hatte ich im Installimage vergessen zu machen.
joe /etc/hosts
dort alle Einträge mit dem Hetzner-Namen ersetzt (bei IPV4 und IPV6). Dann
joe /etc/hostname
dort ebenfalls den Namen ersetzt und dann
hostname -F /etc/hostname
Zum Abschluss wieder ein Neustart des Servers.
Verzeichnisse
Ein paar Verzeichnisse anlegen:
mkdir /var/log/ustat mkdir /srv/www mkdir /srv/www/typo3src mkdir /etc/webalizer.d mkdir /etc/logrotate.d/apache2-vhosts.d mkdir /etc/vhosts-sicherung.d mkdir /var/log/apache2-vhosts.d mkdir /var/vmail mkdir /var/log/vhosts-sicherung mkdir /home/tmp mkdir /home/server-sicherungen mkdir /var/www mkdir /var/www/vhosts mkdir /var/www/htdocs mkdir /var/www/htdocs/dummy mkdir /var/www/htdocs/webalizer
Webserver
Diese Seite beschreibt die Einrichtung und Konfiguration von virtuellen Servern und beinhaltet:
- MySQL bzw. MariaDB
- Apache
- letsencrypt
Viele Apache-Anwendungen benötigen eine Datenbank. Deshalb im ersten Schritt die Installation von MySQL.
Datenbank-MariaDB
Es gibt zwei bei Ubuntu verfügbare Versionen der Datenbank:
- mysql
- mariadb
Beide sind über die ursprünglichen MySQL-Befehle ansprechbar. MariaDB ist aber die offenere und moderne Version, sie will ich auf diesem Server nutzen.
Zur Installation von Server und Client dient der folgende Aufruf:
apt install mariadb-client mariadb-server mariadb-common
MySQL-Passwort
In aktuellen Datenbank-Versionen hat der Benutzer root keinen Zugriff mittels Passwort und kann daher z.B. auch nicht per phpmyadmin arbeiten. Der folgende MySQL-Befehl zeigt die Einstellung
MariaDB [(none)]> SELECT user,authentication_string,plugin,host FROM mysql.user;
+-------------+-----------------------+-----------------------+-----------+
| User | authentication_string | plugin | Host |
+-------------+-----------------------+-----------------------+-----------+
| mariadb.sys | | mysql_native_password | localhost |
| root | invalid | mysql_native_password | localhost |
| mysql | invalid | mysql_native_password | localhost |
+-------------+-----------------------+-----------------------+-----------+
3 rows in set (0,002 sec)
MariaDB [(none)]> exit;
Bye
Ändern lässt sich diese Einstellung mittels:
use mysql;
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
flush privileges;
Dann ergibt sich:
MariaDB [(none)]> SELECT user,authentication_string,plugin,host FROM mysql.user;
+-------------+-------------------------------------------+-----------------------+-----------+
| User | authentication_string | plugin | Host |
+-------------+-------------------------------------------+-----------------------+-----------+
| mariadb.sys | | mysql_native_password | localhost |
| root | *A9172BC315E0BF4D14D021C4CD16374ED187B2B3 | mysql_native_password | localhost |
| mysql | invalid | mysql_native_password | localhost |
| phpmyadmin | *A9172BC315E0BF4D14D021C4CD16374ED187B2B3 | mysql_native_password | localhost |
+-------------+-------------------------------------------+-----------------------+-----------+
Damit ist das Passwort gesetzt. Will man es später einmal ändern, so muss man berücksichtigen, dass sich das Passwort für MySQL nicht mehr mit den altbekannten Kommandos setzen lässt, weil das Passwort nicht mehr im Feld password, sondern im Feld authentication_string zu finden ist:
use mysql;
UPDATE user SET authentication_string= password('password') WHERE User = 'root';
flush privileges;
und https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-20-04-de
Nachdem das Passwort gesetzt ist, kann sich der Benutzer root auch per phpmyadmin anmelden.
Statt root ein Passwort zu geben kann man auch einen individuellen Benutzer anlegen:
CREATE USER newuser@localhost IDENTIFIED BY 'mystrongpassword';
GRANT ALL PRIVILEGES ON *.* TO newuser@localhost;
FLUSH PRIVILEGES;
MariaDB Logdatei
Bei der Fehlersuche im Mailsystem kann es hilfreich sein, wenn man nachvollziehen kann, was für Anfragen an die Datenbank gestellt wurden. Dazu kann man das Logging aktivieren, was im Normalfall nicht aktive ist, dazu fallen im Betrieb einfach zu viele Logging-Daten an.
Eine Abfrage wie
SHOW VARIABLES LIKE '%general%';
sollte normalerweise
general_log = OFF
liefern.
Die zugehörige Einstellung findet sich in der Datei
/etc/mysql/mariadb.conf.d/50-server.cnf
Dort (ab Zeile 52) die Kommentarzeichen vor den hervorgehobenen Zeilen entferne:
# Both location gets rotated by the cronjob.
# Be aware that this log type is a performance killer.
# Recommend only changing this at runtime for short testing periods if needed!
#general_log_file = /var/log/mysql/mysql.log
#general_log = 1
dann
mkdir -m 2750 /var/log/mysql chown mysql mysql
und
systemctl restart mariadb
Nach erfolgreicher Analyse habe ich das Logging wieder abgestellt.
Weitere Informationen finden sich unter https://www.ionos.at/digitalguide/hosting/hosting-technik/mariadb-logs/
phpMyAdmin
Dieses php-Tool zur Verwaltung der Datenbank ist unheimlich praktisch. Es bietet lokalen Zugriff auf die Datenbank und erspart damit die Öffnung der Datenbank ins Netz. Bei der Installation wird auch gleich der Apache und die notwendigen php-Module mit installiert.
apt install phpmyadmin
Bei der Installation wird gefragt, welchen Webserver man nutzen möchte. Ich wähle den Apache. Am Ende der Installation kann man den Datenbank-Nutzer phpmyadmin anlegen lassen, sein Passwort wird erfragt.
Wer auf den Service mit dem ja dann bekannten Benutzer verzichten möchte, der kann auch vorher oder hinterher einen eigenen Benutzer anlegen.
Man muss also nicht dem Benutzer root den Zugriff ermöglichen. Aus Sicherheitsgründen ist es sowieso sinnvoller, einen individuellen Benutzer anzulegen, da oft genug versucht wird, sich über phpmyadmin einzuloggen. Ich habe mich auch angewöhnt, in der Datei /etc/apache2/conf-available/phpmyadmin.conf die Alias-Zeile auszukommentieren:
#Alias /phpmyadmin /usr/share/phpmyadmin
So kann ich erreichen, dass das Tool nicht allen virtuellen Systemen zur Verfügung steht, sondern die Berechtigung aktiv konfiguriert werden muss.
Nach diesen Schritten kann man aus dem Browser heraus auf http://<Servername>/phpmyadmin zugreifen.
letsencrypt
Für die verschlüsselte Übertragung von Webseiten werden Zertifikate von letsencrypt benötigt. Das notwendige Paket ist bei Ubuntu dabei, aber nur noch als Snap-Paket:
Auf https://certbot.eff.org findet sich eine Anleitung das Snap mit dem Certbot zu installieren. Wenn der snapd auf den Systemen bereits vorhanden ist, geht die Installation relativ einfach in folgenden Schritten (als root):
snap install core snap refresh core snap install --classic certbot
Dann noch einen Link setzen:
ln -s /snap/bin/certbot /usr/bin/certbot
Für jede meiner virtuellen Domains habe ich dann eine letsencrypt.ini erstellt, mit folgendem Inhalt:
# Aufruf mit: /usr/bin/certbot certonly --config /var/www/vhosts/meine-maildomain.de/letsencrypt.ini
# Wir nutzen 4096 bit RSA key statt 2048
rsa-key-size = 4096
# allgemeine Angaben
email = uwe@meine-maildomain.de
authenticator = webroot
# Domains fuer die wir Zertifikate beantragen, die erste in
# der liste legt den Hauptnamen fest. Alle Domains müssen beim
# Aufruf erreichbar sein
domains = meine-maildomain.de, www.meine-maildomain.de
# Dies ist das Verzeichnis zur Domain, wo letsencrypt seinen Hash in
# /.well-known/acme-challenge schreiben will. Der Pfad muss auf / enden
# es muss in der vserver.conf stehen: Alias /.well-known /var/www/htdocs/.well-known
webroot-path = /var/www/htdocs/
Die Reihenfolge der Domains spielt insofern eine Rolle, als die erste Domain als Bezeichner für die Verzeichnisstruktur innerhalb von /etc/letsencrypt benutzt wird. Es bietet sich also an mit einer kürzeren Angabe zu beginnen.
Zum Erzeugen der Zertifikate dient dann der Aufruf:
/usr/bin/certbot certonly --config /var/www/vhosts/meine-maildomain.de/letsencrypt.ini
Die täglichen Aktualisierungsversuche für die Zertifikate übernimmt ein Con-Job, der automatisch angelegt wird (/etc/cron.d/certbot). Leider bekommt man dann keine Mails mehr, sondern muss in die Logdateien schauen, ob alles geklappt hat. Falls mir das auf Dauer nicht gefällt, so mache ich das wieder über den eigenen Cron-Job.
Was ich jetzt erst entdeckt habe, ist das Prinzip der Hooks. Man kann bei letsencript an mehreren Stellen Skripte hinterlegen, die bei Aktualisierung eines Zertifikates aufgerufen werden. Damit kann man z.B. den Webserver oder den Mailserver neu starten.
Zertifikate erweitern
Das Erweitern von letsencrypt Zertifikaten ist relativ einfach. Ich ergänze die Domains-Zeile in der Konfigurationsdatei und rufe den Erzeugungsprozess neu auf. Letsencrypt erkennt die Situation und fragt, ob ich das Zertifikat erweitern oder erneuern möchte. Wählt man hier Erweitern, so wird das passende Zertifikat neu erzeugt.
Zertifikat reduzieren
Manchmal soll eine Domain aus einem Zertifikat entfernt werden, weil man sie eventuell an anderer Stelle benötigt, oder sie nicht mehr verfügbar ist. Ich habe bisher keinen direkten Weg gefunden, wenn man vorgeht wie beim Erweitern und einfach die Liste verkürzt, dann legt Letsenctypt ein zusätzliches Zertifikat an, mit der Ergänzung -0001 am Namen. Man muss also das Zertifikat löschen und neu erstellen.
certbot delete --cert-name MeineDomain
Es geht auch interaktiv mit
certbot delete
es erscheint eine Liste der vorhandenen Zertifikate und man gibt die Nummer des Zertifikates an, das man löschen möchte.
Anschließend legt man das Zertifikat mit der verkleinerten Liste neu an.
Man muss aber damit rechnen, dass man von Letsencrypt Hinweis-Mails bekommt, wenn sich das eigentlich gelöschte Zertifikat dem Ablauf-Zeitpunkt nähert. So weit geht die Lösung nämlich nicht.
Dienste neu starten
In der Regel müssen z.B. die Mail-Dienste neu gestartet werden, wenn das benutzte Zertifikat erneuert wurde. Sonst wird weiterhin das alte Zertifikat benutzt. Letsencrypt kennt Hooks, über die Aktionen ausgelöst werden.
Hier die Datei /etc/letsencrypt/renewal-hooks/deploy/postfix-dovecot-reload.sh
#!/bin/sh
# Dieses script liegt ausführbar in: /etc/letsencrypt/renewal-hooks/deploy
for domain in $RENEWED_DOMAINS
do
if [ "$domain" = "mail.<meine Domain>.de" ]
then
systemctl reload postfix
systemctl reload dovecot
fi
done
Automatische Aktualisierung
Danach kann man dann ausprobieren, ob der Certbot mit den vorhandenen Zertifikaten funktioniert:
certbot renew --dry-run
Denkbar ist dann ein Cronjob der Art:
/usr/bin/certbot renew
Meine Crontab habe ich dann angepasst, obwohl mir nicht ganz klar ist, ob die Aktualisierung nicht schon automatisch geschieht.
Mit
systemctl list-timers
kann man sich die Timer anschauen, die nicht über Cron laufen, sondern über den Systemd-Timer. Es gibt dort einen snap.certbot.renew.timer, der im Verzeichnis /etc/systemd/system/ zu finden ist, aber wohl nur für die Aktualisierung des Snaps zuständig ist.
Sonstige Timer sind übrigens meist im Verzeichnis /lib/systemd/system/ zu finden.
Ein neues Zertifikat erzeugt man dann mit
/usr/bin/certbot certonly --config /var/www/vhosts/<domain>/letsencrypt.ini
Apache
Der Apache Webserver ist ein enorm umfangreiches Stück Software. Ich hoffe, dass meine Konfiguration einigermaßen sinnvoll ist.
Installation
Die folgenden grundlegenden Pakete habe ich installiert
apt install apache2 apache2-bin apache2-data apache2-doc apache2-utils
Dann ein paar Pakete für PHP
apt install libapache2-mod-php php php-auth-sasl php-bz2 php-cli php-db php-gd php-imap php-log php-mail php-curl php-imagick php-intl
apt install php-mbstring php-mdb2 php-mysql php-net-smtp php-phpseclib php-soap php-tcpdf php-zip php-apcu php-opcache
Da sind eventuell noch Doppelungen drin, sowohl das Paket, als auch das Metapaket. Es ist aber das, was mir
dpkg --get-selections | grep php
lieferte.
Nicht vorhanden waren die Pakete php-gettext und php-recode, die Ursache muss ich noch recherchieren.
Nun noch ein paar Perl-Pakete:
apt install libapache2-mod-perl2 libapache2-reload-perl libarchive-zip-perl libauthen-sasl-perl libbsd-resource-perl libcairo-perl libgtk3-perl
apt install libcgi-fast-perl libfile-basedir-perl libfile-desktopentry-perl libfile-mimeinfo-perl libfont-afm-perl libgd-graph-perl libglib-perl
apt install libhtml-form-perl libhtml-format-perl libhtml-template-perl libhttp-daemon-perl libimage-magick-perl libmailtools-perl libnet-dbus-perl libtie-ixhash-perl
apt install libx11-protocol-perl libxml-xpathengine-perl libdbi-perl libdbd-mysql libclass-dbi-mysql-perl
Nach erfolgter Konfiguration (s.u.) darf man nicht vergessen die notwendigen Ports in der Firewall frei zu geben:
ufw allow "Apache Full"
Server-Module
Vorsichtshalber noch einmal ein paar Apache-Module aktivieren:
a2enmod perl a2enmod cgi a2enmod expires a2enmod headers a2enmod rewrite a2enmod ssl a2dismod status service apache2 restart
Da ich viel mit CMS-Systemen arbeite, habe ich etwas an den PHP-Einstellungen gedreht in der /etc/php/8.3/apache2/php.ini:
post_max_size=12M upload_max_filesize=12M max_execution_time=240 max_input_vars = 1500 memory_limit = 512M
Typo3 benötigt unbedingt imagemagick (oder alternativ graphicsmagick)
apt install imagemagick imagemagick-doc
apt install graphicsmagick ghostscript webalizer
locale
Anwendungen wie Owncloud benötigen Zugriff auf die locale-Einstellung über den Apache:
In der Datei: /etc/apache2/envvars
die Kommentarzeichen vor folgender Zeile entfernen:
. /etc/default/locale
Reihenfolge-Probleme bei der Apache-Konfiguration
Bei der Apache-Konfiguration muss man sehr auf die Reihenfolge der einzelnen Einstellungen achten. Dabei spielt der Aufbau der Hauptkonfigurationsdatei /etc/apache2/apache2.conf eine wichtige Rolle. Hier werden der Reihe nach alle Dateien aus folgenden Unterverzeichnissen eingebunden:
- mods-enabled
- conf-enabled
- sites-enabled
Die Dateien aus den einzelnen Verzeichnissen werden dann jeweils in alphabetischer Reihenfolge eingebunden, intern entsteht dabei eine einzige große Konfigurationsdatei. Innerhalb dieser virtuellen Datei spielen die Reihenfolgen eine Rolle.
Bei der Reihenfolge von Alias (auch SriptAlias) Anweisungen und Redirects, die in unterschiedlichen Kontexten auftreten, werden die Direktiven nach den üblichen Zusammenführungsregeln verarbeitet. Wenn jedoch mehrere Aliase oder Redirects im gleichen Kontext (z.B. im gleichen Abschnitt) auftreten, werden sie in einer bestimmten Reihenfolge verarbeitet.
Zunächst werden alle Umleitungen verarbeitet, bevor Aliase verarbeitet werden, und daher werden auf eine Anforderung, die mit einer Umleitung oder einer RedirectMatch übereinstimmt, niemals Aliase angewendet. Zweitens werden die Aliase und Redirects in der Reihenfolge verarbeitet, in der sie in den Konfigurationsdateien erscheinen, wobei die erste Übereinstimmung Vorrang hat.
Wenn also in der /etc/apache2/conf-available/postfixadmin.conf steht
Alias /postfixadmin /usr/share/postfixadmin/public
kann ich dies nicht im allgemeinen Teil der /etc/apache2/sites-available/000-default.conf überschreiben, weil die erst später inkludiert wird. Nur innerhalb einer Directory oder VirtualHost Struktur kann ich Veränderungen vornehmen, weil dies spezieller ist.
Aus dem gleichen Grund muss man, wenn zwei oder mehr dieser Direktiven auf denselben Unterpfad angewendet werden, den spezifischsten Pfad zuerst auflisten, damit alle Direktiven eine Wirkung haben. Zum Beispiel wird die folgende Konfiguration wie erwartet funktionieren:
ScriptAlias /cgi-bin/mailman/ /usr/lib/cgi-bin/mailman/
ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin/"
Aber wenn die beiden oben genannten Richtlinien in umgekehrter Reihenfolge angewendet würden, würde der /cgi-bin vor dem /cgi-bin/mailman-Alias stehen, so dass die letztere Richtlinie ignoriert würde.
Es ist sinnvoll beim Start von Apache auf die Meldungen im Syslog zu achten. Habe ich z.B. den Alias /postfixadmin bei den conf-enabled nicht auskommentiert, so erscheint bei meiner Konfiguration (s.u.) die Meldung
The Alias directive in /etc/apache2/sites-enabled/000-default.conf at line 19 will probably never match because it overlaps an earlier Alias.
/etc/apache2/sites-available/000-default.conf
Diese Datei besteht bei mir aus drei Teilen:
- Zuerst die allgemeinen Einstellungen, die dann für alle virtuellen Systeme gelten, sofern sie nicht überschrieben werden.
- Dann der virtuelle Default-Server für Port 80. Er würde aufgerufen, wenn jemand über die IP-Adresse, den Namen beim Provider (static.w.x.y.z.clients.your-server.de) oder eine nicht vorgesehene Domain kommt.
- Der entsprechende virtuelle Default-Server für Port 443.
Die virtuellen Standard-Server sind auch im Zusammenhang mit letsencrypt-Zertifikaten für den Mailserver ganz praktisch. Ich muss nicht für mail.meine-maildomain.de eine Webseite konfigurieren, wenn ich ein Zertifikat erstellen oder erweitern möchte. Letsencrypt landet im Zweifelsfall hier und kann den Zugriff verifizieren. Der Standard-Server auf Port 443 erleichtert dann die Kontrolle der erstellten Zertifikate für den Mailserver, wenn das hier angegebene Zertifikat auch im Mailsystem genutzt wird.
ServerName default
ServerAdmin Uwe@meine-maildomain.de
ServerTokens Major
ServerSignature off
TraceEnable off
ProxyRequests off
UseCanonicalName Off
DocumentRoot /var/www/vhosts/default/httpdocs
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
CustomLog /var/log/apache2/vhosts_access.log vhost_combined
Alias /webmail /var/www/htdocs/dummy
Alias /phpmyadmin /var/www/htdocs/dummy
Alias /postfixadmin /var/www/htdocs/dummy
Alias /webstat /var/www/htdocs/webalizer
Alias /roundcube /var/lib/roundcube
<IfDefine MAILMAN>
ScriptAlias /mailman/ /var/www/htdocs/dummy
Alias /mailmanicons/ /var/www/htdocs/dummy
Alias /pipermail/ /var/www/htdocs/dummy
</IfDefine>
<IfModule mod_userdir.c>
UserDir disabled
</IfModule>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 month"
ExpiresByType text/html "access plus 1 week"
ExpiresByType image/gif "access plus 1 week"
ExpiresByType image/jpeg "access plus 1 week"
ExpiresByType image/png "access plus 1 week"
ExpiresByType text/css "access plus 1 week"
ExpiresByType text/javascript "access plus 1 week"
ExpiresByType application/x-javascript "access plus 1 week"
ExpiresByType text/xml "access plus 1 week"
</IfModule>
<IfModule mod_setenvif.c>
# SEO
BrowserMatchNoCase (mindUp|meanpathbot|seoscanners|AiHitBot|BLEXBot|DotBot|linkdexbot|MJ12bot|SEOkicks-Robot) ist_ein_bot
# Sammeln Backlinks & Links
BrowserMatchNoCase (exabot|Baidu|Haosou|Semrush|MegaIndex|AhrefsBot|BacklinkCrawler|dlcbot|spbot) ist_ein_bot
# Performance Testing
BrowserMatchNoCase (200PleaseBot|LoadTimeBot) ist_ein_bot
# BilderSuche
BrowserMatchNoCase (psbot|Yandex) ist_ein_bot
# Harvester & Marketing
BrowserMatchNoCase (MegaIndex|Applebot|XoviBot|CareerBot|GrapeshotCrawler|iCjobs|magpie-crawler|proximic) ist_ein_bot
# Nutzlos, Schlecht bzw. unbekannt
BrowserMatchNoCase (PetalBot|360Spider|AfD-Verbotsverfahren|Barkrowler|PeoplePal|ltx71|CalendarAgent|JobboerseBot|GarlikCrawler|Mail.RU_B
# Per IP
SetEnvIfNoCase Remote_Addr (62\.138\.0\.25) ist_ein_bot
# kyivstar.net
SetEnvIfNoCase Remote_Addr ^(5\.248|46\.118|37\.115|178\.137) ist_ein_bot
# Einträge von 2020
BrowserMatchNoCase (MaviBot|oBot|MetaJobBot|seocompany|coccocbot-image|SeznamBot) ist_ein_bot
</IfModule>
<IfModule mod_ssl.c>
SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder On
SSLCompression off
SSLCipherSuite ALL:!aNULL:RC4+RSA:+HIGH:+MEDIUM:+LOW:+EXP:+eNULL
</IfModule>
<Directory "/var/www/vhosts">
AllowOverride All
Options +SymLinksIfOwnerMatch -Indexes
Require all granted
<IfModule mod_php.c>
php_value date.timezone "Europe/Berlin"
php_value open_basedir /var/www/:/tmp/
php_value include_path /var/www/:/tmp/
</IfModule>
</Directory>
<VirtualHost *:80>
Alias /.well-known /var/www/htdocs/.well-known
<Directory /var/www/vhosts/default/httpdocs>
AllowOverride All
Options None
Require all granted
</Directory>
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost _default_:443 >
SSLEngine on
# Wenn das erste Zertifikat mit Letsencryp erstellt ist, dann die Zertifikate austauschen
# SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
# SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
SSLCertificateFile /etc/letsencrypt/live/<dummy>/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/<dummy>/privkey.pem
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /var/www/vhosts/default/httpdocs>
SSLRequireSSL
AllowOverride All
Options None
Require all granted
</Directory>
</VirtualHost>
</IfModule>
Die, hier auskommentierten SnakeOil-Zertifikate sind vom Server selbst erstellte Zertifikate, die man nur zum Testen nutzen sollte. Falls sie nicht vorhanden sind, dann kann man sie erzeugen mittels:
make-ssl-cert
Weitere Hinweise dazu unter https://www.thomas-krenn.com/de/wiki/Ubuntu_default_snakeoil_SSL-Zertifikat_erneuern
Die SSL-Einstellungen der Seite kann man unter https://www.cdn77.com/tls-test (Hinweis: deren Cache lässt sich anscheinend nicht löschen) und ganz ausführlich unter https://www.ssllabs.com/ssltest/ testen lassen. Es geht übrigens auch ohne externen Dienstleister mittels
nmap --script ssl-enum-ciphers -p 443 example.com
Ursprünglich hatte ich hier auch einen Alias für .well-known mir drin, das führt aber zu Problemen bei z.B. Nextcloud, hier wird mit Unterverzeichnissen von .well-known gearbeitet und dann treten Probleme mit der Reihenfolge auf.
Vserver-Konfiguration
Für jeden weiteren VServer erfolgt die Konfiguration in /etc/apache2/vhosts/sites-available/<dummy>.conf nach folgendem System, wobei <dummy> durch z.B. den Domainnamen ersetzt wird. Das zugehörige Verzeichnis wird dann mit diesem Namen unterhalb von /var/www/vhosts/ angelegt.
<VirtualHost *:80>
ServerName www.<dummy>:80
ServerAlias <dummy>
DocumentRoot /var/www/vhosts/<dummy>/httpdocs
CustomLog /var/log/apache2/<dummy>_access.log combined
ErrorLog /var/log/apache2/<dummy>_error.log
CustomLog /var/log/apache2/vhosts_access.log vhost_combined
ScriptAlias /cgi-bin/ /var/www/vhosts/<dummy>/cgi-bin/
Alias /webstat /var/www/vhosts/<dummy>/webstat
Alias /.well-known /var/www/htdocs/.well-known
# Nur bei Bedarf aktivieren
# Alias /phpmyadmin /usr/share/phpmyadmin
# Alias /postfixadmin /usr/share/postfixadmin/public
<Directory /var/www/vhosts/<dummy>/httpdocs>
<IfModule mod_setenvif.c>
<RequireAll>
Require all granted
Require not env ist_ein_bot
</RequireAll>
</IfModule>
<IfModule mod_php.c>
php_admin_flag engine on
php_admin_value include_path "/var/www/vhosts/<dummy>/httpdocs:.:/tmp:./:/usr/share/php/PEAR/:/srv/www/typo3src:/usr/bin"
php_admin_value open_basedir "/var/www/vhosts/<dummy>/httpdocs:/tmp:.:/usr/share/php/PEAR/:/srv/www/typo3src:/usr/bin"
</IfModule>
Options -Includes +ExecCGI
</Directory>
<Directory "/var/www/vhosts/<dummy>/cgi-bin">
AllowOverride None
Options +ExecCGI -Includes
Require all granted
</Directory>
</VirtualHost>
# soll SSL aktiviert werden das _no entfernen
<IfModule mod_ssl_no.c>
<VirtualHost *:443>
ServerName www.<dummy>:443
ServerAlias <dummy>
DocumentRoot /var/www/vhosts/<dummy>/httpdocs
CustomLog /var/log/apache2/<dummy>_access.log combined
ErrorLog /var/log/apache2/<dummy>_error.log
CustomLog /var/log/apache2/vhosts_access.log vhost_combined
ScriptAlias /cgi-bin/ /var/www/vhosts/<dummy>/cgi-bin/
Alias /webstat /var/www/vhosts/<dummy>/webstat
Alias /.well-known /var/www/htdocs/.well-known
# Nur bei Bedarf aktivieren
# Alias /phpmyadmin /usr/share/phpmyadmin
# Alias /postfixadmin /usr/share/postfixadmin/public
SSLEngine on
<Directory /var/www/vhosts/<dummy>/httpdocs>
<IfModule mod_setenvif.c>
<RequireAll>
Require all granted
Require not env ist_ein_bot
</RequireAll>
</IfModule>
<IfModule mod_php.c>
php_admin_flag engine on
php_admin_value include_path "/var/www/vhosts/<dummy>/httpdocs:.:/tmp:./:/usr/share/php/PEAR/:/srv/www/typo3src:/usr/bin"
php_admin_value open_basedir "/var/www/vhosts/<dummy>/httpdocs:/tmp:.:/usr/share/php/PEAR/:/srv/www/typo3src:/usr/bin"
</IfModule>
Options -Includes +ExecCGI
</Directory>
<Directory "/var/www/vhosts/<dummy>/cgi-bin">
AllowOverride None
Options +ExecCGI -Includes
Require all granted
</Directory>
SSLCertificateFile /etc/letsencrypt/live/<dummy>/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/<dummy>/privkey.pem
</VirtualHost>
</IfModule>
Verwaltungs-Vserver
Für die Nutzung von
- postfixadmin
- phpmyadmin
- rspamd
- eigenen CGI Scripten
habe ich mir einen speziellen virtuellen Server erstellt, der keine eigenen Ordner bekommt, sondern auf dem Default-Server aufsetzt. /etc/apache2/vhosts/sites-available/verwaltung.conf
<VirtualHost *:80>
ServerName verwaltung.<dummy>:80
DocumentRoot /var/www/vhosts/default/httpdocs
CustomLog /var/log/apache2/verwaltung_access.log combined
ErrorLog /var/log/apache2/verwaltung_error.log
CustomLog /var/log/apache2/vhosts_access.log vhost_combined
ScriptAlias /cgi-bin/ /var/www/vhosts/default/cgi-bin/
Alias /webstat /var/www/vhosts/default/webstat
Alias /phpmyadmin /usr/share/phpmyadmin
Alias /postfixadmin /usr/share/postfixadmin/public
Alias /.well-known /var/www/htdocs/.well-known
<Directory /var/www/vhosts/default/httpdocs>
<IfModule mod_setenvif.c>
<RequireAll>
Require all granted
Require not env ist_ein_bot
</RequireAll>
</IfModule>
Options -Includes +ExecCGI
</Directory>
<Directory "/var/www/vhosts/default/cgi-bin">
AllowOverride None
Options +ExecCGI -Includes
Require all granted
</Directory>
RewriteEngine On
ProxyRequests Off
<Location /rspamd>
Order allow,deny
Allow from all
</Location>
RewriteRule ^/rspamd$ /rspamd/ [R,L]
RewriteRule ^/rspamd/(.*) http://localhost:11334/$1 [P,L]
</VirtualHost>
# soll SSL aktiviert werden das _no entfernen
<IfModule mod_ssl_no.c>
<VirtualHost *:443>
ServerName verwaltung.<dummy>:443
DocumentRoot /var/www/vhosts/default/httpdocs
CustomLog /var/log/apache2/verwaltung_access.log combined
ErrorLog /var/log/apache2/verwaltung_error.log
ScriptAlias /cgi-bin/ /var/www/vhosts/default/cgi-bin/
Alias /webstat /var/www/vhosts/default/webstat
Alias /phpmyadmin /usr/share/phpmyadmin
Alias /postfixadmin /usr/share/postfixadmin/public
Alias /.well-known /var/www/htdocs/.well-known
SSLEngine on
<Directory /var/www/vhosts/default/httpdocs>
<IfModule mod_setenvif.c>
<RequireAll>
Require all granted
Require not env ist_ein_bot
</RequireAll>
</IfModule>
Options -Includes +ExecCGI
</Directory>
<Directory "/var/www/vhosts/default/cgi-bin">
AllowOverride None
Options +ExecCGI -Includes
Require all granted
</Directory>
SSLCertificateFile /etc/letsencrypt/live/verwaltung.<dummy>/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/verwaltung.<dummy>/privkey.pem
RewriteEngine On
ProxyRequests Off
<Location /rspamd>
Order allow,deny
Allow from all
</Location>
RewriteRule ^/rspamd$ /rspamd/ [R,L]
RewriteRule ^/rspamd/(.*) http://localhost:11334/$1 [P,L]
</VirtualHost>
</IfModule>
Logdateien
Da ich die Logdateien für meine virtuellen Server mit Webalizer auswerten möchte, brauche ich eine Erweiterung für Logrotate:
/var/log/apache2/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 root adm
sharedscripts
postrotate
if invoke-rc.d apache2 status > /dev/null 2>&1; then \
invoke-rc.d apache2 reload > /dev/null 2>&1; \
fi;
endscript
prerotate
/root/webalizer.sh
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi; \
endscript
}
Entweder hängt man diesen Teil an /etc/logrotate.d/apache2 an oder man erstellt eine neue Datei /etc/logrotate.d/apache-vhosts .
Mailsystem
Das Mail-System besitzt folgende Komponenten bzw. Funktionen:
- Postfixadmin zur Verwaltung der virtuellen Benutzer
- Dovecot als POP und IMAP-Server
- Postfix als Mailserver
- rspamd über die Milter-Schnittstelle und
- redis als leichte Datenbank für rspamd
- spf und dkim sollen auch aktiviert sein
- Roundcube als Mailclient
SPF, DKIM und DMARC gegen Spam
Mailserver sind von Natur aus vertrauensselig, was von Spammern ausgenutzt wird. Ich denke, dass mehr als 90% aller versendeten Nachrichten in die Kategorie Spam gehören. Der Mailserver Postfix beherrscht ein von Haus aus ein paar Möglichkeiten den Spam zu verringern:
- Nutzung von RBL Listen in den smtpd_client_restrictions. Für jede eingehende Mail werden dann externe Server wie cbl.abuseat.org befragt, ob sie den sendenden Server kennen. Wenn ja, dann wird die Mail rejected. Damit dieses System effektiv wird, muss man aber mehrere derartige Server parallel nutzen.
- Regeln über den formalen Aufbau einer Mail z.B. in den smtpd_helo_restrictions. Hier kann man mit reject_invalid_helo_hostname erreichen, dass nur Mails von Servern angenommen werden, bei denen der Name nicht korrekt ist.
Für weitergehende Untersuchungen, z.B. auf Viren oder Spam bindet man in der Regel zusätzliche Hilf-Programme ein, in der Regel SpamAssassin oder neuerdings auch rspamd. Diese Programme teilen dem Mailserver mit, wie mit der Mail weiter zu verfahren ist. Dabei taucht das Problem auf, dass eine Mail die der Mailserver angenommen hat auch zugestellt werden muss, sofern sich keinen direkten Schadcode beinhaltet. Normaler Spam muss also zugestellt werden, wenn die Mail nicht frühzeitig als Spam erkannt und daher nicht angenommen wird.
Die Spamfilter klassifizieren jede Mail anhand unterschiedlicher Regeln bzw. Kriterien und vergeben dabei einen Score. Je höher der Score, desto wahrscheinlicher handelt es sich um Spam.
Mit der Nutzung von SPF, DKIM und DMARC möchte ich erreichen, dass der Score meiner Mails auf anderen Servern gesenkt wird und sollte jemand mit einer meiner Domains illegal Mails verschicken, so soll sich deren Score erhöhen. Das ist die Idee hinter diesen Konzepten.
SPF
Das Policy Framework (SPF) dient dazu, die Mail anhand der IP Adresse des sendenden Mailservers zu überprüfen. Dazu wird in einem speziellen Namesereintrag vom Typ TXT festgelegt, welche Server berechtigt sind Mails mit dieser Domain zu verschicken.
Im einfachsten Fall sieht der TXT Eintrag folgendermaßen aus:
v=spf1 a mx -all
Ein
dig -t txt meine-maildomain.de
liefert dann
meine-maildomain.de. 3600 IN TXT "v=spf1 a mx -all"
Damit wird ausgesagt, dass nur Server, die einen A- oder einen MX-Eintrag in dieser Domain besitzen berechtigt sind Mails abzuliefern. Über das -all wird festgelegt, wie zu verfahren ist, wenn sich ein Server meldet, der der Regel nicht entspricht.
- -all : Fail der Server darf nicht senden
- ~all : SoftFail der Server darf eigentlich nicht senden, sei aber großzügig
- ?all : Neutral jeder Sender wird akzeptiert.
Ausführlichere Beschreibung der Syntax unter https://www.spf-record.de/syntax
Ein Vorteil von SPF ist, dass am sendenden Server keinerlei Konfiguration notwendig ist. Der größte Nachteil besteht darin, dass es bei Weiterleitungen Probleme gibt, da dann der sendende Server nicht mehr zum Absender passt.
Domainfactory generiert übrigens automatisch auch einen Catchall Eintrag für SPF.
DKIM
Auch das System Keys Identified Mail (DKIM) dient auch dazu nur bestimmte Server zum Senden zu authentifizieren. Das geschieht, indem jede ausgehende Mail im Header digital signiert wird. Der öffentlichen Schlüssel hierzu ist im Nameserver hinterlegt. Der private Schlüssel muss natürlich geschützt auf dem sendenden Server liegen. Da mehrere Server sendeberechtigt sein können, kann es auch mehrere derartige Schlüssel geben. Deshalb wird zusätzlich ein sog. Selektor mit im Mail-Header hinterlegt, damit der Empfänger den richtigen Schlüssel wählen kann.
dig -t txt 2020._domainkey.meine-maildomain.de
liefert dann
2020._domainkey.meine-maildomain.de. 3600 IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClkpAaTMA5GcACTbSfJ1vSGwJyHnv1IVzR4GEu3PMAAIvuYCWPONypEAErZJciY8gK+z3FoPaMdsB+eii4rozlN6Jtfx+Fi/SM0FWV1PvPVI0tkoIXa82lKfJi4hqbWDHXxQYfROEKNFWZtoG/C951MwNOiq34Vk3X0nNoBWfyHwIDAQAB"
In diesem Beispiel ist 2020 der Selector. Damit der Mailclient den richtigen Schlüssel abfragen kann, findet sich in DKIM-Header ein Bereich s=2020.
Weitere Informationen unter https://de.wikipedia.org/wiki/DomainKeys
Ein großer Vorteil von DKIM gegenüber SPF ist, dass Weiterleitungen kein Problem sind. Der versendende Server spielt ja keine Rolle. Ein großer Nachteil ist, dass der Server entsprechend konfiguriert werden muss, damit er die richtigen Header-Zeilen erzeugen kann.
DMARC
Das Konzept Message Authentication, Reporting and Conformance (DMARC) baut auf SPF und DKIM auf. Mit DMARC kann der Absender zusätzlich Empfehlungen geben, auf welche Art der Empfänger mit einer Mail umgeht, die in einem oder beiden Fällen nicht den Anforderungen entspricht.
Es gibt die folgenden Regeln
- p=reject lehnt Mail ab, bei denen die Prüfung fehlgeschlagen ist
- p=quarantine lässt Mail in den Spam-Ordner verschieben, bei denen die Überprüfung fehlgeschlagen ist
- p=none weist den empfangenden Server an Berichte an die Mailadresse zu schicken, die per rua bzw. ruf hinterlegt wurde. Dazu ein Beispiel aus Wikipedia
v=DMARC1;p=quarantine;pct=100;rua=mailto:postmaster@example.org;ruf=mailto:forensik@example.org;adkim=s;aspf=r
Dann ein paar zusätzliche Parameter:
- pct: gibt an, auf wieviel Prozent der Nachrichten die Regel angewandt wird (Standard: 100)
- rua: Mail-Adresse, an die der aggregierte Bericht gesendet werden soll
- ruf: Mail-Adresse, an die der forensische Bericht gesendet werden soll
- fo: Festlegung, in welcher Situation Daten für einen Bericht gesammelt werden sollen:
- 0 (Bericht, wenn SPF+DKIM fehlschlagen)
- 1 (Bericht, wenn SPF oder DKIM fehlschlagen)
- s (Bericht, wenn SPF fehlschlägt)
- d (Bericht, wenn DKIM fehlschlägt)
- adkim: müssen bei DKIM Domain und Subdomain übereinstimmen?
- r (relaxed) ist Standard
- s (strict)
- aspf: müssen bei SPF Domain und Subdomain übereinstimmen?
- r (relaxed) ist Standard
- s (strict)
- ri: Häufigkeit in Sekunden, mit der die Berichte gesendet werden. Standard: 86400 (ein Tag)
Weitere Informationen unter: https://de.wikipedia.org/wiki/DMARC
dig -t txt _dmarc.meine-maildomain.de
liefert hier
_dmarc.meine-maildomain.de. 3599 IN TXT "v=DMARC1; p=reject;"
Hinweis zu dig
Wer auf seinem Rechner nicht über das Programm dig verfügt, der kann die entsprechenden Anfragen über die folgenden Webseiten aufrufen:
Vorbereitungen
Für die folgende Beschreibung wird ein Benutzer vmail (uid 303) und eine Gruppe vmail (gid 303) benutzt. Der Benutzer hat als Homeverzeichnis /var/vmail, wo dann auch die eingehenden Mails liegen.
Da Gruppe und Benutzer nicht vorhanden sind, legt man sie neu an:
groupadd -g 303 vmail
mkdir /var/vmail
chmod a+rxw /var/vmail
useradd -d /var/vmail/ -s /bin/false -u 303 -g 303 vmail
Postfixadmin
Die Beschreibung geht aus von dem Programmpaket PostfixAdmin, welches die Verwaltung der virtuellen Mail-Adressen über ein kleines nettes Webfrontend erlaubt. Die Homepage dieses Programms ist http://postfixadmin.sourceforge.net/. Das Programmpaket greift nur auf eine MySQL-Datenbank zu und nicht direkt in das Mailsystem ein. Alle Änderungen erfolgen nur an und in der Datenbank. Von daher ist es sinnvoll dies als erste Komponente zu installieren.
Das Programm lässt sich ganz einfach über die Paketverwaltung installieren und liegt in der Version 3.3.x vor.
apt install postfixadmin
Bei der Installation kann man gleich die notwendigen Datenbank-Einstellungen mit anlegen lassen. Bei einem ganz neuen System bietet sich das an.
Das Programm wird im Verzeichnis /usr/share/postfixadmin eingerichtet und die Konfigurationsdateien sind auf /etc/postfixadmin verlinkt.
Datenbanken
Für das Tool wird eine Datenbank mit folgenden Tabellen benötigt (So legt sie Postfixadmin über http://<server>/postfixadmin/setup.php an, bzw. aktualisiert sie beim Aufruf der Seite, das kann dann übrigens etwas dauern).
CREATE TABLE `admin` (
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`superadmin` tinyint(1) NOT NULL DEFAULT '0',
`created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`modified` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
`phone` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`email_other` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`token` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`token_validity` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
PRIMARY KEY (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Admins';
CREATE TABLE `alias` (
`address` varchar(255) NOT NULL,
`goto` text NOT NULL,
`domain` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`modified` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`address`),
KEY `domain` (`domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Aliases';
CREATE TABLE `alias_domain` (
`alias_domain` varchar(255) NOT NULL DEFAULT '',
`target_domain` varchar(255) NOT NULL DEFAULT '',
`created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`modified` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`alias_domain`),
KEY `active` (`active`),
KEY `target_domain` (`target_domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Domain Aliases';
CREATE TABLE `config` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(20) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '',
`value` varchar(20) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=ucs2 COMMENT='PostfixAdmin settings';
CREATE TABLE `domain` (
`domain` varchar(255) NOT NULL,
`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`aliases` int NOT NULL DEFAULT '0',
`mailboxes` int NOT NULL DEFAULT '0',
`maxquota` bigint NOT NULL DEFAULT '0',
`quota` bigint NOT NULL DEFAULT '0',
`transport` varchar(255) NOT NULL,
`backupmx` tinyint(1) NOT NULL DEFAULT '0',
`created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`modified` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Domains';
CREATE TABLE `domain_admins` (
`username` varchar(255) NOT NULL,
`domain` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
KEY `username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Domain Admins';
CREATE TABLE `fetchmail` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`domain` varchar(255) DEFAULT '',
`mailbox` varchar(255) NOT NULL,
`src_server` varchar(255) NOT NULL,
`src_auth` enum('password','kerberos_v5','kerberos','kerberos_v4','gssapi','cram-md5','otp','ntlm','msn','ssh','any') CHARACTER SET ucs2 C
`src_user` varchar(255) NOT NULL,
`src_password` varchar(255) NOT NULL,
`src_folder` varchar(255) NOT NULL,
`poll_time` int unsigned NOT NULL DEFAULT '10',
`fetchall` tinyint unsigned NOT NULL DEFAULT '0',
`keep` tinyint unsigned NOT NULL DEFAULT '0',
`protocol` enum('POP3','IMAP','POP2','ETRN','AUTO') CHARACTER SET ucs2 COLLATE ucs2_general_ci DEFAULT NULL,
`usessl` tinyint unsigned NOT NULL DEFAULT '0',
`sslcertck` tinyint(1) NOT NULL DEFAULT '0',
`sslcertpath` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
`sslfingerprint` varchar(255) DEFAULT '',
`extra_options` text,
`returned_text` text,
`mda` varchar(255) NOT NULL,
`date` timestamp NOT NULL DEFAULT '1999-12-31 23:00:00',
`created` timestamp NOT NULL DEFAULT '1999-12-31 23:00:00',
`modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`active` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE `log` (
`timestamp` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`username` varchar(255) NOT NULL,
`domain` varchar(255) NOT NULL,
`action` varchar(255) NOT NULL,
`data` text NOT NULL,
`id` int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `timestamp` (`timestamp`),
KEY `domain_timestamp` (`domain`,`timestamp`)
) ENGINE=MyISAM AUTO_INCREMENT=455 DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Log';
CREATE TABLE `mailbox` (
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`maildir` varchar(255) NOT NULL,
`quota` bigint NOT NULL DEFAULT '0',
`local_part` varchar(255) NOT NULL,
`domain` varchar(255) NOT NULL,
`created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`modified` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`active` tinyint(1) NOT NULL DEFAULT '1',
`phone` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`email_other` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`token` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`token_validity` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
PRIMARY KEY (`username`),
KEY `domain` (`domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Mailboxes';
CREATE TABLE `quota` (
`username` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
`path` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
`current` bigint DEFAULT NULL,
PRIMARY KEY (`username`,`path`)
) ENGINE=MyISAM DEFAULT CHARSET=ucs2;
CREATE TABLE `quota2` (
`username` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
`bytes` bigint NOT NULL DEFAULT '0',
`messages` int NOT NULL DEFAULT '0',
PRIMARY KEY (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=ucs2;
CREATE TABLE `vacation` (
`email` varchar(255) NOT NULL,
`subject` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`body` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`activefrom` timestamp NOT NULL DEFAULT '1999-12-31 23:00:00',
`activeuntil` timestamp NOT NULL DEFAULT '2038-01-17 23:00:00',
`cache` text NOT NULL,
`domain` varchar(255) NOT NULL,
`interval_time` int NOT NULL DEFAULT '0',
`created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
`modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`email`),
KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Vacation';
CREATE TABLE `vacation_notification` (
`on_vacation` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
`notified` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '',
`notified_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`on_vacation`,`notified`),
CONSTRAINT `vacation_notification_pkey` FOREIGN KEY (`on_vacation`) REFERENCES `vacation` (`email`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Postfix Admin - Virtual Vacation Notifications';
Nicht alle Tabellen werden in meiner Konfiguration wirklich benutzt, aber es ist einfacher alle anzulegen.
/etc/postfixadmin/dbconfig.inc.php
Die Datenbankanbindung wird in der Ubuntu-Version über diese Datei konfiguriert.
<?php
##
## database access settings in php format
## automatically generated from /etc/dbconfig-common/postfixadmin.conf
## by /usr/sbin/dbconfig-generate-include
##
## by default this file is managed via ucf, so you shouldn't have to
## worry about manual changes being silently discarded. *however*,
## you'll probably also want to edit the configuration file mentioned
## above too.
##
$dbuser='postfix';
$dbpass='assword';
$basepath='';
$dbname='postfix';
$dbserver='localhost';
$dbport='';
$dbtype='mysqli';
/etc/postfixadmin/config.local.php
Die momentan aktuelle Version besitzt eine Reihe von neuen Funktionen. Schöne bei dieser Version ist die Konfiguration, die sich in einer Datei config.local.php sammeln lässt. Außerdem sind die Voreinstellungen deutlich dichter an meinen Wünschen. Es bleibt dann hier:
<?php
$CONF['configured'] = true;
// on submission it will be echoed out to you as a hashed value.
$CONF['setup_password'] = '7caf48fdc954f6037dcc0a6438358db0:9fdf45d7c3dd759258e8af37d09b361218428af5';
$CONF['default_language'] = 'de';
$CONF['admin_email'] = 'postmaster@meine-maildomain.de';
$CONF['page_size'] = '20';
$CONF['default_aliases'] = array (
'abuse' => 'abuse@meine-maildomain.de',
'hostmaster' => 'hostmaster@meine-maildomain.de',
'postmaster' => 'postmaster@meine-maildomain.de',
'webmaster' => 'webmaster@meine-maildomain.de'
);
$CONF['quota'] = 'YES';
$CONF['footer_text'] = 'Zurück zu Debacher.de';
$CONF['footer_link'] = 'http://debacher.de';
// Welcome Message
// This message is send to every newly created mailbox.
// Change the text between EOM.
$CONF['welcome_text'] = <<<EOM
Herzlich Willkommen,
zum Debacher E-Mail Postfach.
Bei Fragen oder Problemen bitte
Uwe Debacher ansprechen
EOM;
$CONF['show_undeliverable_exceptions']=array("meine-maildomain.de");
$CONF['used_quotas'] = 'YES';
$CONF['maxquota'] = '2048';
$CONF['domain_quota_default'] = '0';
Probleme mit PostfixAdmin
Beim ersten Start tauchte eine Fehlermeldung auf:
ERROR: the templates_c directory doesn't exist or isn't writeable for the webserver
Ich habe dann dieses Verzeichnis angelegt und dem Webserver übereignet.
mkdir /usr/share/postfixadmin/templates_c chown www-data.www-data /usr/share/postfixadmin/templates_c
Danach dann
DEBUG INFORMATION: MySQL 3.x / 4.0 functions not available! (php5-mysql installed?) database_type = 'mysql' in config.inc.php, are you using a different database? Please check the documentation and website for more information.
Dazu muss man dann in der Datei /etc/postfixadmin/dbconfig.inc.php die Zeile
$dbtype='mysql';
ändern in
$dbtype='mysqli';
Die gleichen Einstellungen finden sich auch noch einmal in der Datei /etc/dbconfig-common/postfixadmin.conf
Aktuell ist bei der Version 3.2 eine kleine Änderung zu beachten, der Alias-Eintrag in der VServer-Konfiguration muss jetzt auf das Unterverzeichnis public zeigen:
Alias /postfixadmin /usr/share/postfixadmin/public
Die entsprechende Einstellung ist zwar in der Datei /etc/apache2/conf-available/postfixadmin.conf schon vorhanden, dann ist PostfixAdmin aber in allen virtuellen Domains vorhanden. Ich habe diese Zeile also dort auskommentiert und füge die Zeile in den virtuellen Server ein in dem ich sie haben möchte.
Beim Aufruf der setup.php gab es immer den Hinweis, dass die Datei config.local.php nicht gefunden werden könnte. Das scheint mir eine Falschinformation zu sein, was man schnell damit überprüfen kann, dass man in dieser Datei in der ersten Zeile
$CONF['configured'] = false;
setzt. Die Einstellung wird dann im setup.php kritisiert. Setzt man das wieder auf true, dann kann es weitergehen. Man muss im Webinterface zuerst ein Setup-Passwort erstellen und in die Konfigurationsdatei eintragen, danach muss man dann noch den Superadmin erstellen.
An der Datei /etc/postfixadmin/config.local.php habe ich nur wenig verändert und das auch hauptsächlich Kosmetik
<?php
$CONF['configured'] = true;
// on submission it will be echoed out to you as a hashed value.
$CONF['setup_password'] = '7caf48fdc954f6037dcc0a6438358db0:9fdf45d7c3dd759258e8af37d09b361218428af5';
$CONF['default_language'] = 'de';
$CONF['admin_email'] = 'postmaster@meine-maildomain.de';
$CONF['page_size'] = '20';
$CONF['default_aliases'] = array (
'abuse' => 'abuse@meine-maildomain.de',
'hostmaster' => 'hostmaster@meine-maildomain.de',
'postmaster' => 'postmaster@meine-maildomain.de',
'webmaster' => 'webmaster@meine-maildomain.de'
);
$CONF['quota'] = 'YES';
$CONF['footer_text'] = 'Zurück zu Debacher.de';
$CONF['footer_link'] = 'http://debacher.de';
// Welcome Message
// This message is send to every newly created mailbox.
// Change the text between EOM.
$CONF['welcome_text'] = <<<EOM
Herzlich Willkommen,
zum Debacher E-Mail Postfach.
Bei Fragen oder Problemen bitte
Uwe Debacher ansprechen
EOM;
$CONF['show_undeliverable_exceptions']=array("meine-maildomain.de");
$CONF['used_quotas'] = 'YES';
$CONF['maxquota'] = '2048';
$CONF['domain_quota_default'] = '0';
Dovecot
Eigentlich ist Dovecot nur ein Server für POP3 und Imap. Inzwischen kann dieses Programm deutlich mehr. Die Zugriffe auf die Datenbank mit den virtuellen Usern erfolgt in der Regel über Dovecot. Das geht bis zur Nachrichten-Zustellung in die Postfächer.
apt install dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql dovecot-sieve dovecot-managesieved dovecot-pop3d dovecot-antispam service dovecot stop
Die Versionsnummer von dovecot kann man abfragen mittels
dovecot --version
/etc/dovecot/local.conf
Ich habe die Konfiguration in einer eigenen Datei /etc/dovecot/local.conf gesammelt: (hervorgehoben die Zeilen mit individueller Konfiguration)
##
## Protokollierung
##
#mail_debug = yes
#auth_debug = yes
auth_debug_passwords = yes
#auth_verbose = yes
auth_verbose_passwords = sha1
#verbose_proctitle = yes
##
## Grundeinstellungen
##
first_valid_uid = 303
mail_access_groups = postfix
mail_privileged_group = vmail
mail_uid = vmail
mail_gid = vmail
protocols = imap pop3 lmtp sieve
# die folgenden Einstellungen sind nicht optimal, da die home-Verzeichnisse so nicht automatisch angelegt werden
# geschickter wäre (dann auch dovecot-mysql.conf anpassen):
#mail_home = /var/vmail/%d/%n
#mail_location = maildir:/var/vmail/%d/%n/mail oder mail_location = maildir:~/Maildir
mail_location = maildir:/var/vmail/%d/%n
mail_home = /var/vmail/%d/%n/home
mail_plugins = $mail_plugins quota
disable_plaintext_auth = no
auth_mechanisms = plain login
##
##TLS Konfiguration
##
ssl = yes
ssl_cert = </etc/letsencrypt/live/meine-maildomain.de/fullchain.pem
ssl_key = </etc/letsencrypt/live/meine-maildomain.de/privkey.pem
#ssl_cert = </etc/ssl/certs/ssl-cert-snakeoil.pem
#ssl_key = </etc/ssl/private/ssl-cert-snakeoil.key
# die beiden folgenden Parameter gibt es erst ab dc 2.3 (Ubuntu 20.04)
ssl_dh = </etc/dovecot/dh4096.pem
ssl_min_protocol = TLSv1.2
#ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
#ssl_prefer_server_ciphers = no
##
##Services
##
service auth {
unix_listener /var/spool/postfix/private/auth {
group = postfix
mode = 0660
user = postfix
}
}
service lmtp {
unix_listener lmtp {
#mode = 0666
}
unix_listener /var/spool/postfix/private/dovecot-lmtp {
#mode = 0666
user = postfix
group = postfix
}
}
service managesieve-login {
inet_listener sieve {
port = 4190
}
}
service quota-warning {
executable = script /usr/local/bin/quota-warning.sh
user = vmail
unix_listener quota-warning {
group = vmail
mode = 0660
user = vmail
}
}
service quota-status {
executable = quota-status -p postfix
inet_listener {
# address = 127.0.0.1
port = 12340
}
client_limit = 1
}
# Hinweis in main.cf: smtpd_recipient_restrictions = check_policy_service inet:127.0.0.1:12340, ..
service dict {
unix_listener dict {
mode = 0600
user = vmail
}
}
dict {
sqluserquota = mysql:/etc/dovecot/dovecot-dict-sql-user.conf
}
service imap {
executable = imap imap-postlogin
}
service imap-postlogin {
executable = script-login /usr/local/bin/postlogin.sh
user = vmail
unix_listener imap-postlogin {
}
}
##
## Protokolle
##
protocol pop3 {
pop3_uidl_format = %08Xu%08Xv
mail_max_userip_connections = 5
}
protocol imap {
mail_max_userip_connections = 8
mail_plugins = $mail_plugins imap_quota imap_sieve
}
protocol lmtp {
mail_plugins = $mail_plugins sieve
}
##
## Client Authentifizierung
##
passdb {
args = /etc/dovecot/dovecot-mysql.conf
driver = sql
}
userdb {
args = /etc/dovecot/dovecot-mysql.conf
driver = sql
}
## Hinweis: Datei 10-auth.conf editieren und !include auth-system.conf.ext deaktivieren
##
## Postfächer
##
namespace inbox {
inbox = yes
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Junk {
auto = subscribe
autoexpunge = 26w
special_use = \Junk
}
mailbox "Junk-E-Mail" {
special_use = \Junk
autoexpunge = 26w
}
mailbox "Spam" {
special_use = \Junk
autoexpunge = 26w
}
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox "Sent Messages" {
special_use = \Sent
}
mailbox Trash {
auto = subscribe
autoexpunge = 26w
special_use = \Trash
}
mailbox "Gelöschte Elemente" {
autoexpunge = 26w
special_use = \Trash
}
mailbox "Papierkorb" {
autoexpunge = 26w
special_use = \Trash
}
}
##
##Plugins
##
plugin {
sieve = ~/.dovecot.sieve
sieve_dir = ~/sieve
sieve_plugins = sieve_imapsieve sieve_extprograms
sieve_before = /var/vmail/sieve/global/spam-global.sieve
#quota_rule = *:storage=1G
#quota_rule2 = Trash:storage=+100M
quota_grace = 10%%
quota_warning = storage=66%% quota-warning 66 %u
quota_warning2 = storage=80%% quota-warning 80 %u
quota_warning3 = storage=95%% quota-warning 95 %u
# quota = dict:User Quota::noenforcing:proxy::sqluserquota
quota = dict:User Quota::proxy::sqluserquota
quota_status_success = DUNNO
quota_status_nouser = DUNNO
quota_status_overquota = "552 5.2.2 Mailbox is over quota / Mailbox ist voll"
##Spam lernen
# From elsewhere to Junk folder
imapsieve_mailbox1_name = Junk
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_before = file:/var/vmail/sieve/global/learn-spam.sieve
# From Junk folder to elsewhere
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = Junk
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/var/vmail/sieve/global/learn-ham.sieve
sieve_pipe_bin_dir = /usr/bin
sieve_global_extensions = +vnd.dovecot.pipe
}
Mit der auskommentierten Zeile
# quota = dict:User Quota::noenforcing:proxy::sqluserquota
würde bei einem Postfach, das die Quotas überschritten hat, noch Mail angenommen werden (nonenforcing). Die aktive Zeile bewirkt, dass die Mail dann abgelehnt wird. Dann sollte man aber auch, wie angegeben, die main.cf von Postfix so erweitern, dass er von Dovecot über die Überfüllung des Postfaches informiert werden kann und dann die Annahme weiter Mails selber ablehnt.
Der Teil mit dem Lernen von SPAM und HAM hat mir etwas Probleme bereitet, mit fehlte anfangs das imap_sieve mail_plungin. Leider gibt es keine Fehlermeldungen in den Logdateien. Hilfreich war für mich https://doc.dovecot.org/configuration_manual/howto/antispam_with_sieve/. Wenn es funktioniert kann man das an einem erfolgreichen Aufruf von rspamc mittels
grep "pipe action" /var/log/mail.log
erkennen.
Zusätzlich habe ich die Authentisierung per pam deaktiviert, indem ich im Unterordner conf.d die Datei 10-auth.conf editiert und dort am Ende der Datei die einzig aktive Include-Zeile
!include auth-system.conf.ext
/etc/dovecot/dovecot-mysql.conf
Die in der Konfiguration erwähnte /etc/dovecot/dovecot-mysql.conf
# Database driver: mysql, pgsql
driver = mysql
# Currently supported schemes include PLAIN, PLAIN-MD5, DIGEST-MD5, and CRYPT.
default_pass_scheme = CRYPT
# Database options
#db_unix_socket = /var/lib/mysql/mysql.sock
connect = host=/var/run/mysqld/mysqld.sock dbname=postfix user=postfix password=assword
password_query = SELECT password FROM mailbox WHERE username = '%u' AND active = '1'
user_query = SELECT \
concat('/var/vmail/',maildir,'home/') as home, \
concat('maildir:/var/vmail/',maildir) as mail, \
303 AS uid, \
303 AS gid, \
CONCAT('*:bytes=', IF(mailbox.quota = 0, domain.maxquota*1024000, mailbox.quota)) as quota_rule \
FROM mailbox, domain WHERE username = '%u' AND mailbox.active = '1' AND domain.domain = '%d' AND domain.active = '1'
iterate_query = SELECT username as user FROM mailbox WHERE active ='1' ORDER BY domain, username
/usr/local/bin/quota-warning.sh
In der Konfiguration taucht das Plugins quota_warning auf. Dazu gehört das folgende Script:
#!/bin/sh
PERCENT=$1
USER=$2
ADMIN="uwe@maine-maildomain.de"
FROM="postmaster@maine-maildomain.de"
msg="From: $FROM
To: $USER
Bcc: $ADMIN
Subject: Quota-Warnung $PERCENT%
Lieber Nutzer,
das Postfach $USER ist derzeit zu
$PERCENT% gefuellt.
Bitte einige Mails loeschen und dann
den Papierkorb leeren!
Herzlichen Dank
Das Mail-System."
echo "$msg" | /usr/sbin/sendmail -f $FROM "$USER $ADMIN"
exit 0
Die Auslastung der Quotas kann man sich im PostfixAdmin anschauen oder an der Konsole mittels
doveadm quota get -A
oder statt für alle auch für einen einzelnen Nutzer
doveadm quota get -u user@meine-maildomain.de
Man kann auch die Belegung neu berechnen lassen mittels
doveadm quota recalc -A
oder statt für alle auch für einen einzelnen Nutzer
doveadm quota recalc -u user@meine-maildomain.de
/usr/local/bin/postlogin.sh
Das folgende Script dient dazu, die Verzeichnisse home der einzelnen Mailbenutzer anzulegen. Da das mit dem welcome Plugin nicht funktioniert hat, bin ich auf das Postlogin von Dovecot ausgewichen. Dazu gehört dieses Script:
#!/bin/sh
local=${USER%%@*}
domain=${USER##*@}
if [ ! -d "/var/vmail/$domain/$local/home" ]; then
mkdir /var/vmail/$domain/$local/home
fi
exec "$@"
Vor dem Dovecot-Neustart dann noch die Diffie-Hellman Parameter für Dovecot generieren
openssl dhparam -out /etc/dovecot/dh4096.pem 4096
das dauert leider etwas.
/etc/dovecot/dovecot-dict-sql-user.conf
Diese Datei dient Dovecot dazu die jeweils aktuellen Quota-Werte an der richtigen Stelle in der MySQL-Datenbank zu speichern. Die erste Map für die Anzahl der Bytes, die zweite Map für die Anzahl der Nachrichten siehe https://wiki.dovecot.org/Quota/Dict .
connect = host=/var/run/mysqld/mysqld.sock dbname=postfix user=postfix password=assword
map {
pattern = priv/quota/storage
table = quota2
username_field = username
value_field = bytes
}
map {
pattern = priv/quota/messages
table = quota2
username_field = username
value_field = messages
}
Postfix
apt install postfix postfix-mysql postfix-policyd-spf-python alpine service postfix stop
Für die Konfiguration ist es manchmal wichtig zu wissen, welche Versionsnummer das eigene Postfix-Programm hat. Diese Information liefert:
postconf -d mail_version
Die zentrale Konfigurationsdatei ist die master.cf. Hier werden die benötigten Dienste (z.B. smtp, uucp, ...) gestartet und zum Teil auch konfiguriert. Die eigentliche Konfiguration für den smtp Dienst befindet sich dann in der Datei main.cf. Weitere Dienste mit dem gleichen Programm, wie z.B. smtps oder submission übernehmen die dort gemachten Einstellungen, es sei den die Einstellung wird in einer Zeile, die mit " -o" beginnt überschrieben. Etwas ungewöhnlich ist eine Zeile wie -o smtpd_client_restrictions=$mua_client_restrictions, die so nicht fehlerfrei aktivierbar ist. Der rechte Teil ist nämlich quasi eine Variable, die in der main.cf mit Inhalt gefüllt werden muss.
/etc/postfix/master.cf
#
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: "man 5 master" or
# on-line: http://www.postfix.org/master.5.html).
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (no) (never) (100)
# ==========================================================================
smtp inet n - y - - smtpd
#smtp inet n - y - 1 postscreen
#smtpd pass - - y - - smtpd
#dnsblog unix - - y - 0 dnsblog
#tlsproxy unix - - y - 0 tlsproxy
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
# -o smtpd_tls_auth_only=yes
# -o smtpd_reject_unlisted_recipient=no
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
# -o smtpd_helo_restrictions=$mua_helo_restrictions
-o smtpd_sender_restrictions=reject_non_fqdn_sender,permit_sasl_authenticated,reject
# -o smtpd_recipient_restrictions=
-o smtpd_relay_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
# -o smtpd_reject_unlisted_recipient=no
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
# -o smtpd_helo_restrictions=$mua_helo_restrictions
-o smtpd_sender_restrictions=reject_non_fqdn_sender,permit_sasl_authenticated,reject
# -o smtpd_recipient_restrictions=
-o smtpd_relay_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
#628 inet n - y - - qmqpd
pickup unix n - y 60 1 pickup
cleanup unix n - y - 0 cleanup
qmgr unix n - n 300 1 qmgr
#qmgr unix n - n 300 1 oqmgr
tlsmgr unix - - y 1000? 1 tlsmgr
rewrite unix - - y - - trivial-rewrite
bounce unix - - y - 0 bounce
defer unix - - y - 0 bounce
trace unix - - y - 0 bounce
verify unix - - y - 1 verify
flush unix n - y 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - y - - smtp
relay unix - - y - - smtp
-o syslog_name=postfix/$service_name
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq unix n - y - - showq
error unix - - y - - error
retry unix - - y - - error
discard unix - - y - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - y - - lmtp
anvil unix - - y - 1 anvil
scache unix - - y - 1 scache
postlog unix-dgram n - n - 1 postlogd
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent. See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
maildrop unix - n n - - pipe
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# ====================================================================
#
# Recent Cyrus versions can use the existing "lmtp" master.cf entry.
#
# Specify in cyrus.conf:
# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
#
# Specify in main.cf one or more of the following:
# mailbox_transport = lmtp:inet:localhost
# virtual_transport = lmtp:inet:localhost
#
# ====================================================================
#
# Cyrus 2.1.5 (Amos Gouaux)
# Also specify in main.cf: cyrus_destination_recipient_limit=1
#
#cyrus unix - n n - - pipe
# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
#
# ====================================================================
# Old example of delivery via Cyrus.
#
#old-cyrus unix - n n - - pipe
# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
#
# ====================================================================
#
# See the Postfix UUCP_README file for configuration details.
#
#uucp unix - n n - - pipe
# flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#
ifmail unix - n n - - pipe
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp unix - n n - - pipe
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix - n n - 2 pipe
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
#mailman unix - n n - - pipe
# flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
# ${nexthop} ${user}
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
# Added using postfix-add-policy script:
policy-spf unix - n n - 0 spawn
user=nobody argv=/usr/bin/policyd-spf
/etc/postfix/main.cf
(die einzelnen Parameter sind in http://www.postfix.org/postconf.5.html dokumentiert)
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
##
##Netzwerk und Namen
##
myorigin = /etc/mailname
append_dot_mydomain = no
masquerade_domains = meine-maildomain.de
myhostname = mail.meine-maildomain.de
mydestination = $myhostname, meine-maildomain.de, localhost, hetzner.meine-maildomain.de
#mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
inet_interfaces = all
inet_protocols = ipv4
##
# Einstellungen
##
compatibility_level = 2
smtputf8_enable = no
biff = no
delay_warning_time = 4h
readme_directory = no
unknown_address_reject_code = 552
unknown_client_reject_code = 551
unknown_hostname_reject_code = 550
#maps_rbl_reject_code = 451
message_strip_characters = \0
defer_transports =
mailbox_command =
mailbox_transport =
relayhost =
mailbox_size_limit = 0
recipient_delimiter = +
##
# TLS parameters
##
## ausgehende Verbindungen
smtp_tls_security_level=may
smtp_tls_mandatory_protocols=!SSLv2, !SSLv3
#smtp_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
#smtp_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtp_tls_key_file = /etc/letsencrypt/live/meine-maildomain.de/privkey.pem
smtp_tls_cert_file = /etc/letsencrypt/live/meine-maildomain.de/fullchain.pem
smtp_tls_loglevel = 1
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_note_starttls_offer = yes
## eingehende Verbindungen
smtpd_tls_security_level=may
smtpd_tls_mandatory_protocols=!SSLv2, !SSLv3
#smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
#smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_key_file=/etc/letsencrypt/live/meine-maildomain.de/privkey.pem
smtpd_tls_cert_file=/etc/letsencrypt/live/meine-maildomain.de/fullchain.pem
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
smtpd_tls_dh1024_param_file = /etc/postfix/dh2048.pem
smtpd_delay_reject = yes
smtpd_helo_required = yes
## SASL für eingehende Verbindungen
broken_sasl_auth_clients = yes
smtpd_sasl_local_domain =
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous
smtpd_sasl_type = dovecot
# das kann/sollte hier auf no gesetzt werden, wenn smtps/submission aktiviert sind
smtpd_sasl_auth_enable = yes
smtp_sasl_auth_enable = no
smtp_sasl_security_options =
smtp_sasl_password_maps =
##
# Maps und Tabellen
##
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
relay_domains = $mydestination, hash:/etc/postfix/relay
#virtual_alias_domains = hash:/etc/postfix/virtual
virtual_mailbox_base = /var/vmail/
virtual_alias_maps =
proxy:mysql:/etc/postfix/mysql_virtual_alias_maps.cf
proxy:mysql:/etc/postfix/mysql_virtual_alias_domain_maps.cf
proxy:mysql:/etc/postfix/mysql_virtual_alias_domain_catchall_maps.cf
virtual_mailbox_domains =
proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_maps =
proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
proxy:mysql:/etc/postfix/mysql_virtual_alias_domain_mailbox_maps.cf
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_limit = 0
virtual_minimum_uid = 303
virtual_uid_maps = static:303
virtual_gid_maps = static:303
##
# Restrictions
##
smtpd_client_restrictions =
permit_sasl_authenticated
permit_mynetworks
reject_rbl_client cbl.abuseat.org
reject_rbl_client ix.dnsbl.manitu.net
reject_rbl_client bl.spamcop.net
reject_rbl_client dul.dnsbl.sorbs.net
reject_unknown_client
smtpd_helo_restrictions =
permit_mynetworks
reject_invalid_helo_hostname
smtpd_sender_restrictions =
hash:/etc/postfix/access
reject_unknown_sender_domain
smtpd_recipient_restrictions =
check_policy_service inet:127.0.0.1:12340
permit_sasl_authenticated
permit_mynetworks
reject_unauth_destination
smtpd_relay_restrictions =
permit_mynetworks
permit_sasl_authenticated
reject_unauth_destination
# Block clients that speak too early.
smtpd_data_restrictions = reject_unauth_pipelining
# Neu 3.1.2023 wegen https://www.postfix.org/smtp-smuggling.html
smtpd_discard_ehlo_keywords = chunking, silent-discard
##
# Spamfilter und DKIM-Signaturen via Rspamd
##
#content_filter = smtp-amavis:[localhost]:10024
smtpd_milters = inet:localhost:11332
non_smtpd_milters = inet:localhost:11332
milter_protocol = 6
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
milter_default_action = accept
##
# Limits
##
mailbox_size_limit = 0
message_size_limit = 0
strict_8bitmime = no
strict_rfc821_envelopes = yes
smtpd_client_message_rate_limit = 50
smtpd_client_connection_rate_limit = 10
smtpd_client_recipient_rate_limit = 50
smtpd_client_connection_count_limit = 25
bounce_queue_lifetime = 3d
maximal_queue_lifetime = 3d
smtpd_recipient_limit = 50
Auch für Postfix Diffie-Hellman-Parameter generieren
Die DH-Parameter für Postfix sind hier nur 2048 Bit stark, um zu älteren Mailservern kompatibel zu bleiben.
openssl dhparam -out /etc/postfix/dh2048.pem 2048
Postfix und MySQL
Damit Postfix MySQL-Tabellen nutzen kann muss man folgende Dateien einrichten:
/etc/postfix/mysql_virtual_alias_maps.cf /etc/postfix/mysql_virtual_domains_maps.cf/etc/postfix/mysql_virtual_mailbox_limit_maps.cfdarum kümmert sich Dovecot /etc/postfix/mysql_virtual_mailbox_maps.cf /etc/postfix/mysql_virtual_alias_domain_maps.cf /etc/postfix/mysql_virtual_alias_domain_catchall_maps.cf /etc/postfix/mysql_virtual_alias_domain_mailbox_maps.cf
Diese mysql-Dateien im Verzeichnis /etc/postfix muss man anpassen an die eigenen Datenbankeinstellungen. Muster dazu finden sich in der Datei /usr/share/doc/postfixadmin/DOCUMENTS/POSTFIX_CONF.txt.gz. Im Prinzip wird Postfix hier mitgeteilt, wie die Datenbanktabellen abgefragt werden. Benutzername und Passwort müssen hier an die eigenen Einstellungen angepasst werden.
mysql_virtual_alias_maps.cf
user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
mysql_virtual_domains_maps.cf
user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
mysql_virtual_mailbox_limit_maps.cf
user = postfix password = password hosts = localhost dbname = postfix query = SELECT quota FROM mailbox WHERE username='%s' AND active = '1'
mysql_virtual_mailbox_maps.cf
user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
mysql_virtual_alias_domain_maps.cf
user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
mysql_virtual_alias_domain_catchall_maps.cf
# handles catch-all settings of target-domain
user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
mysql_virtual_alias_domain_mailbox_maps.cf
user = postfix
password = password
hosts = localhost
dbname = postfix
query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1'
Firewall anpassen
ufw allow Postfix
ufw allow "Postfix SMTPS"
ufw allow "Postfix Submission"
ufw allow "Dovecot IMAP"
ufw allow "Dovecot Secure IMAP"
ufw allow "Dovecot POP3"
ufw allow "Dovecot Secure POP3"
Vor dem Neustart der Dienste müssen die Datenbanken erzeugt werden:
postmap /etc/postfix/access newaliases
Konfiguration der Clients
Thunderbird als Client-Programm lässt sich problemlos so konfigurieren, dass er mit den beiden verschlüsselten Protokollen arbeiten kann. Beispieleinstellungen ergeben sich aus dem folgenden Bildern.
Zum Einrichten es neuen Postfaches muss man im Idealfall nur die Mailadresse und das Passwort angeben
Thunderbird versucht dann sich vom Mailserver die passenden Einstellungen zu holen:
Voreingestellt ist hier ein Postausgang über Port 25.
Port 25 ist eigentlich für unverschlüsselte Verbindungen zuständig, über STARTTLS handeln die beteiligten Systeme aber eine Verschlüsselung aus, so dass auch hier verschlüsselt übertragen wird. Es gibt aber auch zwei weitere Ports, über die in der Regel nur verschlüsselte Verbindungen angenommen werden.
Wen man die freie Wahl hat, dann sollte man hier SMTPS über Port 465 auswählen.
Postfix und der Kampf gegen Spam
Heutzutage ist deutlich mehr als 90% aller verschickten Mails unerwünschter Spam. Die zentrale Stelle im Kampf gegen den Spam ist natürlich der Mailserver. Postfix hat eine Reihe von Mechanismen eingebaut, die versuchen Spam zu vermeiden:
- RBL, ein System bei dem bestimmte Server gefragt werden, ob ihnen der abliefernde Server als Spamlieferant bekannt ist
- Regeln wie invalid_hostname, hier überprüft Postfix, ob sich der Name, der zu der abliefernden IP-Adresse gehört zur gleichen IP wieder auflösen lässt
- Access-Listen über die z.B. Mailadressen oder ganze Domains blockiert werden können
Wirklich Viren und Spam erkennen kann Postfix aber nicht. Dazu bedarf es eines externen Hilfsprogrammes, wie AmaVis oder rspamd. Diese Programme können allgemein nach zwei unterschiedlichen Konzepten eingebunden werden.
- als Mail-Proxy
- Über die Milter-Schnittstelle
AmaVis wird in der Regel als Proxy eingebunden. Dabei nimmt Postfix auf dem normalen Port z.B. 25 eine Mail an und gibt sie zur Untersuchung an AmaVis weiter. Wenn AmaVis mit der Mail fertig ist, dann gibt er die an einen zweiten Postfix-Prozess weiter, der z.B. auf Port 10025 lauscht. Dieses Verfahren kann man gut in den Header-Zeilen der Mail nachvollziehen, hier taucht der eigene Server nämlich doppelt auf. Nachteil bei dem Proxy-System ist, dass AmaVis die Mail erst sehen kann, wenn sie angenommen wurde. Auch, wenn sie als Spam klassifiziert wurde muss sie zugestellt werden. Konfiguriert wird der zweite Postfix-Daemon über die letzten Zeilen in der /etc/postfix/master.cf
127.0.0.1:10025 inet n - - - - smtpd
-o content_filter=
-o smtpd_delay_reject=no
...
und der Zugriff auf AmaVis erolgt über eine Zeile in der main.cf
content_filter = smtp-amavis:[localhost]:10024
Über die Milter-Schnittstelle kann sich ein externes Programm wie rspamd in den Postfix-Prozess einklinken. Es wird also kein zweiter Postfix-Prozess benötigt. Außerdem ist das externe Programm so in der Lage eine Mail als Spam zu klassifizieren, ohne das sie letztendlich angenommen wurde. Postfix kann dann den Prozess abbrechen und dem sendenden Mailserver dabei eine entsprechende Fehlermeldung zukommen lassen. Damit sollten als Spam gekennzeichnete Mail überhaupt nicht mehr beim Empfänger auftauchen.
Für Amavis gibt es auch ein Milter-Programm, das ist aber schon einige Zeit nicht mehr aktualisiert worden, vor allem in den Ubuntu-Versionen nicht.
/var/vmail/sieve/global/spam-global.sieve
require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
fileinto "Junk";
}
if header :is "X-Spam" "Yes" {
fileinto "Junk";
}
/var/vmail/sieve/global/learn-ham.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
if environment :matches "imap.mailbox" "*" {
set "mailbox" "${1}";
}
if string "${mailbox}" "Trash" {
stop;
}
pipe :copy "rspamc" ["learn_ham"];
/var/vmail/sieve/global/learn-spam.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve"];
pipe :copy "rspamc" ["learn_spam"];
rspamd
Die Entwickler des rspamd möchten nicht, dass man die Pakete aus den jeweiligen Distributionen benutzt. Damit wollen sie einerseits erreichen, dass immer die aktuellste Version installiert ist und die Ubuntu-Paketentwickler nicht an der Konfiguration gedreht haben. Daher soll man das Programm immer von der Entwickler-Seite laden, dafür gibt es auch für Ubuntu die passenden Pakete.
apt install wget
wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add -
echo "deb [arch=amd64] http://rspamd.com/apt-stable/ $(lsb_release -c -s) main" > /etc/apt/sources.list.d/rspamd.list
echo "deb-src [arch=amd64] http://rspamd.com/apt-stable/ $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/rspamd.list
apt update
apt install rspamd clamav clamav-daemon redis-server
service rspamd stop
Bei anderen Prozessor-Architekturen als amd64 muss man den Ausdruck [arch=amd64] weglassen oder passend ersetzen.
Beim apt update kam am Ende immer eine Fehlermeldung
http://rspamd.com/apt-stable/dists/noble/InRelease: Schlüssel ist im veralteten Schlüsselbund trusted.gpg gespeichert (/etc/apt/trusted.gpg), siehe den Abschnitt MISSBILLIGUNG in apt-key(8) für Details.
Ursache dafür ist, das Ubuntu die Keys jetzt in individuellen Dateien im Verzeichnis /etc/apt/trusted.gpg.d/ speichert. Unter https://askubuntu.com/questions/1407632/key-is-stored-in-legacy-trusted-gpg-keyring-etc-apt-trusted-gpg habe ich Erklärung und Lösung gefunden:
for KEY in $(apt-key --keyring /etc/apt/trusted.gpg list | grep -E "(([ ]{1,2}(([0-9A-F]{4}))){10})" | tr -d " " | grep -E "([0-9A-F]){8}\b" ); do K=${KEY:(-8)}; apt-key export $K | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/imported-from-trusted-gpg-$K.gpg; done
Für die Anpassung der Konfiguration haben die Entwickler sich ein interessantes System ausgedacht, wie man am Inhalt der Datei /etc/rspamd/rspamd.conf erkennen kann
# For specific modules or configuration you can also modify
# '$LOCAL_CONFDIR/local.d/file.conf' - to add your options or rewrite defaults
# '$LOCAL_CONFDIR/override.d/file.conf' - to override the defaults
Für jeden der vorhandenen Konfigurationsbereiche gibt es jeweils eine vorbereitete Konfigurationsdatei im Hauptverzeichnis der Konfiguration. Änderungsdateien legt man unter dem gleichen Namen entweder ins Unterverzeichnis:
- local.d oder
- override.d
Einstellungen die im Unterverzeichnis local.d gemacht werden ergänzen die vorhandenen Einstellungen, bei gleichem Bezeichner überschreiben sie auch. Einstellungen im Verzeichnis override.d löschen erst einmal alle Voreinstellungen, nur die neu gemachte Einstellung bleibt gültig.
Die Konfiguration des rspamd erfolgt erst einmal in relativ wenigen Schritten:
cd /etc/rspamd/
dann lässt man sich einen Passwort-Hash erzeugen
rspamadm pw
das Passwort wird im Dialog abgefragt, der Hash, z.B. $2$piqhd3fcs6ncafzfw7qhjehjjwdmaoeo$nkdo6u8ot7ydibt6eipn7m97opzhcb3mcqpq9n64un7bec3mzhzy erscheint dann auf dem Bildschirm und muss in die Datei /etc/rspamd/local.d/worker-controller.inc übertragen werden.
/etc/rspamd/local.d/worker-controller.inc
password = "$2$piqhd3fcs6ncafzfw7qhjehjjwdmaoeo$nkdo6u8ot7ydibt6eipn7m97opzhcb3mcqpq9n64un7bec3mzhzy"; enable_password = "$2$piqhd3fcs6ncafzfw7qhjehjjwdmaoeo$nkdo6u8ot7ydibt6eipn7m97opzhcb3mcqpq9n64un7bec3mzhzy";
Im Proxy-Modus scannt rspamd_proxy die Nachrichten selbst und spricht direkt mit dem MTA unter Verwendung des Milter-Protokolls. Der Vorteil dieses Ansatzes ist seine Einfachheit.
/etc/rspamd/local.d/worker-proxy.inc
bind_socket = "localhost:11332";
milter = yes;
timeout = 120s;
upstream "local" {
default = yes;
self_scan = yes;
}
In der Regel wird man die Logmeldungen nicht in einer extra-Datei haben wollen, sondern im Syslog, dazu wieder eine kleine Erweiterung:
/etc/rspamd/local.d/local.d/logging.inc
type = "syslog"; level = "warning";
Die Header-Zeilen konfiguriert man
/etc/rspamd/local.d/milter_headers.conf
use = ["x-spamd-bar", "x-spam-level", "authentication-results"]; authenticated_headers = ["authentication-results"];
Das kleine Datenbank-Tool redis soll für Bayes-Filter genutzt werden und Auto-Learning soll aktiv sein:
/etc/rspamd/local.d/classifier-bayes.conf
backend = "redis"; autolearn = true;
Wo findet redis seine Partner
/etc/rspamd/local.d/redis.conf
servers = "127.0.0.1";
Clamav aktivieren, er muss natürlich installiert sein und auf der angegebenen Socket /var/run/clamav/clamd.ctl lauschen
/etc/rspamd/local.d/antivirus.conf
clamav {
action = "reject";
scan_mime_parts = true;
log_clean = true;
symbol = "CLAM_VIRUS";
type = "clamav";
servers = "/var/run/clamav/clamd.ctl";
}
Mail-Subject ändern (Vorsicht, das hat Seiteneffekte und erfordert eine längere Beschreibung).
/etc/rspamd/local.d/actions.conf
subject = "***SPAM*** %s"; rewrite_subject = 6;
Individuelle Black- und White-Listen
/etc/rspamd/local.d/multimap.conf
WHITELIST_IP {
type = "ip";
map = "/var/lib/rspamd/whitelist_ip.map";
description = "Lokale ip whitelist -> accept";
action = "accept";
}
WHITELIST_FROM {
type = "from";
map = "/var/lib/rspamd/whitelist_from.map";
description = "Lokale from Whitelist -> accept";
action = "accept";
}
WHITELIST_FROM_DOMAIN {
type = "from";
filter = "email:domain";
map = "/var/lib/rspamd/whitelist_from_domain.map";
description = "Lokale from Domain Whitelist -> -6.0";
score = -6.0
}
BLACKLIST_IP {
type = "ip";
map = "/var/lib/rspamd/blacklist_ip.map";
description = "Lokale ip Blacklist -> reject";
action = "reject";
}
BLACKLIST_FROM {
type = "from";
map = "/var/lib/rspamd/blacklist_from.map";
description = "Lokale from Blacklist -> reject";
action = "reject";
}
BLACKLIST_IP_SCORE {
type = "ip";
map = "/var/lib/rspamd/blacklist_ip_score.map";
description = "Lokale Blacklist ip -> +6.0";
score = 6.0;
}
BLACKLIST_FROM_DOMAIN {
type = "from";
filter = "email:domain";
map = "/var/lib/rspamd/blacklist_from_domain.map";
description = "Lokale Blacklist from Domain -> +6.1";
score = 6.1;
}
BLACKLIST_FROM_DOMAIN_REG {
type = "from";
filter = "email:domain";
map = "/var/lib/rspamd/blacklist_from_domain_reg.map";
description = "Lokale Blacklist from Domain Regexp -> +6.2";
score = 6.2;
regexp = true;
}
BLACKLIST_DOMAIN_REJECT_REG {
type = "from";
filter = "email:domain";
map = "/var/lib/rspamd/blacklist_domain_reject_reg.map";
description = "Lokale Blacklist Domain Regexp -> reject";
action = "reject";
regexp = true;
}
BLACKLIST_HOSTNAMES_REG {
type = "hostname";
map = "/var/lib/rspamd/blacklist_hostname_reg.map";
regexp = true;
description = "Lokale Blacklist hostname Regexp -> +6.3";
score = 6.3;
}
BLACKLIST_HEADER_FROM {
type = "header";
header = "from";
map = "/var/lib/rspamd/blacklist_header_from.map";
filter = "email:addr";
description = "Lokale Blacklist nach FROM header -> reject";
action = "reject";
}
BLACKLIST_SPAMMY_SUBJECT {
type = "header";
header = "subject";
map = "/var/lib/rspamd/blacklist_subject_spam.map";
description = "Lokale Blacklist nach SUBJECT header -> reject";
action = "reject";
regexp = true;
}
BLACKLIST_SPAMMY_BODY {
type = "content";
filter = "oneline";
map = "/var/lib/rspamd/blacklist_body_spam.map";
description = "Lokale Blacklist nach Body -> +5.9";
score = 5.9;
regexp = true;
}
Diese Listen muss man nicht anlegen, das passiert automatisch, wenn man z.B. in der GUI einen Eintrag vornimmt. Statt der action-Zeilen kann man auch score-Zeilen nutzen, um die Entscheidung abzuschwächen:
score=-6 (für die Whitelisten score=6 (für die Blacklisten)
Ich habe hier meist leicht unterschiedliche Scores (5.9, 6.1, ...) benutzt, damit lässt sich die richtige Liste schneller in der Übersicht erkennen.
Hinweis: Man darf auf keinen Fall +6 schreiben, dann wird dies vom rspamd als String interpretiert und nicht als Zahl. Hat man eine Liste mit regexp=true, so muss die Map mit einem Zeilenumbruch enden, sonst wird die letzte Zeile nicht berücksichtigt.
Ein paar Erläuterungen zu den Beispielen: Breaking this example down:
- BLACKLIST_SPAMMY_BODY - ist der Name des Symbols, der ist ziemlich frei zu wählen und taucht in den Logs und Berichten auf
- type = "content"; bedeutet, wir vergleichen mit dem email Inhalt
- filter = "body"; bedeutet, schaue nur in den rohen undecodierten Body der Email (z.B. Ignoriere Headerzeilen)
- map - ist der Pfad zuz Datei, in der die einzlnen Vergleichstexte stehen
- description - eine Beschreibung, die im Webinterface auftaucht
- score - ist der Wert, der zum Spamwert addiert wird
- regexp = true; bedeutet, dass diese map Reguläre Ausdrücke enthält
- action = "reject"; alternativ zum Score, die Aktion, die auszuführen ist. "reject" stoppt die Message, andere Optionen sind accept, add header, rewrite subject und greylist
- prefilter = true; hiermit wird bei einem Treffer die weitere Untersuchung abgebrochen, macht z.B. im Zusammenhang mit action="reject" Sinn
Weitere Möglichkeiten und Beispiele finden sich unter https://rspamd.com/doc/modules/multimap.html
Die Map-Dateien
Normalerweise stehen in einer Map-Datei Zeilenweise unterschiedliche Vergleichstexte, die dann entsprechend der Regel verglichen werden. Etwas anders sieht das aus, wenn reguläre Ausdrücke im Spiel sind. Dazu ein paar kleine Besispiele:
/var/lib/rspamd/blacklist_body_spam.map
/eine dringende Nachricht/i
taucht im Body einer Nachricht irgendwo dieser Text (zwischen den schrägen Strichen) auf, dann trifft die Regel. Das i am Ende bewirkt, dass Gros-/Klein-Schreibung keine Rolle spielt.
/var/lib/rspamd/blacklist_from_domain_reg.map
/^.*\.lol$/
hier wird eine Mail geblockt, wenn die Toplevel-Domain .lol ist. In dieser Regel sagt "^.*" am Anfang beliebig viele Zeichen, dann "\.lol" ein Punkt und danach lol.
HAM/Spam lernen
Der rspamd lernt aus den eingehenden Mail. Man kann ihn aber auch vorab mit den vorhandenen Mails trainieren. Dazu bin ich in mein Postfachverzeichnis /var/vmail/<domain>/<user> gegangen und habe folgendes Kommandos abgesetzt:
find cur/* -type f -exec /usr/bin/rspamc learn_ham {} \;
find .Junk/cur/* -type f -exec /usr/bin/rspamc learn_spam {} \;
Falls sehr viele Mails vorhanden sind kann man die Suche einschränken, indem man vor dem Stern noch passende Ziffern anhand der Liste mit angibt. Also z.B.
find cur/16* -type f
DKIM-Signierung
Rspamd kann das Signieren der ausgehenden Mail übernehmen. Dazu muss zunächst ein entsprechender Schlüssel erzeugt und hinterlegt werden.
Hinweis: Meist wird empfohlen eine Schlüssellänge 2048 zu nutzen (-b 2048), der dann aber längere Schlüssel lässt sich bei manchen Nameservern aber nicht speichern.
mkdir /var/lib/rspamd/dkim/ rspamadm dkim_keygen -b 1024 -s 2020 -k /var/lib/rspamd/dkim/2020.key > /var/lib/rspamd/dkim/2020.txt chown -R _rspamd:_rspamd /var/lib/rspamd/dkim chmod 440 /var/lib/rspamd/dkim/*
Den erzeugten Key kann man sich ansehen mittels:
cat /var/lib/rspamd/dkim/2020.txt
Die Zeichenkette 2020 ist der sogenannte Selektor. Damit lässt sich der passende Schlüssel im Zonenfile des Nameservers wiederfinden.
Mich hat ursprünglich irritiert, dass sich die erzeugten Schlüssel an Anfang und Ende kaum unterschieden, ich hatte befürchtet, dass immer der gleiche Schlüssel erzeugt wird. Dazwischen unterscheiden sich die Schlüssel aber auf alle Fälle, so ist der Vergleich bzw. die Zuordnung aber schwierig.
/etc/rspamd/local.d/dkim_signing.conf
path = "/var/lib/rspamd/dkim/$selector.key"; selector = "2020"; ### Erlaube DKIM signing auch für alias sender Adressen allow_username_mismatch = true;
Die gleiche Information wird auch vom ARC-Modul benötigt.
ln -s /etc/rspamd/local.d/dkim_signing.conf /etc/rspamd/local.d/arc.conf
Das Webinterface von rspamd
Der rspamd stellt ein Webinterface zur Verfügung, welches auf dem Port 11334 des Servers auf Verbindungen wartet. Man hat jetzt drei Möglichkeiten auf dieses Interface zuzugreifen:
- Man gibt Port 11334 in der Firewall frei und benötigt dann das Passwort, welches man bei der Konfiguration des rspamd gesetzt hat, zusätzlich muss man erreichen, dass der Worker auch auf der normalen IP-Adresse lauscht, dazu ergänzt man in der worker-controller.inc nach den Passwörtern noch
bind_socket = "*:11334";
- Ein ssh-Tunnel zum Server ssh -L 8080:localhost:11334 root@meine-maildomain.de -N macht das Webinterface unter Port 8080 des lokalen Rechners verfügbar
- Web-Proxy für den Apache, in einem virtuellen Server ergänzt man:
RewriteEngine On
ProxyRequests Off
<Location /rspamd>
Order allow,deny
Allow from all
</Location>
RewriteRule ^/rspamd$ /rspamd/ [R,L]
RewriteRule ^/rspamd/(.*) http://localhost:11334/$1 [P,L]
Das Proxy-Modul muss dazu installiert sein:
a2enmod proxy a2enmod proxy_http
Damit ist dann nach einem Neustart des Webservers der rspamd über das Verzeichnis /rspamd/ erreichbar.
Warnung: Mit dem Proxy-Modul sollte man sehr vorsichtig sein. Es gibt immer wieder Leute, die versuchen den Server als Forward-Proxy zu nutzen, um verschleiert auf andere Server zugreifen zu können.
Das kann man mit der Einstellung ProxyRequests Off verhindern. Wir brauchen hier einen Reverse-Proxy, der einen internen Dienst (rspamd) über das Webinterface zur Verfügung stellt. Das ist weniger problematisch.
Eine ausführliche Beschreibung habe ich gefunden unter: https://www.netnea.com/cms/apache-tutorial-9-reverse-proxy-einrichten/
Roundcube
Roundcube ist ein sehr beliebter und mächtiger Webmail-Client. Er lässt sich über eine Reihe von Plugins erweitern. Ich nutze gern die Plugins
- sieve, zu Pflegen der entsprechenden Regeln
- Password, zum Ändern des eigenen Passwortes in der Postfix-Datenbank.
Zuerst die Installation:
apt install roundcube roundcube-plugins roundcube-plugins-extra
Das Programm wird standardmäßig im Verzeichnis /var/lib/roundcube/ abgelegt (in Version 1.4.3). Hierbei werden einige Unterverzeichnisse und Dateien an andere Stellen verlinkt
- config -> /etc/roundcube
- program -> /usr/share/roundcube/program
- .htaccess -> /etc/roundcube/htaccess
- logs -> /var/log/roundcube
- robots.txt -> /usr/share/roundcube/robots.txt
Die Plugins finden sich im Verzeichnis /usr/share/roundcube/plugins/, wobei die Konfigurationsdateien, die auf /etc/roundcube/plugins/ verlinkt wurden, jeweils nahezu leer sind. Ein Muster findet sich dann jeweils unter /usr/share/roundcube/plugins/ in der Datei config.inc.php.dist
Also
cp /usr/share/roundcube/plugins/password/config.inc.php.dist /etc/roundcube/plugins/password/config.inc.php cp /usr/share/roundcube/plugins/managesieve/config.inc.php.dist /etc/roundcube/plugins/managesieve/config.inc.php
cp /usr/share/roundcube/plugins/zipdownload/config.inc.php.dist /etc/roundcube/plugins/zipdownload/config.inc.php cp /usr/share/roundcube/plugins/jqueryui/config.inc.php.dist /etc/roundcube/plugins/jqueryui/config.inc.php
Danach sind dann ein paar Dateien zu editieren.
/etc/roundcube/debian-db.php
<?php
##
## database access settings in php format
## automatically generated from /etc/dbconfig-common/roundcube.conf
## by /usr/sbin/dbconfig-generate-include
##
## by default this file is managed via ucf, so you shouldn't have to
## worry about manual changes being silently discarded. *however*,
## you'll probably also want to edit the configuration file mentioned
## above too.
##
$dbuser='roundcube';
$dbpass='assword';
$basepath='';
$dbname='roundcube';
$dbserver='localhost';
$dbport='';
$dbtype='mysql';
/etc/roundcube/plugins/password/config.inc.php ab Zeile 105
// SQL Driver options
// ------------------
// PEAR database DSN for performing the query. By default
// Roundcube DB settings are used.
// Supported replacement variables:
// %h - user's IMAP hostname
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %z - IMAP domain (IMAP hostname without the first part)
$config['password_db_dsn'] = 'mysql://postfix:geheim@localhost/postfix';
// The SQL query used to change the password.
// The query can contain the following macros that will be expanded as follows:
// %p is replaced with the plaintext new password
// %P is replaced with the crypted/hashed new password
// according to configured password_algorithm
// %o is replaced with the old (current) password
// %O is replaced with the crypted/hashed old (current) password
// according to configured password_algorithm
// %h is replaced with the imap host (from the session info)
// %u is replaced with the username (from the session info)
// %l is replaced with the local part of the username
// (in case the username is an email address)
// %d is replaced with the domain part of the username
// (in case the username is an email address)
// Escaping of macros is handled by this module.
// Default: "SELECT update_passwd(%P, %u)"
$config['password_query'] = 'UPDATE mailbox SET password=%c WHERE username=%u';
...
/etc/roundcube/plugins/managesieve/config.inc.php
<?php
// managesieve server port. When empty the port will be determined automatically
// using getservbyname() function, with 4190 as a fallback.
$config['managesieve_port'] = 4190;
/etc/roundcube/config.inc.php In der Hauptkonfigurationsdatei von Roundcube ist eine Änderung notwendig.
Ab Zeile 54
// List of active plugins (in plugins/ directory)
// Debian: install roundcube-plugins first to have any
$config['plugins'] = array(
'archive',
'zipdownload',
'managesieve',
'password',
);
Komischerweise musste ich den Port für SMTP auf 25 ändern (von 587)
Ab Zeile 20
$config = [];
// Do not set db_dsnw here, use dpkg-reconfigure roundcube-core to configure database!
include("/etc/roundcube/debian-db-roundcube.php");
// IMAP host chosen to perform the log-in.
// See defaults.inc.php for the option description.
$config['imap_host'] = ["localhost:143"];
// SMTP server host (for sending mails).
// See defaults.inc.php for the option description.
//$config['smtp_host'] = 'localhost:587';
$config['smtp_host'] = 'localhost:25';
Die Datenbankkonfiguration findet sich dann in der Datei /usr/share/roundcube/SQL/mysql.initial.sql
Damit für einen virtuellen Host der Zugriff auf Roundcube möglich ist, muss es in der Apache-Konfiguration für diesen Host folgende Zeile geben:
Alias /roundcube /var/lib/roundcube/public_html/ Alias /roundcubemail /var/lib/roundcube/public_html/
Im Idealfall nur in dem Teil der für https zuständig ist.
Testen
Nach Konfigurationsänderungen ist das Testen des Ergebnisses immer wichtig. Das betrifft einerseits die Viren und Spam Erkennung aber auch die ganzen Nameservereinträge.
Spam und Viren Testen kann man den Spamfilter mit GTUBE von Apache. Generic Test for Unsolicited Bulk Email (GTUBE) ist ein kurzer Mail-Text, der als Spam erkannt werden muss:
Herunterladen der Test-Datei:
wget http://spamassassin.apache.org/gtube/gtube.txt -P /tmp
und dann verschicken an einen User
sendmail uwe@meine-maildomain.de < /tmp/gtube.txt
Oder
https://www.heise.de/security/dienste/Emailcheck-2109.html
Die SSL-Parameter
openssl s_client -connect meine-maildomain.de:25 -starttls smtp openssl s_client -connect meine-maildomain.de:993
Nameserver-Einträge
SPF
dig -t txt meine-maildomain.de
bzw. mit übersichtlicherme Ergebnis
dig +short -t txt meine-maildomain.de
DKIM
dig -t txt 2020._domainkey.meine-maildomain.de
DMARC
dig -t txt _dmarc.meine-maildomain.de
Quotas
Das Testen der Quota-Einstellungen ist etwas mühsam. Die Warnungen werden z.B. immer dann erzeugt, wenn der Speicherplatz die angegebene Grenze übersteigt. Danach dann aber bis zur nächsten Grenze nicht mehr. Man muss also Mails löschen, um eine Grenze erneut auszutesten.
Bei Problemen kann man darauf achten, ob überhaupt Dovecot für die Mailzustellung genutzt wird:
Oct 18 11:21:19 mail dovecot: lmtp(name@meine-maildomain.de): msgid=<95fd0a2b46d4969a5ff2e514b.98ea0f958f.20201018090500.574acd086e.19474f00@mail111.beispiel.de>: saved mail to INBOX Oct 18 11:21:19 mail postfix/lmtp[13873]: 7EBFD24006C: to=<name@meine-maildomain.de>, relay=meine-maildomain.de[private/dovecot-lmtp], delay=1.3, delays=1.1/0/0.01/0.12, dsn=2.0.0, status=sent (250 2.0.0 <name@meine-maildomain.de> UBNYEg8JjF8yNgAA37fa2w Saved)
Falls Postfix selber zustellt, wie bei der Mail an root
Oct 18 10:30:03 mail postfix/local[13154]: 61D1B240091: to=<root@meine-maildomain.de>, orig_to=<root>, relay=local, delay=0.28, delays=0.2/0/0/0.08, dsn=2.0.0, status=sent (delivered to mailbox)
greifen die Dovecot Einstellungen natürlich nicht.
Falls es probleme gibt kann man auch gut in der local.conf von Dovecot
mail_debug = yes
setzen. Beim Überschreiten einer Grenze sollte sich dann in der Mail.log ein Eintrag finden wie
Oct 18 10:31:22 mail dovecot: lmtp(name@meine-maildomain.de)<587134><ZL7WNlj9i19+9QgAjuSTOg>: Debug: quota: Executing warning: quota-warning 66 name@meine-maildomain.de (because bytes=235928217 -> 314565267 over limit 270336000)
Was mir so auffiel
Was mich etwas überrascht hat, ist dass
tcpdump localhost
keine Dienste anzeigt, die an localhost bzw. 127.0.0.1 gebunden sind. Das betrifft in der Standardkonfiguration die Dienste auf den Ports 11222, 11333 und 11334 des rspamd. Dienste auf diesen Ports kann man aber mit
lsof -i TCP -n -P
ausgeben lassen.
Weiterleitungen mit Sieve anpassen
Bei Weiterleitungen und Mailinglisten gibt es manchmal das Problem, dass einige Empfangs-Server die weitergeleiteten Mails ablehnen, wenn der Absender ebenfalls aus ihrem Bereich kommt.
Nehmen wir einmal als Beispiel eine Schule, deren Lehrer Accounts auf dem System des Behörden-Dienstleisters haben, also z.B. klaus.test@schule-bundesland.de. Die Schule selber hat nun einen eigenen Account auf der Homepage, z.B. info@beispiel-schule.de. Dieser Account wird nun generell weitergeleitet auf beispiel-schule@schule-bundesland.de. Wenn nun jemad an info@beispiel-schule.de schreibt, dann geht die Mail problemlos an beispiel-schule@schule-bundesland.de und wird dort zugestellt. Aber leider nicht, wenn der Absender ein Behördenaccount ist, wie z.B. klaus.test@schule-bundesland.de, dann wird die Mail mit einer Fehlermeldung des Behördenservers abgelehnt, vor allem wenn SPF aktiviert ist.
Ein Versuch dieses Problem zu umgehen lässt sich mit sieve realisieren.
Dazu muss aber in der local.conf von Dovecot innerhalb von plugin eine Zeile ergänzt werden:
plugin {
...
sieve_extensions = +editheader
Damit steht dann auch editheader zur Verfügung.
# rule:[Info]
require ["fileinto", "editheader", "envelope", "regex", "variables"];
if true
{
if envelope :matches "From" "*@schule-bundesland.de" {
deleteheader "Reply-To";
addheader "Reply-To" "${1}@schule-bundesland.de";
deleteheader "DKIM-Signature";
deleteheader "DomainKey-Signature";
deleteheader "X-DKIM";
deleteheader "X-DomainKeys";
deleteheader "From";
deleteheader "To";
deleteheader "ARC-Seal";
deleteheader "ARC-Message-Signature";
deleteheader "ARC-Authentication-Results";
deleteheader "Authentication-Results";
addheader "From" "info@beispiel-schule.de";
addheader "To" "beispiel-schule@schule-bundesland.de";
}
redirect "beispiel-schule@schule-bundesland.de";
}
Der Mailserver von beispiel-bundesland.de sieht nun sich nicht mehr selber als Absender der Mail, sondern die (inoffizielle) Adresse der Schule.
Links zu Anleitungen
Dies ist eine Sammlung von Adressen zum Nachlesen und Vergleichen:
rspamd
- https://rspamd.com/ die Homepage des rspamd
- https://roll.urown.net/server/mail/rspamd.html
- https://wiki.rockstable.it/rspamd
- https://arnowelzel.de/spamfilter-und-dkim-mit-rspamd
Gesamtsystem mit rspamd
- https://123qwe.com/tutorial-debian-10/ sehr schöne Beschreibung
- https://www.scaleway.com/en/docs/setup-a-mailserver-on-ubuntu-bionic-beaver-with-dovecot-postfix-rspamd/ sehr schöne Anleitung für das, was ich auch machen möchte
- https://thomas-leister.de/mailserver-debian-buster/ seine Seiten sind immer lesenswert
- https://linuxize.com/post/install-and-integrate-rspamd/
Gesamtsystem ohne rspamd
- https://www.linuxbabe.com/mail-server/host-multiple-mail-domains-in-postfixadmin Hier gibt es mehrere Teile
- https://thomas-leister.de/mailserver-unter-ubuntu-16.04/ Schon etwas älter
SPF, DKIM und DMARC
- https://www.digicomp.ch/blog/2019/02/18/spf-dkim-und-dmarc-verstaendlich-erklaert SPF, DKIM und DMARC verständlich erklärt
- https://www.excontinuum.de/de/2016/06/23/dkim-und-spf-fuer-dovecot-mit-spamassassin/ DKIM, DMARC und SPF für Dovecot und Postfix mit SpamAssassin
- https://scaron.info/blog/debian-mail-spf-dkim.html Für Systeme mit Spamassassin
- https://dmarcian.com/spf-syntax-table/ ausführliche Anleitungen, zu spf, DKIM und DMARC
- https://www.zytrax.com/books/dns/ch9/dmarc.html ausfühliche Auflistung der DMARC Bestandteile
- https://www.df.eu/de/support/df-faq/e-mail/spf-sender-policy-framework/spf-eintraege/ DF bietet eine Anleitung zu spf
- https://support.google.com/a/answer/2466563 DMARC
Links zu Werkzeugen
- check-auth@verifier.port25.com schickt man eine Mail an diese Adresse, so bekommt man per Mail einen Authentication Report
- https://www.mail-tester.com/ auch hier kann man einen Report bekommen, dazu muss man an die auf der Startseite generierte Adresse eine Mail schicken und bekommt dann das Ergebnis im Browser angezeigt
- https://dkimvalidator.com/ auch hier per Mail
- https://www.appmaildev.com/de/dkim
- https://www.spf-record.de/ hier kann man SPF-Records erzeugen und überprüfen
- https://www.kitterman.com/spf/validate.html ein Tool zum Testen
- https://de.ssl-tools.net/mailservers SSL-Test
- https://mxtoolbox.com/dkim.aspx
- https://toolbox.googleapps.com/apps/main/
Zum Thema Mail-Server-Konfiguration
- https://mxtoolbox.com/diagnostic.aspx
- https://tools.dnsstuff.com/mstc
- https://network-tools.webwiz.net/email-test.htm
Mediawiki
- https://de.wikipedia.org/wiki/Hilfe:Syntaxhighlight
- https://www.mediawiki.org/wiki/Extension:SyntaxHighlight/de
vsftpd
Da wir auf dem System nur virtuelle Nutzer haben, muss auch der FTP-Server auf die Benutzerdatenbank zugreifen können. Dazu dienen die folgenden Konfigurationsschritte:
Bei 20.04 scheint das Paket libpam-mysql in Ordnung zu sein. Die Installation von vsftpd ist dadurch relativ einfach:
apt install libpam-mysql vsftpd
direkt installieren.
Nun müssen noch am Anfang der Datei /etc/pam.d/vsftpd zwei Zeilen ergänzt werden:
auth sufficient pam_mysql.so user=postfix passwd=asswd host=localhost db=postfix table=mailbox usercolumn=username passwdcolumn=password crypt=1 where=active="1" account sufficient pam_mysql.so user=postfix passwd=asswd host=localhost db=postfix table=mailbox usercolumn=username passwdcolumn=password crypt=1 where=active="1" # Standard behaviour for ftpd(8). auth required pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed ...
Mit den beiden Zeilen wird dem Pam-System (bzw. dem Modul pam_mysql) mitgeteilt, dass es auf die MySQL-Datenbank zugreifen soll und wo es die notwendigen Daten findet. Statt der beiden langen Parameterlisten könnte man auch mit einem config_file arbeiten ( auth required pam_mysql.so config_file=/lib/security/pam_mysql.conf). Das hätte dann folgenden Aufbau:
users.host localhost users.database postix users.db_user postfix users.db_passwd asswd users.table mailbox users.user_column username users.password_column password users.password_crypt 1 users.where_clause active="1"
Nun habe ich in der Datei /etc/vsftpd.conf noch ein paar Änderungen vorgenommen. Hier eine Liste aller aktiven Einstellungen in alphabetischer Reihenfolge:
allow_writeable_chroot=YES anon_world_readable_only=YES anonymous_enable=YES chroot_list_enable=YES chroot_list_file=/etc/vsftpd.chroot_list chroot_local_user=YES connect_from_port_20=YES dirmessage_enable=YES dual_log_enable=YES guest_enable=YES guest_username=ftp listen=YES listen_ipv6=NO local_enable=YES log_ftp_protocol=YES nopriv_user=ftpsecure pam_service_name=vsftpd pasv_max_port=30100 pasv_min_port=30000 rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key secure_chroot_dir=/var/run/vsftpd/empty setproctitle_enable=YES ssl_enable=NO use_localtime=YES user_config_dir=/etc/vsftpd/ vsftpd_log_file=/var/log/vsftpd.log write_enable=YES xferlog_enable=YES xferlog_file=/var/log/xferlog xferlog_std_format=YES
Der hier benutzte unterprivilegierte User ftpsecure muss noch angelegt werden:
adduser --system --home /var/run/vsftpd/empty --no-create-home --disabled-login ftpsecure
Nun muss noch für jeden Benutzer, der FTP nutzen können soll, eine Datei in /etc/vsftpd erstellt werden. Der Name der Datei ist der Benutzername, hier also die Mailadresse.
local_root=/var/www/vhosts/<verzeichnis>/httpdocs anon_umask=022 anonymous_enable=YES anon_world_readable_only=NO anon_upload_enable=YES anon_umask=022 anon_mkdir_write_enable=YES anon_other_write_enable=YES guest_username=www-data connect_from_port_20=YES
Automatische Updates
Auch eine Server-Distribution muss gelegentlich aktualisiert werden. Dazu dient das Paket unattended-upgrades, das zuerst einmal installiert werden muss.
apt-get install unattended-upgrades
Es gibt dann ein paar Konfigurationdateien, die angepasst werden müssen/können. /etc/apt/apt.conf.d/50unattended-upgrades
// Automatically upgrade packages from these (origin:archive) pairs
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
// Extended Security Maintenance; doesn't necessarily exist for
// every release and this system may not have it installed, but if
// available, the policy for updates is such that unattended-upgrades
// should also install from here by default.
"${distro_id}ESM:${distro_codename}";
"${distro_id}:${distro_codename}-updates";
// "${distro_id}:${distro_codename}-proposed";
// "${distro_id}:${distro_codename}-backports";
};
// List of packages to not update (regexp are supported)
Unattended-Upgrade::Package-Blacklist {
// "vim";
// "libc6";
// "libc6-dev";
// "libc6-i686";
};
// This option allows you to control if on a unclean dpkg exit
// unattended-upgrades will automatically run
// dpkg --force-confold --configure -a
// The default is true, to ensure updates keep getting installed
//Unattended-Upgrade::AutoFixInterruptedDpkg "false";
// Split the upgrade into the smallest possible chunks so that
// they can be interrupted with SIGUSR1. This makes the upgrade
// a bit slower but it has the benefit that shutdown while a upgrade
// is running is possible (with a small delay)
//Unattended-Upgrade::MinimalSteps "true";
// Install all unattended-upgrades when the machine is shuting down
// instead of doing it in the background while the machine is running
// This will (obviously) make shutdown slower
Unattended-Upgrade::InstallOnShutdown "false";
// Send email to this address for problems or packages upgrades
// If empty or unset then no email is sent, make sure that you
// have a working mail setup on your system. A package that provides
// 'mailx' must be installed. E.g. "user@example.com"
Unattended-Upgrade::Mail "root";
...
In dem oberen Bereich legt man Fest, welche Art von Updates installiert werden. Ich habe zusätzlich "${distro_id}:${distro_codename}-updates" aktiviert. Außerdem lasse ich mir per Mail berichten.
Dann sollte man noch die Datei /etc/apt/apt.conf.d/10periodic anlegen:
APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::AutocleanInterval "7"; APT::Periodic::Unattended-Upgrade "1";
Ausführlichere Informationen finden sich unter https://www.techgrube.de/tutorials/automatische-updates-auf-ubuntu-server-nutzen.
Nützliche Links
- https://yannici.de/server/linux/debian/debian-8-mailserver-installation/
- https://stackoverflow.com/questions/42300579/letsencrypt-certbot-multiple-renew-hooks
- https://www.exratione.com/2019/02/a-mailserver-on-ubuntu-18-04-postfix-dovecot-mysql/
- https://dokuwiki.tachtler.net/doku.php?id=tachtler:dovecot_plugins
- https://doc.dovecot.org/configuration_manual/config_file/config_variables/
- https://workaround.org/ispmail/jessie/postfix-dovecot