Root-Server mit Ubuntu 16.04
Ich habe nun schon häufiger davor zurück geschreckt auch bei den Servern von OpenSUSE auf Ubuntu umzustellen, obwohl auch Lukas Thiel das immer wieder angeregt hatte. Aktuell wird OpenSUSE aber bei den Strato-Servern nicht mehr supportet, so dass die Entscheidung für Ubuntu 16.04 nun gefallen ist.
Root Server Linux D400
Bei den bisherigen Servern haben wir mit der Hardware eigentlich noch keine Probleme, aber das System ist zu alt. Wenn man neue Typo3-Versionen benutzen will, dann benötigt man PHP7. Also war auf alle Fälle eine Neuinstallation fällig und die ist nun mal einfacher, wenn man auch gleich die Hardware erneuert. So habe ich mehr Zeit für die Konfiguration.
Die technischen Daten:
Intel® Xeon E3-1230v3 (4x6599 Bogomips) 4 x 3,3 GHz 16 GB RAM 2x2 TB Festplatte als Raid1
Die Bereitstellung des Rechners hat fast 48 Stunden gedauert, bestellt am Freitag Nachmittag (27.1.2017), bereit gestellt am Sonntag Nachmittag (29.1.2017. Nach der Bereitstellung ist noch kein System installiert, das löst man dann in der Verwaltungsoberfläche von Strato aus. Mindestlaufzeit bei diesem Server ist 12 Monate.
Bei der Partionierung hat man nicht viel Auswahl. Ich habe die Version mit der ausführlichsten Partitionierung gewählt und Ubuntu 16.04. Die Partitionsgrößen kann man nicht weiter beeinflussen, das ist etwas schade, da /home in der Regel viel zu groß eingestellt ist. Aber bisher habe ich trotzdem noch nie Platzprobleme bekommen. Knapp eine Stunde später war das Gerät dann erreichbar, partitioniert:
/dev/md0 /boot (1GB) /dev/md1 / (20GB) /dev/md2 /home (1138GB) /dev/md3 /var (758GB)
Irritiert hatte mich das Fehlen einer eigenen Partition für /srv, aber Ubuntu legt dort eigentlich keine Dateien ab. Die Datenbanken befinden sich unter /var/lib/mysql und die Webseiten unter /var/www/html und /usr/lib/cgi-bin.
Man kann die Partitionierung natürlich auch noch nachträglich ändern, das ist aber immer mit etwas Aufwand und Bastelei verbunden. Strato bietet dafür eine Minimal-Partitionierung an, gute Hinweise um Umgang mit den Raid-Partitionen findet man unter https://www.thomas-krenn.com/de/wiki/Software_RAID_mit_MDADM_verwalten.
Ubuntu 16.04 kommt mit Apache 2.4.18, PHP 7.0.13, MySQL 5.7.17, Dovecot 2.2.22 und Postfix 3.1.0
Was mir aufgefallen ist
Bei SUSE liefert
hostname
den kurzen Namen ohne Domain, bei der Ubuntu-Version den vollen Namen mit Domain, wie sonst hostname -f . Der kurzen Namen bekomme ich mittels
hostname -s
Das macht in manchen meiner Scripten einen Unterschied.
Root Server Linux B500
Jetzt soll auch der zweite Netthelp-Server aktualisiert werden. Dazu habe ich im April 2018 einen Root Server Linux B500 bestellt (Server-Sondermodell).
Die technischen Daten:
Intel® Xeon E3-1270v3 Haswell (4x7000 Bogomips) 4 x 3,5 GHz 32 GB RAM 2x2 TB Festplatte als Raid1 1x120 GB SSD
Naja, was die kleine SSD soll, leuchtet mir nicht so ganz ein, aber wird ja sicher nicht schaden.
Irritiert haben mich die Partitionsvorschläge von Strato. Eigentlich waren bei allen Vorschlägen wesentliche Partitionen auf der SSD. Ich denke, dass es nicht sinnvoll ist Partitionen wie /var oder /home auf die SSD zu legen, da dort viel geschrieben wird. Außerdem werden die Partitionen auf der SSD viel zu klein. Um dann die Festplatten zu nutzen, die als /data eingebunden werden, müsste man viel tricksen.
Ich habe letztendlich die Standard-Partitionierung ausgewählt:
/dev/sda1 /boot (969M) /dev/sda2 swap (7,6G) /dev/sda3 / (109G) /dev/md0 /data (1.834G)
Mein Ziel dabei ist die /data-Partition und das zugehörige Raid aufzulösen und auf die Partitionen /var und /home aufzuteilen.
Zuerst das vorhandene Raid auflösen:
umount /data mdadm --stop /dev/md0 mdadm --zero-superblock /dev/sdb1 mdadm --zero-superblock /dev/sdc1
Festplatten partitionieren
fdisk /dev/sdb Gerät Boot Start Ende Sektoren Größe Id Typ /dev/sdb1 2048 2147485695 2147483648 1T fd Linux raid autodetect /dev/sdb2 2147485696 3907029167 1759543472 839G fd Linux raid autodetect fdisk /dev/sdc Gerät Boot Start Ende Sektoren Größe Id Typ /dev/sdc1 2048 2147485695 2147483648 1T fd Linux raid autodetect /dev/sdc2 2147485696 3907029167 1759543472 839G fd Linux raid autodetect
Raid erzeugen
mdadm --create /dev/md1 --level=1 --raid-devices=2 --name=h2778056:1 /dev/sdb1 /dev/sdc1 mdadm --create /dev/md2 --level=1 --raid-devices=2 --name=h2778056:2 /dev/sdb2 /dev/sdc2 #mdadm --detail --scan >> /etc/mdadm/mdadm.conf oder einfacher noch: /usr/share/mdadm/mkconf > /etc/mdadm/mdadm.conf
Bei aktuellen Ubuntu-Systemen liefert hostname den vollständigen Rechnernamen mit Domain (so wie bei OpenSUSE hostname -f). Hier sollte nur der Name ohne Domain eingetragen werden.
Dateisystem auf /dev/md1 und /dev/md2 erzeugen und mounten:
mkfs -t ext4 /dev/md2 mount /dev/md1 /home mkfs -t ext4 /dev/md1 mount /dev/md2 /mnt/ cp -a /var/* /mnt/ umount /mnt mount /dev/md2 /var (Dass dieser Teil geklappt hat, erspart den Wechsel in ein Rettungssystem. Es geht wohl nur in dem minimalen Grundsystem) joe /etc/fstab #/dev/md0 /data ext4 defaults 1 2 /dev/md1 /home ext4 defaults 1 2 /dev/md2 /var ext4 defaults 1 2
Dann mit
cat /proc/mdstat
getestet, wie weit die Synchronisation der Laufwerke vorangeschritten ist.
Personalities : [raid1] [raid0] [linear] [multipath] [raid6] [raid5] [raid4] [raid10] md2 : active raid1 sdc2[1] sdb2[0] 879640640 blocks super 1.2 [2/2] [UU] resync=DELAYED bitmap: 7/7 pages [28KB], 65536KB chunk md1 : active raid1 sdc1[1] sdb1[0] 1073610752 blocks super 1.2 [2/2] [UU] [=========>...........] resync = 45.6% (490366272/1073610752) finish=62.9min speed=154345K/sec bitmap: 6/8 pages [24KB], 65536KB chunk unused devices: <none>
dann unbedingt
update-initramfs -u
und abschließend neu booten. Ohne das Updaten des RamFS werden die Partitionen beim Booten als /dev/127 und /dev/126 angelegt, das herauszufinden hat mich einige Zeit gekostet.
Bei Installationsfehlern kann man ggf. mit folgenden Befehlen Änderungen vornehmen:
mdadm --create /dev/md1 -l1 -n2 --metadata=1.0 --assume-clean /dev/sdb1 /dev/sdc1 (ändert die Version der Metadaten, dabei verändern sich auch UUIDs) mdadm --assemble /dev/md/1 --name=h2778056:1 --update=name /dev/sdb1 /dev/sdc1 (ändert den Namen der Partition)
SSD-Problem
Nun macht die SSD wohl doch Probleme. Die Smartmontools melden:
Device: /dev/sda [SAT], 62 Offline uncorrectable sectors
Das Problem muss vor 656 Stunden, also etwa 27 Tagen aufgetreten sein. Eventuell hat der Vorbesitzer das Gerät deswegen zurück gegeben. Mal sehen, was der Strato-Support antwortet und wann.
Heute morgen hatte ich eine nette Mail im Kasten, mit der ein Strato-Mitarbeiter mir mitteilte, dass er das SSD-Problem noch nicht dramatisch sieht, mir aber trotzdem einen Serveraustausch anbot. Da ich tagsüber nicht dazu gekommen bin meine Mails zu lesen, habe ich die Nachricht erst am Abend gesehen und ihm geantwortet, dass ich vorsichtshalber lieber den Serveraustausch hätte. Leider hat er wohl schon Feierabend, so dass ich warten muss, bis der entsprechende Button in der Verwaltungsoberfläche auftaucht.
Bei Strato hat sich wirklich etwas getan. Heute Morgen hatte ich die Rückmeldung von dem gleichen Strato-Mitarbeiter, dass der Button zum Anfordern des Serveraustausches nun aktiviert ist. Ich habe dann im Laufe des Tages nachgeschaut und wirklich, oberhalb des Buttons zur Neuinstallation gibt es jetzt ein Checkfeld für den Server-Austausch. Ich habe das Kästchen angeklickt und eine neue Installation beauftragt. Relativ geschickte Kombination, da dann keine Frage nach der Sicherung der Daten mehr aufkommen kann.
Mal sehen, wie lange der Austausch dauern wird. Rechnername und IP sollen bleiben. Hoffentlich sind auf dem neuen Rechner dann die Platten in Ordnung.
Ich bin begeistert, nur wenige Stunden nach meinem Auftrag ist der Tausch abgeschlossen und das System neu installiert. Die aktuellen Platten haben keine Fehler und mit 4 Jahren auch eine deutlich kürzere Laufzeit. Die verbrauchte Lebensdauer der SSD liegt bei 20% und nicht bei 40% wie vorher. Ich werde noch ausführlich untersuchen, aber das sieht schon einmal sehr positiv aus.
Grundinstallation
Bevor man mit der eigentlichen Einrichtung beginnt, sollte man den Server unbedingt einmal neu starten.
Benötigt man einmal die Liste aller installierten Pakete, so bekommt man die mit
dpkg --get-selections
Leider steht dann immer noch install hinter dem Paketnamen, aber das lässt sich ja mit Suchen und Ersetzen beseitigen.
In den aktuellen Ubuntu-Versionen läuft das Starten und Stoppen der Netzwerkdienste systemctl, der klassische Runlevel-Editor funktioniert da teilweise auch noch, als Umleitung.
systemctl status|start|stop <daemon>.service systemctl enable|disable <daemon>.service
Am Ende der Installation sollte man daran denken, die Namensauflösung für die Strato-Server IP auf einen eigenen Namen zu setzen und nicht die Voreinstellung zu belassen. Manche Provider lehnen Mails von Absenderadressen ab, wenn noch der Standardname gesetzt ist.
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://help.ubuntu.com/lts/serverguide/firewall.html, http://www.savvyadmin.com/ubuntus-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
Da meine Internetverbindung per SSH lange Zeit nicht stabil war, ich bin O2-Kunde, nutzte ich das Programm mosh um die Probleme zu lösen. Also noch einrichten:
apt install mosh
und
ufw allow mosh
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, dass 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.
Erste Installationen
Ich habe mir dann noch gleich ein paar nützliche Hilfsmittel installiert:
apt install synaptic apt-xapian-index update-apt-xapian-index -vf
Installiert das grafische Tool zur Paketverwaltung. Dann kann ich relativ leicht nach Paketen suchen.
Auch grafische Tools lassen sich per ssh aufrufen (aber leider nicht mit mosh), 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 18470 Stunden gelaufen sind, also etwas mehr als zwei Jahre. Es gibt aber keine Reallocierten Sektoren und beide Platten haben die gleiche Laufzeit.
Im Netzwerk benötigt man dann oft auch whois Informationen
apt install whois
Datenbank
Zur Installation von Server und Client dient der folgende Aufruf:
apt install mysql-client mysql-server mysql-common
Ich habe dann die Konfigurationsdatei /etc/mysql/mysql.conf.d/mysqld.cnf ergänzt
#ergänzt von U.D. innodb_flush_log_at_trx_commit = 2
und die Datenbank neu gestartet. Den Datenbankzugriff sollte man nicht über das Netz erlauben, also auch in der Firewall den entsprechenden Port nicht öffnen. Die Datenbank wird ja in der Regel nur über lokale Anwendungen genutzt und über PHPMyAdmin administriert.
Apache-Webserver
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 libapache2-mod-php7.0 php php-auth php-auth-http php-auth-sasl php-bz2 php-cli php-common php-crypt-chap apt install php-db php-gd php-geoip php-gettext php-imap php-log php-mail php-mbstring php-mcrypt php-mdb2 php-mysql php-net-smtp apt install php-net-socket php-pear php-phpseclib php-recode php-soap php-tcpdf php-xml php7.0 php7.0-bz2 php7.0-cli php7.0-common apt install php7.0-gd php7.0-imap php7.0-json php7.0-mbstring php7.0-mcrypt php7.0-mysql php7.0-opcache php7.0-readline php7.0-recode apt install php7.0-soap php7.0-xml php7.0-zip phpmyadmin
Da sind jetzt eine Reihe von Doppelungen drin, sowohl das Paket, als auch das Metapaket. Es ist aber das, was mir
dpkg --get-selections | grep php
liefert.
Laut https://www.thomaschristlieb.de/mehrere-php-versionen-auf-einem-linux-server-mit-php-fpm/ kann man eventuell php7 und php5 parallel betreiben.
Nun noch ein paar Perl-Pakete:
apt install libapache2-mod-perl2 libapache2-reload-perl libapparmor-perl libarchive-zip-perl libauthen-sasl-perl libbsd-resource-perl apt install libcairo-perl libcgi-fast-perl libcgi-pm-perl libdevel-symdump-perl libencode-locale-perl libfcgi-perl libfile-basedir-perl apt install libfile-desktopentry-perl libfile-listing-perl libfile-mimeinfo-perl libfont-afm-perl libgd-graph-perl libgd-perl libgd-text-perl apt install libglib-perl libgtk2-perl libhtml-form-perl libhtml-format-perl libhtml-parser-perl libhtml-tagset-perl libhtml-template-perl apt install libhtml-tree-perl libhttp-cookies-perl libhttp-daemon-perl libhttp-date-perl libhttp-message-perl libhttp-negotiate-perl apt install libimage-magick-perl libimage-magick-q16-perl libio-html-perl libio-socket-ssl-perl libipc-system-simple-perl liblocale-gettext-perl apt install liblwp-mediatypes-perl liblwp-protocol-https-perl libmailtools-perl libnet-dbus-perl libnet-http-perl libnet-smtp-ssl-perl apt install libnet-ssleay-perl libpango-perl libperl5.22:amd64 libtext-charwidth-perl libtext-iconv-perl libtext-wrapi18n-perl apt install libtie-ixhash-perl libtimedate-perl liburi-perl libwww-perl libwww-robotrules-perl libx11-protocol-perl libxml-parser-perl apt install libxml-twig-perl libxml-xpathengine-perl perl perl-base perl-modules-5.22 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"
letsencrypt
Für die verschlüsselte Übertragung von Webseiten werden Zertifikate benötigt. Für die Installation gemäß http://www.debacher.de/ublog/2016/06/letsencrypt/ benötige ich git:
apt install git
Letsencrypt rotiert täglich seine Logdatei und legt nach der Voreinstellung bis zu 1.000 Backups davon an (siehe /root/letsencrypt/certbot/constants.py). Flexibler ist es mit Logrotate zu arbeiten:
$ cat /etc/letsencrypt/cli.ini # Da wir logrotate für größere Flexibilität nutzen, # deaktivieren wir die intere logrotation. max-log-backups = 0
und erstellen:
$ cat /etc/logrotate.d/letsencrypt /var/log/letsencrypt/*.log { rotate 12 weekly compress missingok }
für Typo3
Da ich viel mit Typo3 arbeite habe ich etwas an den PHP-Einstellungen gedreht in der /etc/php/7.0/apache2/php.ini:
post_max_size=10M upload_max_filesize=10M max_execution_time=240 max_input_vars = 1500
Typo3 benötigt unbedingt imagemagick (oder alternativ graphicsmagick)
apt install imagemagick imagemagick-doc
apt install graphicsmagick
/etc/apache2/sites-available/000-default.conf
Im ersten Schritt ändere ich einen Teil der Standardvorgaben in der Datei 000-default.conf. Der Name resultiert aus der Tatsache, dass der Apache die Dateien in alphabetischer Reihenfolge einliest. Diese Datei muss als erste eingelesen werden.
ServerAdmin Webmaster@<dummy>.de ServerTokens Major DocumentRoot /var/www/htdocs Alias /groupoffice /var/www/htdocs/dummy Alias /squirrelmail /var/www/htdocs/dummy Alias /webmail /var/www/dummy Alias /webstat /var/www/htdocs/webalizer <Directory "/var/www/vhosts"> AllowOverride All Options +FollowSymLinks Require all granted </Directory> <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 (XoviBot|CareerBot|GrapeshotCrawler|iCjobs|magpie-crawler|proximic) ist_ein_bot # Nutzlos, Schlecht bzw. unbekannt BrowserMatchNoCase (Ezooms|updown_tester|^Java) ist_ein_bot # Per IP SetEnvIfNoCase Remote_Addr (62\.138\.0\.25) ist_ein_bot </IfModule> <VirtualHost *:80> ServerName default UseCanonicalName Off DocumentRoot /var/www/vhosts/default/httpdocs Alias /groupoffice /var/www/htdocs/dummy Alias /squirrelmail /var/www/htdocs/dummy Alias /webmail /var/www/htdocs/dummy Alias /postfixadmin /var/www/htdocs/dummy Alias /phpMyAdmin /var/www/htdocs/dummy Alias /roundcube /var/www/htdocs/dummy Alias /.well-known /var/www/htdocs/.well-known ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined <IfModule mod_ssl.c> SSLEngine off </IfModule> <Directory /var/www/vhosts/default/httpdocs> AllowOverride All Options None Require all granted <IfModule mod_php5.c> php_admin_flag engine on php_admin_flag safe_mode off # php_admin_value include_path "/var/www/htdocs/horde/pear:/var/www/htdocs:./" # php_admin_value open_basedir "/var/www/htdocs:/tmp" </IfModule> </Directory> </VirtualHost>
Der Ordner /var/www/htdocs/dummy ist hier ein leerer Dummy-Ordner, damit Zugriffe auf die entsprechenden Anwendungen ins Leere laufen. Natürlich müssen die in der Konfiguration genannten Pfade eingerichtet sein, also z.B. /var/www/vhosts/default/httpdocs und /var/www/vhosts/default/httpsdocs. Idealerweise sollte in den Ordnern auch eine Datei index.html liegen, um Fehlermeldungen zu vermeiden.
/etc/apache2/sites-available/default-ssl.conf
Damit die Konfiguration funktionieren kann muss, sofern das Modul SSL aktiviert wurde, an der angegebenen Stelle ein Zertifikat vorliegen. Es kann ruhig ein selbst erstelltes Zertifikat sein. Zur Vereinfachung ist bei Ubuntu gleich ein Zertifikat erstellt.
Dann habe ich mir die vorhandene Datei default-ssl.conf angepasst:
<IfModule mod_ssl.c> <VirtualHost _default_:443 > ServerAdmin webmaster@<dummy>.de # ServerName default UseCanonicalName Off DocumentRoot /var/www/vhosts/default/httpsdocs ScriptAlias /cgi-bin/ "/usr/lib/cgi-bin/" Alias /groupoffice /var/www/htdocs/dummy Alias /squirrelmail /var/www/htdocs/dummy Alias /webmail /var/www/htdocs/dummy Alias /postfixadmin /var/www/htdocs/dummy Alias /phpMyAdmin /var/www/htdocs/dummy Alias /roundcube /var/www/htdocs/dummy ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLEngine on SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNUL SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key <FilesMatch "\.(cgi|shtml|phtml|php)$"> SSLOptions +StdEnvVars </FilesMatch> <Directory "/usr/lib/cgi-bin/"> AllowOverride None Options None Require all denied SSLOptions +StdEnvVars </Directory> <Directory /var/www/vhosts/default/httpsdocs> SSLRequireSSL AllowOverride None Options None Require all granted </Directory> </VirtualHost> </IfModule>
Im Prinzip hätte ich auch beides in eine Datei packen können, aber es waren ja schon die beiden vorhanden.
Für alle weiteren https Seiten benutze ich Zertifikat von letsencrypt, aber für Stratoserver-Adressen erstellt letsencrypt keine Zertifikate mehr, weil es schon zuviele für xxx.stratoserver.net gibt.
/etc/apache2/sites-available/stratoserver.net.conf
Ich will einen Unterschied haben zwischen der Seite die bei einem Aufruf über die IP-Adresse oder eine nicht konfigurierte Domain erfolgt und der Seite, die über den korrekten Server-Namen geliefert wird. Daher ein virtueller Server für legale Namen.
<VirtualHost *:80> ServerName h2656233.stratoserver.net ServerAlias server3.netthelp.de UseCanonicalName Off DocumentRoot /var/www/vhosts/default/httpdocs CustomLog /var/log/apache2/server_access_log combined ErrorLog /var/log/apache2/server_error_log ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin/" Alias /phpMyAdmin /var/www/htdocs/phpMyAdmin Alias /postfixadmin /var/www/htdocs/postfixadmin Alias /webmail /var/www/roundcubemail Alias /webstat /var/www/vhosts/default/webstat Alias /roundcube /var/www/roundcubemail Alias /roundcubemail /var/www/roundcubemail Alias /.well-known /var/www/htdocs/.well-known <IfModule mod_ssl.c> SSLEngine off </IfModule> <Directory "/var/www/vhosts/cgi-bin/cgi-bin/"> AllowOverride None Options None Require all granted </Directory> <Directory /var/www/vhosts/default/httpdocs> AllowOverride All Options None Require all granted <IfModule mod_php5.c> php_admin_flag engine on php_admin_flag safe_mode off # php_admin_value include_path "/var/www/htdocs/horde/pear:/var/www/htdocs:./" # php_admin_value open_basedir "/var/www/htdocs:/tmp" </IfModule> </Directory> </VirtualHost> <IfModule mod_ssl.c> <VirtualHost *:443 > ServerName h2656233.stratoserver.net UseCanonicalName Off DocumentRoot /var/www/vhosts/default/httpsdocs CustomLog /var/log/apache2/server_access_log combined ErrorLog /var/log/apache2/server_error_log ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin/" Alias /phpMyAdmin /var/www/htdocs/phpMyAdmin Alias /postfixadmin /var/www/htdocs/postfixadmin Alias /webmail /var/www/roundcubemail Alias /webstat /var/www/vhosts/default/webstat Alias /roundcube /var/www/roundcubemail Alias /roundcubemail /var/www/roundcubemail SSLEngine on SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNUL SSLCertificateFile /etc/letsencrypt/live/server3.netthelp.de/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/server3.netthelp.de/privkey.pem # SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem # SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key SSLProtocol All -SSLv2 -SSLv3 <Directory "/var/www/vhosts/default/cgi-bin/"> AllowOverride None Options None Require all granted </Directory> <Directory /var/www/vhosts/default/httpsdocs> SSLRequireSSL AllowOverride None Options None Require all granted </Directory> </VirtualHost> </IfModule>
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> ServerAlias <dummy>.server3.netthelp.de UseCanonicalName Off DocumentRoot /var/www/vhosts/<dummy>/httpdocs CustomLog /var/log/apache2-vhosts.d/<dummy>_access.log combined ErrorLog /var/log/apache2-vhosts.d/<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 <IfModule mod_ssl.c> SSLEngine off </IfModule> <Directory /var/www/vhosts/<dummy>/httpdocs> <IfModule mod_php5.c> php_admin_flag engine on php_admin_flag safe_mode off php_admin_value include_path "/var/www/vhosts/<dummy>/httpdocs:.:/tmp:./:/usr/share/php5/PEAR/:/var/www/typo3src" php_admin_value open_basedir "/var/www/vhosts/<dummy>/httpdocs:/tmp:.:/usr/share/php5/PEAR/:/var/www/typo3src" php_value date.timezone "Europe/Berlin" </IfModule> <IfModule mod_python.c> <Files ~ (\.py$)> SetHandler python-program PythonHandler mod_python.cgihandler </Files> </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> UseCanonicalName Off DocumentRoot /var/www/vhosts/<dummy>/httpdocs CustomLog /var/log/apache2-vhosts.d/<dummy>_access.log combined ErrorLog /var/log/apache2-vhosts.d/<dummy>_error.log ScriptAlias /cgi-bin/ /var/www/vhosts/<dummy>/cgi-bin/ Alias /webstat /var/www/vhosts/<dummy>/webstat SSLEngine on <Directory /var/www/vhosts/<dummy>/httpdocs> <IfModule mod_php5.c> php_admin_flag engine on php_admin_flag safe_mode off php_admin_value include_path "/var/www/vhosts/<dummy>/httpdocs:.:/tmp:./:/usr/share/php5/PEAR/:/var/www/typo3src" php_admin_value open_basedir "/var/www/vhosts/<dummy>/httpdocs:/tmp:.:/usr/share/php5/PEAR/:/var/www/typo3src" php_value date.timezone "Europe/Berlin" </IfModule> <IfModule mod_python.c> <Files ~ (\.py$)> SetHandler python-program PythonHandler mod_python.cgihandler </Files> </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 SSLProtocol All -SSLv2 -SSLv3 SSLHonorCipherOrder On SSLCompression off # Add six earth month HSTS header for all users... # Header add Strict-Transport-Security "max-age=15768000" SSLCipherSuite EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown CustomLog /var/log/apache2-vhosts.d/<dummy>_ssl.log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" </VirtualHost> </IfModule>
Server-Module
Vorsichtshalber noch einmal ein paar Apache-Module aktivieren:
a2enmod perl a2enmod cgi a2enmod expires a2enmod headers a2enmod rewrite service apache2 restart
Verzeichnisse
Ein paar Verzeichnsse 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/server2-sicherungen
Mailsystem
Auf diesem Server soll es möglichst wenig Systembenutzer geben. Alle Mailadressen sollen also virtuell sein. Das System besteht aus folgenden Komponenten:
- Postfix
- Dovecot
- MySQL
- PostfixAdmin
Eine weitere wichtige Rolle hierbei spielt
- Roundcube
damit kann der virtuelle Benutzer Mailfilter bearbeiten und sein eigenes Passwort ändern.
Vorweg noch ein paar Informationen, die für das Testen ganz nützlich sind, man kann Mails in der Warteschlange (Abfrage mittels mailq) einzeln oder alle auf einen Schlag löschen.
postsuper -d ALL postsuper -d 52DBF19F51 (die komische Zeichenkette ist die Queue-ID die mailq mit ausgibt, hier wird diese Mail gelöscht)
Den Inhalt der Mail findet man in
/var/spool/postfix/deferred/5/52DBF19F51
Zustellinformationen bzw. Fehlermeldungen in
/var/spool/postfix/defer/5/52DBF19F51
oder per
postcat -vq 52DBF19F51 (zeigt die Mail mit der angegebenen ID)
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
Zunächst müssen einige Pakete installiert werden
apt install amavisd-new amavisd-new-postfix postfix postfix-mysql postfix-policyd-spf-python postfixadmin dovecot-antispam spamass-milter spamassassin spamc apt install roundcube roundcube-core roundcube-mysql roundcube-plugins roundcube-plugins-extra mailutils apt install dovecot-antispam dovecot-core dovecot-imapd dovecot-lmtpd dovecot-managesieved dovecot-mysql dovecot-pop3d dovecot-sieve dovecot-sqlite
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 Programmes ist http://postfixadmin.sourceforge.net/. Das Programmpaket greift nur auf eine MySQL-Datenbank zu und nicht direkt in das Mailsystem ein.
Das Programm lässt sich ganz einfach über die Paketverwaltung installieren und liegt in der Version 2.3.7 vor (aktuell verfügbar ist 3.1: http://sourceforge.net/projects/postfixadmin/files/latest/download?source=files). Ich habe die aktuelle Version benutzt.
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 Postfixadmin 3.1 sie über setup.php an).
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', 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(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL DEFAULT , `value` varchar(20) NOT NULL DEFAULT , PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 COMMENT='PostfixAdmin settings'; CREATE TABLE `domain` ( `domain` varchar(255) NOT NULL, `description` varchar(255) CHARACTER SET utf8 NOT NULL, `aliases` int(10) NOT NULL DEFAULT '0', `mailboxes` int(10) NOT NULL DEFAULT '0', `maxquota` bigint(20) NOT NULL DEFAULT '0', `quota` bigint(20) 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(11) 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') DEFAULT NULL, `src_user` varchar(255) NOT NULL, `src_password` varchar(255) NOT NULL, `src_folder` varchar(255) NOT NULL, `poll_time` int(11) unsigned NOT NULL DEFAULT '10', `fetchall` tinyint(1) unsigned NOT NULL DEFAULT '0', `keep` tinyint(1) unsigned NOT NULL DEFAULT '0', `protocol` enum('POP3','IMAP','POP2','ETRN','AUTO') DEFAULT NULL, `usessl` tinyint(1) unsigned NOT NULL DEFAULT '0', `sslcertck` tinyint(1) NOT NULL DEFAULT '0', `sslcertpath` varchar(255) CHARACTER SET utf8 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=InnoDB 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, KEY `timestamp` (`timestamp`), KEY `domain_timestamp` (`domain`,`timestamp`) ) ENGINE=MyISAM 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 NOT NULL, `maildir` varchar(255) NOT NULL, `quota` bigint(20) 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', PRIMARY KEY (`username`), KEY `domain` (`domain`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Mailboxes'; CREATE TABLE `quota` ( `username` varchar(255) NOT NULL, `path` varchar(100) NOT NULL, `current` bigint(20) NOT NULL DEFAULT '0', PRIMARY KEY (`username`,`path`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; CREATE TABLE `quota2` ( `username` varchar(100) NOT NULL, `bytes` bigint(20) NOT NULL DEFAULT '0', `messages` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`username`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; CREATE TABLE `vacation` ( `email` varchar(255) NOT NULL, `subject` varchar(255) CHARACTER SET utf8 NOT NULL, `body` text CHARACTER SET utf8 NOT NULL, `activefrom` timestamp NOT NULL DEFAULT '1999-12-31 23:00:00', `activeuntil` timestamp NOT NULL DEFAULT '1999-12-31 23:00:00', `cache` text NOT NULL, `domain` varchar(255) NOT NULL, `interval_time` int(11) 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 NOT NULL, `notified` varchar(255) CHARACTER SET latin1 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.inc.php
In dieser Datei der Ubuntu-Version sind viele Vor-Einstellungen anders, als ich es von meinen bisherigen Installationen gewohnt war. Hier ein paar Einstellungen, die wohl eine Rolle spielen:
$CONF['configured'] = true; $CONF['setup_password'] = 'changeme'; $CONF['default_language'] = 'de'; $CONF['admin_email'] = 'postmaster@change-this-to-your.domain.tld'; $CONF['smtp_server'] = 'localhost'; $CONF['smtp_port'] = '25'; $CONF['encrypt'] = 'md5crypt'; $CONF['authlib_default_flavor'] = 'md5raw'; $CONF['dovecotpw'] = "/usr/bin/doveadm pw"; $CONF['min_password_length'] = 5; $CONF['generate_password'] = 'NO'; $CONF['show_password'] = 'NO'; $CONF['page_size'] = '20'; $CONF['domain_path'] = 'YES'; $CONF['domain_in_mailbox'] = 'NO'; $CONF['maildir_name_hook'] = 'NO'; $CONF['aliases'] = '10'; $CONF['mailboxes'] = '10'; $CONF['maxquota'] = '10240'; $CONF['quota'] = 'YES'; $CONF['quota_multiplier'] = '1024000'; $CONF['transport'] = 'NO'; $CONF['transport_options'] = array ( $CONF['transport_default'] = 'virtual'; $CONF['vacation'] = 'NO'; $CONF['vacation_domain'] = 'autoreply.change-this-to-your.domain.tld'; $CONF['vacation_control'] ='YES'; $CONF['vacation_control_admin'] = 'YES'; $CONF['alias_control'] = 'YES'; $CONF['alias_control_admin'] = 'YES'; $CONF['special_alias_control'] = 'NO'; $CONF['alias_goto_limit'] = '0'; $CONF['alias_domain'] = 'YES'; $CONF['backup'] = 'NO'; $CONF['sendmail'] = 'YES'; $CONF['logging'] = 'YES'; $CONF['fetchmail'] = 'YES'; $CONF['fetchmail_extra_options'] = 'NO'; $CONF['show_header_text'] = 'NO'; $CONF['header_text'] = ':: Postfix Admin ::'; $CONF['show_footer_text'] = 'YES'; $CONF['footer_text'] = 'Return to change-this-to-your.domain.tld'; $CONF['welcome_text'] = <<<EOM Herzlich Willkommen, zum Netthelp E-Mail Postfach. Bei Fragen oder Problemen bitte Uwe Debacher ansprechen EOM; $CONF['emailcheck_resolve_domain']='YES'; $CONF['show_status']='YES'; $CONF['show_status_key']='YES'; $CONF['show_status_text']=' '; $CONF['show_undeliverable']='YES'; $CONF['show_undeliverable_color']='tomato'; $CONF['show_undeliverable_exceptions']=array("unixmail.domain.ext","exchangeserver.domain.ext","gmail.com"); $CONF['show_popimap']='YES'; $CONF['show_popimap_color']='darkgrey'; $CONF['show_custom_domains']=array("subdomain.domain.ext","domain2.ext"); $CONF['show_custom_colors']=array("lightgreen","lightblue"); $CONF['recipient_delimiter'] = ""; $CONF['create_mailbox_subdirs_prefix']='INBOX.'; $CONF['used_quotas'] = 'YES'; $CONF['new_quota_table'] = 'YES';
Version 3.1
Die momentan aktuelle Version besitzt eine Reihe von neuen Funktionen. Ich habe mir das Archiv also heruntergeladen und nach /var/www/postfixadmin-3.1 installiert.
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'] = '533a0f62bf8dcf073112eb0a0ed8929a:d85f0fe1081dccf9738b01fa7b377005b2ee8d9e'; $CONF['default_language'] = 'de'; // Database Config $CONF['database_type'] = 'mysqli'; $CONF['database_host'] = 'localhost'; $CONF['database_user'] = '<benutzer>'; $CONF['database_password'] = '<passwort>'; $CONF['database_name'] = '<datenbank>'; $CONF['admin_email'] = 'postmaster@netthelp.de'; $CONF['page_size'] = '20'; $CONF['default_aliases'] = array ( 'abuse' => 'abuse@netthelp.de', 'hostmaster' => 'hostmaster@netthelp.de', 'postmaster' => 'postmaster@netthelp.de', 'webmaster' => 'webmaster@netthelp.de' ); $CONF['quota'] = 'YES'; $CONF['footer_text'] = 'Zurück zu Netthelp.de'; $CONF['footer_link'] = 'http://netthelp.de'; // Welcome Message // This message is send to every newly created mailbox. // Change the text between EOM. $CONF['welcome_text'] = <<<EOM Herzlich Willkommen, zum Netthelp E-Mail Postfach. Bei Fragen oder Problemen bitte Uwe Debacher ansprechen EOM; $CONF['show_undeliverable_exceptions']=array("netthelp.de","debacher.de"); $CONF['used_quotas'] = 'YES'; $CONF['maxquota'] = '2048'; $CONF['domain_quota_default'] = '0';
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.
Version 3.2
Aktuell ist jetzt die Version 3.2, hier gibt es eine kleine Änderung zu beachten, der Alias-Eintrag in der VServer-Konfiguration muss jetzt auf das Unterverzeichnis public zeigen:
Alias /postfixadmin /var/www/postfixadmin-3.2/public
AmaVis
Diese Programm ist dazu da sich um Spam und Viren in EMails zu kümmern. Dazu arbeitet es mit Clamav und Spamassasin zusammen.
Für die Zusammenarbeit ist etwas Vorarbeit zu leisten, ich orientiere mich dabei an https://www.exratione.com/2016/05/a-mailserver-on-ubuntu-16-04-postfix-dovecot-mysql/
Zuerst werden die Programme gegenseitig in ihre Gruppen aufgenommen:
adduser clamav amavis adduser amavis clamav
Dann wird die Datei /etc/clamav/clamd.conf etwas angepasst
# Needed to allow things to work with Amavis, when both amavis and clamav # users are added to one another's groups. AllowSupplementaryGroups true
In der Datei /etc/amavis/conf.d/15-content_filter_mode müssen die Checks überhaupt erst einmal aktiviert werden, indem man die Kommentarzeichen vor den Zeilen entfernt.
use strict; # You can modify this file to re-enable SPAM checking through spamassassin # and to re-enable antivirus checking. # # Default antivirus checking mode # Please note, that anti-virus checking is DISABLED by # default. # If You wish to enable it, please uncomment the following lines: @bypass_virus_checks_maps = ( %bypass_virus_checks, @bypass_virus_checks_acl, $bypass_virus_checks_re); # # Default SPAM checking mode # Please note, that anti-spam checking is DISABLED by # default. # If You wish to enable it, please uncomment the following lines: @bypass_spam_checks_maps = ( %bypass_spam_checks, @bypass_spam_checks_acl, $bypass_spam_checks_re); 1; # ensure a defined return
Ob die Anpassung in /etc/default/spamassassin notwendig ist, wurde mir nicht ganz klar.
# Change to one to enable spamd ENABLED=1 # Cronjob # Set to anything but 0 to enable the cron job to automatically update # spamassassin's rules on a nightly basis CRON=1
Nun noch /etc/amavis/conf.d/50-user anpassen, damit die lokalen Domains aus der Datenbank genommen werden
use strict; # # Place your configuration directives here. They will override those in # earlier files. # # See /usr/share/doc/amavisd-new/ for documentation and examples of # the directives you can use in this file # # Three concurrent processes. This should fit into the RAM available on an # AWS micro instance. This has to match the number of processes specified # for Amavis in /etc/postfix/master.cf. $max_servers = 3; # Add spam info headers if at or above that level - this ensures they # are always added. $sa_tag_level_deflt = -9999; # Check the database to see if mail is for local delivery, and thus # should be spam checked. @lookup_sql_dsn = (['DBI:mysql:database=postfix;host=127.0.0.1;port=3306', 'postfix', 'assword']); $sql_select_policy = 'SELECT domain from domain WHERE CONCAT("@",domain) IN (%k)'; $sql_select_white_black_list = undef; # Uncomment to bump up the log level when testing. # $log_level = 2; #------------ Do not modify anything below this line ------------- 1; # ensure a defined return
Zum Abschluss die Dienste neu starten:
service clamav-freshclam restart service clamav-daemon restart service amavis restart service spamassassin restart
Dovecot
Unter http://www.debacher.de/wiki/Root-Server_mit_OpenSuSE_13.2#Dovecot habe ich die schrittweise Entwicklung meiner Dovecot-Konfiguration beschrieben. Diese Konfiguration passt weiterhin und befindet sich in der Datei /etc/dovecot/local.conf
disable_plaintext_auth = no first_valid_uid = 303 mail_access_groups = postfix mail_privileged_group = postfix mail_location = maildir:/var/vmail/%d/%n mail_home = /var/vmail/%d/%n/home mail_plugins = $mail_plugins quota passdb { args = /etc/dovecot/dovecot-mysql.conf driver = sql } plugin { sieve = ~/.dovecot.sieve sieve_dir = ~/sieve } dict { sqluserquota = mysql:/etc/dovecot/dovecot-dict-sql-user.conf } protocols = imap pop3 lmtp sieve ssl = yes #ssl_cert = </etc/letsencrypt/live/server2.netthelp.de/fullchain.pem #ssl_key = </etc/letsencrypt/live/server2.netthelp.de/privkey.pem ssl_cert = </etc/ssl/certs/ssl-cert-snakeoil.pem ssl_key = </etc/ssl/private/ssl-cert-snakeoil.key userdb { args = /etc/dovecot/dovecot-mysql.conf driver = sql } verbose_proctitle = yes 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 } service auth { unix_listener /var/spool/postfix/private/auth { group = postfix mode = 0660 user = postfix } } protocol lmtp { mail_plugins = $mail_plugins sieve } 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 } } plugin { #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 = maildir:User quota:noenforcing quota = dict:User Quota::noenforcing:proxy::sqluserquota } service quota-warning { executable = script /usr/local/bin/quota-warning.sh user = vmail unix_listener quota-warning { group = vmail mode = 0660 user = vmail } } service dict { unix_listener dict { mode = 0600 user = vmail } } auth_mechanisms = plain login #verbose_proctitle = no #mail_debug = yes #auth_debug = yes auth_debug_passwords = yes #auth_verbose = yes auth_verbose_passwords = sha1
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
durch Voranstellen einer Raute deaktiviert habe. Das spart viel Zeit bei allen Authentifizierungen.
/etc/dovecot/dovecot-mysql.conf
Diese Datei musste ich etwas anpassen, da bei Ubuntu die Mysql-Socket Adresse etwas anders ist.
# Database driver: mysql, pgsql driver = mysql # Currently supported schemes include PLAIN, PLAIN-MD5, DIGEST-MD5, and CRYPT. default_pass_scheme = CRYPT # Database options 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('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'
/etc/dovecot/dovecot-dict-sql-user.conf
Auch in dieser Datei muss ich der veränderten Socket Rechnung tragen
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 }
Erweiterungen
Manchmal taucht das Problem auf, dass auf dem Server mehrere Ordner für den gleichen Zwecke auftauchen, also z.B.
- .Junk
- .Spam
für unerwünschte Mails und
- .Trash
- .Papierkorb
für Müll
- .Gesendet
- .Sent
für versckickte Mails
Das kann man verhindern, indem man die Konfiguration der /etc/dovecot/conf.d/15-mailboxes.conf erweitert
namespace inbox {
mailbox Drafts { special_use = \Drafts } mailbox Junk { special_use = \Junk } mailbox Spam { special_use = \Junk } mailbox Trash { special_use = \Trash } mailbox Papierkorb { special_use = \Trash } .... }
Eventuell muss man hier auf die Eigenarten weiterer Client-Programme reagieren.
Roundcube
Dieses beliebte Webmail-Programm wird standardmäßig im Verzeichnis /var/lib/roundcube/ abgelegt. 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 77
// SQL Driver options // ------------------ // PEAR database DSN for performing the query. By default // Roundcube DB settings are used. $config['password_db_dsn'] = 'mysql://postfix:assword@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_method // %o is replaced with the old (current) password // %O is replaced with the crypted/hashed old (current) password // according to configured password_method // %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) // Deprecated macros: // %c is replaced with the crypt version of the new password, MD5 if available // otherwise DES. More hash function can be enabled using the password_crypt_hash // configuration parameter. // %D is replaced with the dovecotpw-crypted version of the new password // %n is replaced with the hashed version of the new password // %q is replaced with the hashed password before the change // Escaping of macros is handled by this module. // Default: "SELECT update_passwd(%c, %u)" $config['password_query'] = 'UPDATE mailbox SET password=%c WHERE username=%u'; // By default the crypt() function which is used to create the %c // parameter uses the md5 algorithm (deprecated, use %P). // You can choose between: des, md5, blowfish, sha256, sha512. $config['password_crypt_hash'] = 'md5'; ...
/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 sind zwei Änderungen notwendig.
Ab Zeile 25
// The mail host chosen to perform the log-in. // Leave blank to show a textbox at login, give a list of hosts // to display a pulldown menu or set one host as string. // To use SSL/TLS connection, enter hostname with prefix ssl:// or tls:// // Supported replacement variables: // %n - hostname ($_SERVER['SERVER_NAME']) // %t - hostname without the first part // %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part) // %s - domain name after the '@' from e-mail address provided at login screen // For example %n = mail.domain.tld, %t = domain.tld $config['default_host'] = 'localhost';
Ab Zeile 74
// List of active plugins (in plugins/ directory) $config['plugins'] = array( 'archive', 'zipdownload', 'managesieve', 'password', );
Postfix
Das zentrale Mailprogramm wird über die Dateien /etc/postfix/master.cf und /etc/postfix/main.cf konfiguriert. An der master.cf habe ich keinerlei Änderungen vorgenommen. Lediglich die main.cf habe ich nach meinen Anforderungen erweitert.
/etc/postfix/main.cf
# See /usr/share/postfix/main.cf.dist for a commented, more complete version # Debian specific: Specifying a file name will cause the first # line of that file to be used as the name. The Debian default # is /etc/mailname. #myorigin = /etc/mailname smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) biff = no # appending .domain is the MUA's job. append_dot_mydomain = no # Uncomment the next line to generate "delayed mail" warnings #delay_warning_time = 4h readme_directory = no # TLS parameters smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key smtpd_use_tls=yes smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache # See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for # information on enabling SSL in the smtp client. smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination myhostname = server3.netthelp.de alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases myorigin = /etc/mailname mydestination = $myhostname, server3.netthelp.de, h2656233.stratoserver.net, localhost.stratoserver.net, localhost relayhost = #mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = all inet_protocols = ipv4 content_filter = smtp-amavis:[localhost]:10024 policy-spf_time_limit = 3600s relay_domains = $mydestination, hash:/etc/postfix/relay #virtual_alias_domains = hash:/etc/postfix/virtual #virtual_alias_maps = hash:/etc/postfix/virtual, hash:/var/lib/mailman/data/virtual-mailman, 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_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 broken_sasl_auth_clients = yes smtpd_sasl_local_domain = smtpd_sasl_path = private/auth smtpd_sasl_security_options = noanonymous smtpd_sasl_type = dovecot smtpd_sasl_auth_enable = yes smtp_sasl_auth_enable = no smtp_sasl_security_options = smtp_sasl_password_maps = unknown_address_reject_code = 552 unknown_client_reject_code = 551 unknown_hostname_reject_code = 550 virtual_gid_maps = static:303 virtual_mailbox_base = /var/vmail/ virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf virtual_mailbox_limit = 0 virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf, proxy:mysql:/etc/postfix/mysql_virtual_alias_domain_mailbox_maps.cf virtual_minimum_uid = 303 virtual_transport = lmtp:unix:private/dovecot-lmtp virtual_uid_maps = static:303 #maps_rbl_reject_code = 451 #canonical_maps = hash:/etc/postfix/canonical #relocated_maps = hash:/etc/postfix/relocated #sender_canonical_maps = hash:/etc/postfix/sender_canonical #transport_maps = hash:/etc/postfix/transport #mail_spool_directory = /var/mail message_strip_characters = \0 defer_transports = mailbox_command = mailbox_transport = mailbox_size_limit = 0 message_size_limit = 0 strict_8bitmime = no strict_rfc821_envelopes = yes smtpd_delay_reject = yes smtpd_helo_required = yes 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.dnsb smtpd_helo_restrictions = permit_mynetworks, reject_invalid_hostname smtpd_sender_restrictions = hash:/etc/postfix/access, reject_unknown_sender_domain #smtpd_recipient_restrictions = , check_policy_service unix:private/policy-spf smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination # tls config # eingehende Verbindungen smtpd_use_tls = yes smtpd_enforce_tls = no # Obiges kann zusammengefasst werden zu smtpd_tls_security_level=may smtpd_tls_loglevel = 1 smtpd_tls_received_header = yes smtpd_tls_session_cache_timeout = 3600s smtpd_tls_mandatory_protocols=!SSLv2, !SSLv3 #tls_random_source = dev:/dev/urandom #tls_random_prng_update_period = 3600s # ausgehende Verbindungen smtp_use_tls = yes smtp_enforce_tls = no # Obiges kann zusammengefasst werden zu smtp_tls_security_level=may smtp_tls_note_starttls_offer = yes 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/server3.netthelp.de/privkey.pem #smtp_tls_cert_file = /etc/letsencrypt/live/server3.netthelp.de/fullchain.pem smtp_tls_loglevel = 1 smtp_tls_mandatory_protocols=!SSLv2, !SSLv3 # Limits - neu ab 17.1.17 gegen Spam 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
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.cf /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.
Für die Dateien kenne ich jeweisl zwei unterschiedliche Formulierungen, hier am Beispiel der mysql_virtual_domains_maps.cf
SuSE-Version
user = postfix password = password hosts = localhost #hosts = 127.0.0.1 dbname = postfix table = domain select_field = domain where_field = domain additional_conditions = and backupmx = '0' and active = '1'
Übliche Version.
user = postfix password = password hosts = localhost dbname = postfix query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
Man sieht, dass die SuSE-Version etwas erweitert wurde. Bei Ubuntu findet man jeweils die übliche Form.
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"
mailman
Mich hat überrascht, wie mühsam es ist eine Beschreibung zu finden, wie man mailman mit virtuellen Postfix-Mail verknüpft. Die hier beschriebene Konfiguration lässt einen Mailinglisten-Namen nur einmalig über alle Domains zu. Wenn es also eine Liste info@virtual1.tld gibt, dann ist es nicht möglich ebenfalls info@virtual2.tld einzurichten.
Weitere Informationen unter:
- http://list.org/mailman-install/postfix-virtual.html
- http://hilfedatenbank.de/2009/01/28/mailman-einrichten/
- http://www.gentoo.org/doc/de/virt-mail-howto.xml#doc_chap12
- https://wiki.archlinux.org/index.php/Mailman
Zuerst muss man den Mailman installieren, per
apt install mailman
dann muss man ihn in der Apache-Konfiguration aktivieren:
Zuerst muss man die Konfigurationsdatei kopieren:
cp /etc/mailman/apache.conf /etc/apache2/conf-available/mailman.conf
und dann aktivieren mittels:
a2enconf mailman
Danach den Apache neu starten.
service apache2 reload
Vor dem Neustart habe ich dann noch in jede vhost-Konfiguration die Zugriff auf Mailman bekommen soll die Zeilen
# Mailman-Pfade, ScriptAlias muss vor dem allgemeinen cgi-bin stehen ScriptAlias /cgi-bin/mailman/ /usr/lib/cgi-bin/mailman/ Alias /pipermail/ /var/lib/mailman/archives/public/ Alias /images/mailman/ /usr/share/images/mailman/ ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin/"
eingefügt. Wichtig ist, dass die drei neuen Zeilen vor der üblichen ScriptAlias-Zeile für cgi-bin stehen, sonst funktioniert der SriptAlias für Mailman nicht.
Eine Änderung erfolgt in der Datei /etc/postfix/main.cf dort muss die Zeile
alias_maps = hash:/etc/aliases
erweitert werden zu
alias_maps = hash:/etc/aliases, hash:/var/lib/mailman/data/aliases
damit die Alias-Einträge vom Mailman berücksichtigt werden. Zusätzlich muss für die virtuellen Domains der Eintrag virtual_alias_maps erweitert werden zu
virtual_alias_maps = hash:/etc/postfix/virtual, hash:/var/lib/mailman/data/virtual-mailman, 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
Außerdem habe ich in der master.cf die mailan-spezifischen Zeilen auskommentiert:
#mailman unix - n n - - pipe # flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py # ${nexthop} ${user}
Dahinter würde ein anderer Ansatz stecken.
Nun legt man das Site-Kennwort fest mit
/usr/lib/mailman/bin/mmsitepass
In der Datei /usr/lib/mailman/Mailman/mm_cfg.py finden sich einige Grundeinstellungen für den Mailman, die man mit einem Texteditor vornehmen kann, weitere Standardvorgaben findet man in der Datei /usr/lib/mailman/Mailman/Defaults.py.
Also ergänzen wir ein paar Zeilen in der Datei /usr/lib/mailman/Mailman/mm_cfg.py:
################################################## # Put YOUR site-specific settings below this line. DEFAULT_SERVER_LANGUAGE = 'de' DEFAULT_ARCHIVE = Off DEFAULT_ARCHIVE_PRIVATE = 1 SMTP_MAX_RCPTS = 500 DEFAULT_URL_HOST = 'myserver.tld' DEFAULT_EMAIL_HOST = 'myserver.tld' add_virtualhost('virtual1.tld', 'virtual1.tld') add_virtualhost('virtual2.tld', 'virtual2.tld') MTA = 'Postfix' POSTFIX_STYLE_VIRTUAL_DOMAINS = ['virtual1.tld', 'virtual2.tld'] DEFAULT_REQUIRE_EXPLICIT_DESTINATION = No
Jetzt legt man noch die notwendige Standard-Mailingliste "mailman" an mittels
/usr/lib/mailman/bin/newlist -l de mailman postmaster@myserver.tld passwort
Dann kann man den Dienst starten:
systemctl start mailman.service
und dann auch veranlassen, dass er zukünftig automatisch gestartet wird
systemctl enable mailman.service
Wichtig ist jetzt und beim Neuanlegen einer Mailingliste immer ein Blick in das Verzeichnis /var/lib/mailman/data, hier müssen vier Dateien mit aktuellem Zeitstempel auftauchen:
-rw-rw---- 1 root list 1843 Feb 19 15:35 aliases -rw-r----- 1 root list 12288 Feb 19 15:35 aliases.db -rw-rw---- 1 root list 1011 Feb 19 15:35 virtual-mailman -rw-r----- 1 root list 12288 Feb 19 15:35 virtual-mailman.db
Diese Dateien werden automatisch erzeugt vom Programm /usr/lib/mailman/bin/genaliases . Manchmal dauert es etwas, bis die Dateien auftauchen, man kann das Programm auch von Hand aufrufen.
Hinweis: Die Dateien virtual-mailman und virtual-mailman.db werden natürlich erst angelegt, wenn für eine virtuelle Domain eine Mailingliste erzeugt wird. Solange bis die Dateien existieren ist die Postfix-Konfiguration nicht in Ordnung: Das hat mich mal wieder etwas Zeit gekostet.
Hier einmal ein Inhalt der Datei virtual-mailman
# This file is generated by Mailman, and is kept in sync with the binary hash # file virtual-mailman.db. YOU SHOULD NOT MANUALLY EDIT THIS FILE unless you # know what you're doing, and can keep the two files properly in sync. If you # screw it up, you're on your own. # # Note that you should already have this virtual domain set up properly in # your Postfix installation. See README.POSTFIX for details. # LOOP ADDRESSES START mailman-loop@apachebuch.de mailman-loop # LOOP ADDRESSES END # STANZA START: test # CREATED: Sun Feb 19 15:35:19 2017 test@apachebuch.de test test-admin@apachebuch.de test-admin test-bounces@apachebuch.de test-bounces test-confirm@apachebuch.de test-confirm test-join@apachebuch.de test-join test-leave@apachebuch.de test-leave test-owner@apachebuch.de test-owner test-request@apachebuch.de test-request test-subscribe@apachebuch.de test-subscribe test-unsubscribe@apachebuch.de test-unsubscribe # STANZA END: test
Dazu gehört dann folgend aliases-Datei:
# This file is generated by Mailman, and is kept in sync with the # binary hash file aliases.db. YOU SHOULD NOT MANUALLY EDIT THIS FILE # unless you know what you're doing, and can keep the two files properly # in sync. If you screw it up, you're on your own. # The ultimate loop stopper address mailman-loop: /var/lib/mailman/data/owner-bounces.mbox # STANZA START: mailman # CREATED: Sun Feb 19 15:32:09 2017 mailman: "|/var/lib/mailman/mail/mailman post mailman" mailman-admin: "|/var/lib/mailman/mail/mailman admin mailman" mailman-bounces: "|/var/lib/mailman/mail/mailman bounces mailman" mailman-confirm: "|/var/lib/mailman/mail/mailman confirm mailman" mailman-join: "|/var/lib/mailman/mail/mailman join mailman" mailman-leave: "|/var/lib/mailman/mail/mailman leave mailman" mailman-owner: "|/var/lib/mailman/mail/mailman owner mailman" mailman-request: "|/var/lib/mailman/mail/mailman request mailman" mailman-subscribe: "|/var/lib/mailman/mail/mailman subscribe mailman" mailman-unsubscribe: "|/var/lib/mailman/mail/mailman unsubscribe mailman" # STANZA END: mailman # STANZA START: test # CREATED: Sun Feb 19 15:35:19 2017 test: "|/var/lib/mailman/mail/mailman post test" test-admin: "|/var/lib/mailman/mail/mailman admin test" test-bounces: "|/var/lib/mailman/mail/mailman bounces test" test-confirm: "|/var/lib/mailman/mail/mailman confirm test" test-join: "|/var/lib/mailman/mail/mailman join test" test-leave: "|/var/lib/mailman/mail/mailman leave test" test-owner: "|/var/lib/mailman/mail/mailman owner test" test-request: "|/var/lib/mailman/mail/mailman request test" test-subscribe: "|/var/lib/mailman/mail/mailman subscribe test" test-unsubscribe: "|/var/lib/mailman/mail/mailman unsubscribe test" # STANZA END: test
Die Dateien mit der Endung .db sind jeweils gehashte Versionen der Klartext-Dateien.
Will man eine neue Mailingliste erstellen, so ist das kein Problem, sofern es für die betreffende Domain schon eine Liste gibt. Dann kann man die einfach über http://server.tld/mailman/create anlegen. Wichtig ist aber, dass man anschließend noch einmal in die Konfiguration der Liste geht Allgemeine Optionen und dort unter Bevorzugter Hostname für E-Mail an diese Liste die zugehörige Domain angibt.
Gibt es für die Domain noch keine Mailingliste, so muss man darauf achten, dass die Domain per postfixadmin eingetragen ist, sonst nimmt das System keinerlei Mails für die Domain an. Dann mauss man in der Datei /usr/lib/mailman/Mailman/mm_cfg.py eine add_virtualhost() Zeile ergänzen und die Domain auch bei POSTFIX_STYLE_VIRTUAL_DOMAINS mit eintragen. Erst danach kann man dann die Liste sinnvoll anlegen.
Kontrollieren kann man noch, ob das Startscript legt die Datei /etc/cron.d/mailman anlegt. Beim Stoppen löscht es diese Datei auch wieder.
Nachtrag vom 1.6.2017
Bei letzten Übertragen von Mailman-Listen vom alten Server2 auf den neuen Server3 hatte ich das Problem, dass an manchen Stellen in Mails und Links plötztlich noch Server2 auftauchte. Ich habe lange verzeweifelt nach der Konfigurationsdatei gesucht.
Gefunden habe ich es dann in:
/var/lib/mailman/lists/<listenname>/config.pck
Hierbei handelt es sich wohl um eine gepackte Konfigurationsdatei. Ich habe hier einfach per Hand die URL korrigiert.
Nachträglich gefunden habe ich noch:
withlist -l -r fix_url <listname> -u mailman.yyy.com
setzt den host in web_page_url auf mailman.yyy.com and host_name auf xxx.com. (Habe ich dann ausprobiert, funktioniert einwandfrei.)
- https://www.gnu.org/software/mailman/site.html
- https://wiki.list.org/DOC/4.27%20Securing%20Mailman%27s%20web%20GUI%20by%20using%20Secure%20HTTP-SSL%20%28HTTPS%29
- https://wiki.list.org/DOC/4.62%20Why%20doesn%27t%20my%20public%20list%20appear%20on%20the%20listinfo%20overview%20page%3F%20aka%20Why%20can%27t%20I%20create%20a%20list%20from%20the%20web%3F
Zusätzlich hatte ich bei dem Ubuntu-System das Problem, dass alle System-Nachrichten auf Englisch waren, trotz entsprechender Konfiguration. Das ließ sich aber beseitigen:
cp -a /usr/share/mailman/de/ /etc/mailman/
vsftpd
Warum soll es immer nur bei SUSE mitgelieferte Probleme geben;-) Bei dem Ubuntu-System konnte ich die Quellen von pam_imap nicht compilieren und das mitgelieferte Modul pam_mysql ist leider defekt (https://bugs.launchpad.net/ubuntu/+source/pam-mysql/+bug/1574900). Beim Einsatz des Modules bekommt man Fehlermeldungen der Art
connected: PAM unable to dlopen(pam_mysql.so): /lib/security/pam_mysql.so: undefined symbol: make_scrambled_password connected: PAM adding faulty module: pam_mysql.so connected: pam_unix(vsftpd:auth): check pass; user unknown
Nach längerer Suche habe dafür eine einfache Lösung gefunden und zwar hier https://launchpad.net/~voronov84/+archive/ubuntu/andreyv Der Autor Andrey Voronov hat eine funktionsfähige Version des Moduls erstellt, die einfach nur anstatt der mitgelieferten Version installiert werden muss:
add-apt-repository ppa:voronov84/andreyv apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 12946919 apt update apt list --upgradable apt upgrade
Unter den aktualisierbaren Paketen sollte auch libpam_mysql vorhanden sein und beim upgrade aktualisiert werden, wenn es bereits installiert war, sonst mit
apt install libpam-mysql
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 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
fail2ban
Bei fail2ban handelt es sich um ein nützliches Tool, welches bestimmte Logdateien verfolgt und IP-Adressen blockt, die hier häufiger mit unerwünschten Zugriffen auftauchen. Diese IP-Adressen werden dann eine gewisse Zeit mittels Iptables-Regeln blockiert. Das Tool ist sehr konfigurierbar und nahezu beliebig erweiterbar, zumindest wenn man sich mit regulären Ausdrücken auskennt.
Installiert und gestartet wird das Tool mittels:
apt install fail2ban
Die Konfiguration befindet sich im Verzeichnis /etc/fail2ban
Hier findet sich für jeden zu überwachenden Dienst nein Bereich wie:
[sshd] port = ssh logpath = %(sshd_log)s
Hier wird festgelegt, welcher Port eine Rolle spielt und welche Logdateien. Die Konfiguration ist so aber noch nicht vollständig. Weiter oben in der Datei finden sich einige Vorgaben, die hier auch überschrieben werden könnten.
# "bantime" is the number of seconds that a host is banned. bantime = 600 # A host is banned if it has generated "maxretry" during the last "findtime" seconds. findtime = 600 # "maxretry" is the number of failures before a host get banned. maxretry = 5
und vor allem
# "enabled" enables the jails. # By default all jails are disabled, and it should stay this way. # Enable only relevant to your setup jails in your .local or jail.d/*.conf # # true: jail will be enabled and log files will get monitored for changes # false: jail is not enabled enabled = false
Durch diese Vorgabe wird kein einzige Jail gestartet. Änderungen nimmt man nicht hier vor, sondern in der Datei jail.d/defaults-debian.conf. Bei der Auslieferung hat diese Datei folgenden Inhalt:
[sshd] enabled = true
Somit wird das Jail sshd gestartet. Wie genau es arbeitet wird über die Datei filter.d/sshd.conf festgelegt. Ihr Inhalt besteht aus einer Reihe von regulären Ausdrücken, die die Konfigurationsdatei untersuchen.
Die jail.d/defaults-debian.conf hat bei mir folgenden Inhalt:
[sshd] enabled = true [apache-badbots] enabled = true [vsftpd] enabled = true [postfix] enabled = true [postfix-rbl] enabled = true [dovecot] enabled = true
Blacklist mit fail2ban
Auf eine interessante Anwendung von fail2ban hat mit Lukas Thiel aufmerksam gemacht. Man kann damit eine Sperrliste für IP-Adressen aufbauen.
Dazu ergänzt man die jail.d/defaults-debian.conf am Ende um folgende Zeilen:
[ip-blacklist] enabled = true action = iptables-allports[name=ip-blacklist] filter = ip-blacklist logpath = /etc/fail2ban/ip.blacklist maxretry = 0 findtime = 15552000 bantime = -1
Nun noch den Filter definieren mit filter.d/ip-blacklist.conf
[Definition] # Option: failregex # Notes : Detection of blocked ip addresses. # Values: TEXT # failregex = ^<HOST> \[.*\]$ # Option: ignoreregex # Notes : Regex to ignore. # Values: TEXT # ignoreregex =
Jetzt kann man IP-Adressen blocken über die Datei ip.blacklist:
192.168.84.188 [31/03/2018 16:34:05] 192.168.169.190 [16/04/2018 19:49:00]
Die Einträge bestehen jeweils aus einer Zeile, vorn die IP-Adresse, dahinter eine Zeitangabe für den Eintrag. Damit kann die Gültigkeit der Sperre begrenzt werden. Angegeben ist ja als findtime 15552000 Sekunden, was etwa einem halben Jahr entspricht.
Überprüfen kann man die Funktions mittls:
fail2ban-client status ip-blacklist
das ergibt eine Ausgabe wie:
Status for the jail: ip-blacklist |- Filter | |- Currently failed: 0 | |- Total failed: 2 | `- File list: /etc/fail2ban/ip.blacklist `- Actions |- Currently banned: 2 |- Total banned: 2 `- Banned IP list: 192.168.84.188 192.168.169.190
Mehr dazu
Unter https://sven.rojek.de/posts/fail2ban-iprange-mit-blackliste-blocken habe ich jetzt eine interessante Version gefunden, die auch das Blockieren von Netzblöcken zulässt.
Auch bei dieser Version habe ich den Effekt, dass gelegentlich Teile der IP-Adresse nicht berücksichtigt werden. Dadurch entstehen dann ganz andere Bereiche, die geblockt werden.
Geblockte Adressen kann man folgendermaßen per Hand freigeben:
fail2ban-client set ip-blacklist unbanip 116.255.167.53
entsprechend kann man sie mit banip auch von Hand blocken.
Ich hatte aber auch schon das Problem, dass sich fälschlich geblockte IP-Adressen nicht wieder löschen ließen. Hier hilft ein Neustart von fail2ban nicht weiter. Beim Stoppen werden zwar alle Blockaden entfernt, das Programm restauriert sie aber beim Neustart.
Die Datenbank mit diesen Einstellungen habe ich im Verzeichnis /var/lib/fal2ban gefunden. Dort gibt es die Datei fail2ban.sqlite3 mit den internen Daten. Ein Löschen dieser Datei führt dazu, dass beim Neustart von fail2ban keine Blockaden vorhanden sind. Die Datei ip-blacklist muss man nach dem Neustart einmal verändern, damit die Adressen neu eingelesen werden.
Ich meine, dass die erste Filterdatei filter ip-blacklist.conf nicht ganz korrekt ist, es fehlen die Leerzeichen nach der IP-Adresse (vor dem .*), dadurch ist das [^/] wirkungslos. Hinter dem [^/] muss auch ein Leerzeichen stehen, sonst werden auch für alle größeren Netzwerkblöcke zusätzlich /32er Regeln erzeugt. Generell sollte man daher zwischen IP-Adresse und Datumsbereich immer mindestens zwei Leerzeichen stehen haben.
[Definition] # Option: failregex # Notes : Detection of blocked ip addresses. # Values: TEXT # failregex = ^<HOST>(/32 .*|[^/] .*)?$ # Option: ignoreregex # Notes : Regex to ignore. # Values: TEXT # ignoreregex =
Konsequenterweise sollte man das Leerzeichen wohl in allen der Filter setzen.
Die Funktion eines Filter kann man prüfen mit
fail2ban-regex ip-blacklist "^<HOST>(/32 .*|[^/] .*)?$"
bzw.
fail2ban-regex "10.10.10.10 [2018-09-18 16:16:00]" "^<HOST>(/32 .*|[^/] .*)?$"
Übrigens, bei dem Datumsformat ist fail2ban relativ flexibel, da sind mehrere Versionen hinterlegt. Die hier benutzen regulären Ausdrücke benötigen z.B. die eckigen Klammern um das Datum nicht.
Es geht (u.a.):
fail2ban-regex "10.10.10.10 19-09-2018 16:16:00" "^<HOST>(/32 .*|[^/] .*)?$" fail2ban-regex "10.10.10.10 [19-09-2018 16:16:00]" "^<HOST>(/32 .*|[^/] .*)?$" fail2ban-regex "10.10.10.10 19/09/2018 16:16:00" "^<HOST>(/32 .*|[^/] .*)?$" fail2ban-regex "10.10.10.10 [2018-09-19 16:16:00]" "^<HOST>(/32 .*|[^/] .*)?$" fail2ban-regex "10.10.10.10 [Sep 19 16:16:00]" "^<HOST>(/32 .*|[^/] .*)?$" fail2ban-regex "10.10.10.10 [19/Sep/2018:16:16:00]" "^<HOST>(/32 .*|[^/] .*)?$"
Überarbeitete Lösung für IP-Blacklisten mit fail2ban
Die folgende Beschreibung baut auf dem Text unter https://sven.rojek.de/posts/fail2ban-iprange-mit-blackliste-blocken auf. Leider ist auf der Seite keine Kontaktmöglichkeit angegeben um Änderungsvorschläge zu machen. Auch finden sich dort für meinen Geschmack zu wenig Erläuterungen.
Die Sperrliste
Die Datei /etc/failban/ip-blacklist beinhaltet zeilenweise die IP-Adressen bzw. Bereich und den zugehörigen Zeitstempel.
######################################## # # Single IP Example: # 10.10.10.10 [2015/01/01 12:00:00] # 10.10.10.10/32 [2015-0101 12:00:00] # ######################################### # # IP Range Options: # 10.10.10.10/24 = 10.10.10.* # 10.10.10.10/16 = 10.10.*.* # 10.10.10.10/8 = 10.*.*.* # ######################################### # # IP Range Examples: # 10.10.10.10/16 [2015-01-01 12:00:00] # 10.10.10.10/24 [2015-01-01 12:00:00] # ######################################### 10.2.245.209 [21/09/2018 16:01:00] 10.214.206.13/24 [21/09/2018 15:33:00]
Hier eine einzelne IP-Adresse und ein 24-er Block mit 256 Ip-Adressen. Zwischen der IP-Adresse und dem Zeitstempel müssen mindestens zwei Leerzeichen liegen. Es bietet sich an, alle Zeitstempel in Form einer Tabelle anzuordnen, damit man Tippfehler leichter erkennt. Gegenüber Fehlern in dem Zeitstempel (aber auch der IP-Adresse) ist fail2ban empfindlich.
Als Zeitstempel kommt alles in Frage, was fail2ban akzeptiert z.B.
[19-09-2018 16:16:00] [2018-09-19 16:16:00] [Sep 19 16:16:00] [19/Sep/2018:16:16:00]
Die Konfigurationsdatei jail.local
Die Datei /etc/fail2ban/jail.local ist in der Standardinstallation von Ubuntu nicht vorhanden, kann also risikolos angelegt werden. Sie beinhaltet die Hauptkonfiguration für die flexible Blacklist.
[ip-blacklist] enabled = true port = anyport action = action_ip-blacklist filter = filter_ip-blacklist logpath = /etc/fail2ban/ip-blacklist maxretry = 0 findtime = 15552000 bantime = -1 [ip-blacklist24] enabled = true port = anyport action = action_ip-blacklist[mask=24] filter = filter_ip-blacklist24 logpath = /etc/fail2ban/ip-blacklist maxretry = 0 findtime = 15552000 bantime = -1 [ip-blacklist16] enabled = true port = anyport action = action_ip-blacklist[mask=16] filter = filter_ip-blacklist16 logpath = /etc/fail2ban/ip-blacklist maxretry = 0 findtime = 15552000 bantime = -1 [ip-blacklist8] enabled = true port = anyport action = action_ip-blacklist[mask=8] filter = filter_ip-blacklist8 logpath = /etc/fail2ban/ip-blacklist maxretry = 0 findtime = 15552000 bantime = -1
Die Datei definiert vier Regeln, für jede der vier Netzwerkklassen eine.
- Alle Regeln sind aktiviert (enabled=true),
- die Blockade betrifft alle Ports (port=anyport) ,
- als Action wird action_ip-blacklist aufgerufen, die entsprechende Datei findet sich in /etc/fail2ban/action.d und bekommt den Parameter mask übergeben
- als Filter dient die Datei filter_ip-blacklistnn aus dem Verzeichnis /etc/fail2ban/filter.d
- die Quelle für das Sperren ist die Datei /etc/fail2ban/ip-blacklist
- es gibt beliebig viele Versuche (maxretry=0)
- der Zeitstempel darf maximal 180 Tage zurückliegen (findtime=15552000)
- der Ban wird nie aufgehoben (bantime=-1)
Die Datei action_ip-blacklist.conf mit den Aktionen
Die Datei /etc/fail2ban/action.d/action_ip-blacklist.conf beschreibt, was zu tun ist z.B. beim Sperren einer IP-Adresse. Dieses Tool basiert sehr stark auf Iptables. Sie ähnelt der Datei iptables-common.conf, die von vielen anderen Jails aufgerufen wird.
[Definition] # Option: actionstart # Notes.: command executed once at the start of Fail2Ban. # Values: CMD # actionstart = iptables -N fail2ban-<name> iptables -A fail2ban-<name> -j RETURN iptables -I <chain> -p <protocol> -j fail2ban-<name> # Option: actionstop # Notes.: command executed once at the end of Fail2Ban # Values: CMD # actionstop = iptables -D <chain> -p <protocol> -j fail2ban-<name> iptables -F fail2ban-<name> iptables -X fail2ban-<name> # Option: actioncheck # Notes.: command executed once before each actionban command # Values: CMD # actioncheck = iptables -n -L <chain> | grep -q fail2ban-<name> # Option: actionban # Notes.: command executed when banning an IP. Take care that the # command is executed with Fail2Ban user rights. # Tags: <ip> IP address # <failures> number of failures #
Im Bereich Init werden einige Variable angelegt, die im oberen Bereich auch benutzt werden. Die Variablen können über Parameter beim Aufruf überschrieben werden.
- (name = default) legt den Bezeichner für die eigene Chain fest, wird zu fail2ban-default
- (protocol=all) es werden immer alle Ports blockiert
- (chain=INPUT) die eigene Chain hängt sich in die Standard-Chain INPUT ein
- (mask=32) wenn kein Parameter mask übergeben wird, dann gilt 32 als Standard-Maske
Im Bereich Definition werden die Aktionen festgelegt:
- actionstart greift beim Start von fail2ban. Hier wird die eigene Chain (fail2ban-default) angelegt. Hier gibt es einen kleinen Schönheitsfehler, das wir vier Jails mit dem gleichen Namen anlegen wird auch die eigene Chain viermal angelegt. Alle IP-Blockaden arbeiten aber immer mit der ersten Chain (aufgrund des gleichen Namens).
- actionstop beseitigt die eigene Chain und die darin noch vorhandenen Regeln
- actioncheck testet vor dem Bannen, ob es die eigene Chain gibt
- actionban blockiert die IP-Adresse bze. den IP-Bereich mittels Iptables. Als Aktion ist hier DROP angegeben und nicht wie sonst REJECT, der Bösewicht bekommt also keine Rückmeldung
- actionunban hebt die Sperre für eine IP-Adresse bzw. einen IP-Block wieder auf.
Die Filterdateien
Im Verzeichnis /etc/fail2ban/filter.d/ finden sich die vier Filterdateien
- filter_ip-blacklist24.conf
- filter_ip-blacklist16.conf
- filter_ip-blacklist8.conf
- filter_ip-blacklist.conf
Die ersten drei ähneln sich sehr, hier ist nur die Netzwerkmaske zu berücksichtigen:
[Definition]
# Option: failregex # Notes : Detection of blocked ip addresses. # Values: TEXT # failregex = ^<HOST>/24 .*$ # Option: ignoreregex # Notes : Regex to ignore. # Values: TEXT # ignoreregex =
In der Zeile failregex wird das Muster festgelegt, das von fail2ban erwartet werden soll, hier:
^<HOST>/24 .*$
Dieses Muster besagt, dass am Anfang der Zeile (das ^ sagt am Anfang) eine IP-Adresse stehen soll. <HOST> ist so etwas wie ein fail2ban Makro, ein komplizierterer regulärer Ausdruck, der hier nur benutzt wird. Danach folgt die Netzwerkmaske und darauf ein Leerzeichen. Hinter dem Leerzeichen folgen beliebig (*) viele beliebige Zeichen (.) bis zum Ende der Zeile ($). Im diesem Teil sucht fail2ban dann einen Zeitstempel.
Lediglich die vierte Datei weicht etwas ab, da die 32 Maske gesetzt werden kann, oder auch nicht.
[Definition] # Option: failregex # Notes : Detection of blocked ip addresses. # Values: TEXT # failregex = ^<HOST>(/32 .*|[^/] .*)?$ # Option: ignoreregex # Notes : Regex to ignore. # Values: TEXT # ignoreregex =
Der Ausdruck beginnt wieder mit der IP-Adresse. Innerhalb der runden Klammer stehen zwei Möglichkeiten zur Wahl (getrennt durch |).
- Die erste Möglichkeit ist Netzwerkmaske 32, ein Leerzeichen und beliebig viele beliebige Zeichen
- Die zweite Möglichkeit, kein Schrägstrich ([^/]), dann ein Leerzeichen und dann beliebig viele beliebige Zeichen. Das Fragezeichen vor dem $ regelt die Gefräßigkeit der Regeln.
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 und http://kilobyte.bplaced.net/ubuntu-automatische-aktualisierung-aktivieren-ein-appell/
Alle Dienste
Der Aufruf von
service --status-all
liefert die folgende Ausgabe (insgesamt 61 Zeilen)
[ + ] amavis [ + ] amavis-mc [ + ] amavisd-snmp-subagent [ + ] apache-htcacheclean [ + ] apache2 [ + ] apparmor [ - ] bootmisc.sh [ - ] checkfs.sh [ - ] checkroot-bootclean.sh [ - ] checkroot.sh [ + ] clamav-daemon [ + ] clamav-freshclam [ - ] console-setup [ + ] cron [ + ] dbus [ + ] dovecot [ + ] fail2ban [ + ] grub-common [ - ] hostname.sh [ - ] hwclock.sh [ + ] irqbalance [ + ] iscsid [ + ] keyboard-setup [ - ] killprocs [ + ] kmod [ + ] mailman [ + ] mdadm [ - ] mdadm-waitidle [ - ] mountall-bootclean.sh [ - ] mountall.sh [ - ] mountdevsubfs.sh [ - ] mountkernfs.sh [ - ] mountnfs-bootclean.sh [ - ] mountnfs.sh [ + ] mysql [ - ] networking [ + ] ntp [ + ] ondemand [ + ] open-iscsi [ - ] plymouth [ - ] plymouth-log [ + ] postfix [ + ] procps [ + ] rc.local [ + ] resolvconf [ - ] rsync [ + ] rsyslog [ - ] sendsigs [ + ] smartmontools [ + ] spamass-milter [ + ] spamassassin [ + ] ssh [ + ] udev [ + ] ufw [ - ] umountfs [ - ] umountnfs.sh [ - ] umountroot [ + ] unattended-upgrades [ + ] urandom [ - ] uuidd [ + ] vsftpd [ - ] x11-common
Erfahrungen
Typo3 6.2 scheint zu laufen. Es gab nur eine Reihe von Warnungen der Art:
[Mon Feb 20 13:00:32.243132 2017] [:error] [pid 28367] [client 141.91.210.10:53370] PHP Warning: Declaration of TYPO3\\CMS\\Core\\Package \\FailsafePackageManager::registerPackagesFromConfiguration() should be compatible with TYPO3\\CMS\\Core\\Package\\PackageManager::registerPackagesFromConfiguration($registerOnlyNewPackages = false) in /srv/www/typo3src/typo3_src-6.2.30/typo3/sysext/core/Classes/Package/FailsafePackageManager.php on line 24, referer: http://gi-hill.server3.netthelp.de/typo3/sysext/install/Start/Install.php?install[action]=configuration&install[context]=standalone&install[controller]=tool
Dazu habe ich folgende Anleitung unter http://stackoverflow.com/questions/35804678/typo3-ver-6-2-error-at-installation gefunden:
This also happend to me when using Typo3 6.2LTS with php7. I fixed it in file typo3\sysext\core\Classes\Package\FailsafePackageManager.php line 66: before protected function registerPackagesFromConfiguration() { after: protected function registerPackagesFromConfiguration($registerOnlyNewPackages = false) {
phpmyadmin
Die Software nervte gelegentlich (warum eigentlich nicht immer) mit einer Reihe von Fehlermeldungen der Art:
phpmyadmin Deprecation Notice in ./../php/php-gettext/streams.php#48
Das Problem lässt sich lösen, indem man in das Verzeichnis
/usr/share/php/php-gettext
wechselt und dort die Dateien gettext.php und streams.php bearbeitet. Bei den Konstruktoren muss jeweils der Klassenname durch __construct ersetzt werden.
Aus
/** * Constructor * * @param object Reader the StreamReader object * @param boolean enable_cache Enable or disable caching of strings (default on) */ function gettext_reader($Reader, $enable_cache = true) { // If there isn't a StreamReader, turn on short circuit mode.
wird dann
/** * Constructor * * @param object Reader the StreamReader object * @param boolean enable_cache Enable or disable caching of strings (default on) */ function __construct($Reader, $enable_cache = true) { // If there isn't a StreamReader, turn on short circuit mode.
Fortsetzung folgt