Hetzner-Server mit Ubuntu 20.04

Aus Debacher-Wiki
Wechseln zu:Navigation, Suche

Neuer Hetzner-Server

Nach meiner Einschätzung hat mein bisheriger Hetzner-Server ein Festplattenproblem. Zumindest synchroniosert sich das Raid ziemlich oft und Smartctl liefert Fehler

SMART Attributes Data Structure revision number: 10
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE
  1 Raw_Read_Error_Rate     0x000f   116   099   006    Pre-fail  Always       -       101230976
  3 Spin_Up_Time            0x0003   095   094   000    Pre-fail  Always       -       0
  4 Start_Stop_Count        0x0032   100   100   020    Old_age   Always       -       16
  5 Reallocated_Sector_Ct   0x0033   100   100   010    Pre-fail  Always       -       0
  7 Seek_Error_Rate         0x000f   089   060   030    Pre-fail  Always       -       839780273
  9 Power_On_Hours          0x0032   062   062   000    Old_age   Always       -       33544
 10 Spin_Retry_Count        0x0013   100   100   097    Pre-fail  Always       -       0
 12 Power_Cycle_Count       0x0032   100   100   020    Old_age   Always       -       16
 ...


Als ich das Problem vor einiger Zeit beim Hetzner-Support gemeldet habe bin ich leider nicht weiter gekommen, da die Platte ansonsten keine Fehler meldet. Aktuelle steht aber eine Aktualisierung des Betriebssystems an, Ubuntu 16.04 bietet eine zu alte PHP-Version. Die Mühe mit der Aktualisierung wollte ich mir aber nicht mit einer defekte Festplatte antun. Also habe ich heute einen neuen Hetzner-Server geordert, auch wenn er mit 27€ etwas teurer ist als der bisherige Server. Dafür habe ich darauf geachtet, dass der Server über Enterprise HDs verfügt. Hoffentlich ist hier die Haltbarkeit höher.

Das Gerät verfügt über folgende Harware:

  • Prozessor Intel Core i7-4770 CPU @ 3.40GHz (CPU-B 7048)
  • dazu Festplatten 2x2 TB Ent. HDD und
  • 32 GB Hauptspeicher.
  • 8 x 6799.56 Bogomips

Nach der Bestellung hat es nicht einmal eine halbe Stunde gedauert, bis der Server zur Grundinstallation im Rettungssystem zur Verfügung stand.

Festplatten-Tausch

Leider musste ich feststellen, dass auch diese Platten nicht in Ordnung sind, ich werde also erst einmal keine Installation vornehmen. Wenn der Support wieder sagt, dass alles in Ordnung ist, dann werde ich den Server zurückgeben. Platte /dev/sda hat eine hohe Rate an Raw_Read_Error_Rate, das ist aber bei manchen Platten wohl Ok, wenn der Wert mit Hardware_ECC_Recovered übereinstimmt. Die Platte /dev/sdb hat aber einen Reallocated_Sector_Ct von 17, nach meiner Kenntnis muss man dann zeitnah mit einem Ausfall der Platte rechnen. Mal sehen, wie gut der Service von Hetzner ist.

Ergebnis: Der Service ist gut. Mein Problem mit dem Server trat am Samstag auf und war je kein Notfall. Am Montag um 08.39 Uhr hatte ich eine Antwort vom Support. Das Angebot war die Platte mit den defekten Sektoren auszuwechseln. Dazu musste ich mein Einverständnis erklären, dass der Server heruntergefahren wird. Eine halbe Stunde danach kam die Mitteilung, dass die Platte gewechselt ist.

/dev/sda 56173 Stunden (etwas mehr als 6 Jahre) bei 27 Start/Stopps (Seagate Constellation ES.3, ST2000NM0033-9ZM175)
/dev/sdb 43372 Stunden (knapp 5 Jahre) bei 15 Start/Stopps (Hitachi/HGST Ultrastar 7K4000, HGST HUS724020ALA640)

Natürlich war die Platte nicht ins System eingebunden, so war unpartitioniert. Ich fand es dann einfacher die gesamte Installation neu zu starten. Dazu muss man im Hetzner-Robot für diesen Server die Funktion Rescue aktivieren. Das ging erst einmal nicht, das System beschwerte sich, dass VNC aktiviert wäre. Nachdem ich das deaktiviert hatte, konnte ich das Rescue-System starten.

Danach konnte ich dann wieder die ganz normale Erstinstallation nach dem Hetzner-System durchgehen.

Grundinstallation

Startet man im Rescue-System das Programm installimage, so muss man zuerst das Betriebssystem auswählen, welches man installieren möchte. Ich habe mich für Ubuntu 20.04 entschieden. Nach dieser Auswahl landet man in einem Editor, indem man vor allem die Partitionierung der Festplatten festlegt. Die vorgegebene Datei ist gut dokumentiert, so dass hier eigentlich keine Probleme auftauchen sollten. Ich habe mich für folgende Aufteilung entschieden:

/dev/md1    1G /boot
/dev/md2   50G /
/dev/md3    5G /tmp
/dev/md4  800G /var
/dev/md5  600G /home
/dev/md6  380G /data (der gesamte Rest)

Schwierig kann es sein den Editor ordnungsgemäß zu verlassen. Die Funktionstaste F10 wirkt bei mir nicht auf den Hetzner-Editor, sondern auf das Terminal. Hetzner schlägt im Wiki vor ESC und dann 0 zu drücken.

Im nächsten Schritt dann

apt update
apt upgrade

Am Ende des Upgrade-Prozesses tauchen Fenster auf mit Fragen, die beantwortet werden müssen. Bei der Frage nach der Aktualisierung der OpenSSH-Konfiguration habe ich micht für das belassen der vorhandenen Version entschieden. Schwieriger war die Grag zu GRUB:

Fortsetzen ohne Installation von GRUB yes/no? Bei no kam das Fenster immer wieder, man muss also yes antworten.

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, wenn man beim Start der Verbindung den Parameter -X mit angibt:

ssh -X root@mein-server.domain

Da ich schon häufiger Probleme mit den Festplatten hatte, sind mir die Smartmontools wichtig:

apt install smartmontools

Der Aufruf von

smartctl -A /dev/sda

bzw.

smartctl -A /dev/sdb

Liefert mir die Information, dass die Festplatten schon viele Stunden gelaufen sind.

Im Netzwerk benötigt man dann oft auch whois Informationen

apt install whois

Dann noch die Firewall

apt install ufw
ufw allow OpenSSH
ufw enable

Danach habe ich dann einen Reboot veranlasst.

Die Spracheinstellungen anpassen

update-locale LANG=de_DE.UTF-8

Danach neu anmelden, um den Effekt zu sehen.

~ # locale 
LANG=de_DE.UTF-8
LANGUAGE=
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_COLLATE="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_MESSAGES="de_DE.UTF-8"
LC_PAPER="de_DE.UTF-8"
LC_NAME="de_DE.UTF-8"
LC_ADDRESS="de_DE.UTF-8"
LC_TELEPHONE="de_DE.UTF-8"
LC_MEASUREMENT="de_DE.UTF-8"
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=

Noch ein paar zusätzliche Pakete:

apt install bind9-host whois nmap lsof man-db
apt-get install arj bzip2 cabextract cpio file gzip nomarch pax rar unrar unzip zip zoo lhasa p7zip ssl-cert lrzip lzop rpm2cpio unrar-free p7zip p7zip-rar

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
mkdir /var/www/htdocs
mkdir /var/www/htdocs/dummy

Webserver

Viele Apache-Anwendungen benötigen eine Datenbank. Deshalb im ersten Schritt die Installation von MySQL.

Datenbank-MySQL

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.


MySQL-Passwort

In aktuellen Datenbank-Versionen hat der Benutzer root keinen Zugriff mittels Passwort und kann daher z.B. auch nicht per phpmyadmin arbeiten. Der folgende MySQL-Befehl zeigt die Einstellung

mysql> SELECT user,authentication_string,plugin,host FROM mysql.user;
+---------------------+-------------------------------------------+-----------------------+-----------+
| user                | authentication_string                     | plugin                | host      |
+---------------------+-------------------------------------------+-----------------------+-----------+
| root                |                                           | auth_socket           | localhost |
| mysql.session       | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
| mysql.sys           | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
...

Ändern lässt sich diese Einstellung mittels:

use mysql;
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
flush privileges;

Dann ergibt sich:

mysql> select user,authentication_string,plugin,host FROM mysql.user;
+---------------------+-------------------------------------------+-----------------------+-----------+
| user                | authentication_string                     | plugin                | host      |
+---------------------+-------------------------------------------+-----------------------+-----------+
| root                | *A9172BC315E0BF4D14D201C4CD16374ED187B2B3 | mysql_native_password | localhost |
| mysql.session       | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
| mysql.sys           | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |


Damit ist das Passwort gesetzt. Will man es später einmal ändern, so muss man berücksichtigen, dass sich das Passwort für MySQL nicht mehr mit den altbekannten Kommandos setzen lässt, weil das Passwort nicht mehr im Feld password, sondern im Feld authentication_string zu finden ist:

use mysql;
UPDATE user SET authentication_string= password('password') WHERE User = 'root';
flush privileges;

Siehe auch https://stackoverflow.com/questions/30692812/mysql-user-db-does-not-have-password-columns-installing-mysql-on-osx

und

https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-20-04-de

Nachdem das Passwort gesetzt ist, kann sich der Benutzer root auch per phpmyadmin anmelden.

MySQL im Zusammenspiel mit phpmyadmin

Eine etwas einfachere Lösung das Passwort-Problem zu lösen gibt es, wenn mit phpmyadmin gearbeitet wird. In der Datei /etc/mysql/debian.cnf sind die Zugangsdaten für einen bei der Installation angelegten User zu finden:

# Automatically generated for Debian scripts. DO NOT TOUCH!
[client]
host     = localhost
user     = debian-sys-maint
password = BmhrjzFR0D0521NX
socket   = /var/run/mysqld/mysqld.sock
[mysql_upgrade]
host     = localhost
user     = debian-sys-maint
password = BmhrjzFR01D021NX
socket   = /var/run/mysqld/mysqld.sock


Mit dem hier befindlichen Benutzer und dem hier befindlichen zufällig generiertem Passwort kann man per phpmyadmin auf die Datenbank zugreifen. Hier kann man dann bequem einen Benutzer mit allen gewünschten Rechten anlegen.


Apache

Die folgenden grundlegenden Pakete habe ich installiert

apt install apache2 apache2-bin apache2-data apache2-doc apache2-utils		

Dann ein paar Pakete für PHP

apt install libapache2-mod-php  php php-auth-sasl php-bz2 php-cli php-db php-gd php-geoip php-imap php-log php-mail php-curl php-imagick php-intl
apt install php-mbstring php-mdb2 php-mysql php-net-smtp php-phpseclib php-soap php-tcpdf php7.2-zip phpmyadmin 

Da sind eventuell noch Doppelungen drin, sowohl das Paket, als auch das Metapaket. Es ist aber das, was mir

dpkg --get-selections | grep php

lieferte.

Nicht vorhanden waren die Pakete php-gettext und php-recode, die Ursache muss ich noch recherchieren.

Nun noch ein paar Perl-Pakete:

apt install libapache2-mod-perl2 libapache2-reload-perl libapparmor-perl libarchive-zip-perl libauthen-sasl-perl libbsd-resource-perl libcairo-perl
apt install libcgi-fast-perl libfile-basedir-perl libfile-desktopentry-perl libfile-mimeinfo-perl libfont-afm-perl libgd-graph-perl libglib-perl libgtk2-perl
apt install libhtml-form-perl libhtml-format-perl libhtml-template-perl libhttp-daemon-perl libimage-magick-perl libmailtools-perl libnet-dbus-perl libtie-ixhash-perl
apt install libx11-protocol-perl libxml-xpathengine-perl libdbi-perl libdbd-mysql libclass-dbi-mysql-perl

Nach erfolgter Konfiguration (s.u.) darf man nicht vergessen die notwendigen Ports in der Firewall frei zu geben:

ufw allow "Apache Full"

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

für Typo3

Da ich viel mit Typo3 arbeite habe ich etwas an den PHP-Einstellungen gedreht in der /etc/php/7.4/apache2/php.ini:

post_max_size=12M
upload_max_filesize=12M
max_execution_time=240
max_input_vars = 1500

Typo3 benötigt unbedingt imagemagick (oder alternativ graphicsmagick)

apt install imagemagick imagemagick-doc
apt install graphicsmagick ghostscript webalizer

/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, liegt im Paket ssl-cert.

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
a2enmod ssl
service apache2 restart


NextCloud Update

Auf dem bisherigen Server war Nextcloud 15.0.x die höchste Version, danach war die PHP-Version nicht mehr für eine Aktualisierung geeignet. Auf dem neuen Server läuft php7.4, was erst mit NextCloud 18.x.y unterstützt wird. Ein Update ohne Fehlermeldungen ist also nicht möglich.

Es gibt aber einen einfachen Trick mittels:

joe lib/versioncheck.php

wird die Versionsnummer manipuliert. Wenn man dort als Grenze 7.5 einsetzt, dann läuft das Update mittels

sudo -u www-data php occ upgrade

durch.

Ich hatte dann im Frontend bei Version 16.0.11 die Fehlermeldung

Das Setzen der Umgebungslokale auf en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8 ist fehlgeschlagen

Das lässt sich lösen mittels

joe /etc/apache2/envvars

Hier in Zeile 28 das Kommentarzeichen entfernen

## Uncomment the following line to use the system default locale instead:
. /etc/default/locale

und den Apache neu starten.


Mediawiki-Uodate

Bei mediawiki 1.31.8 tauchten PHP-Warnungen in der Logdatei auf, unter PHP7.4:

PHP Notice:  Trying to access array offset on value of type null in /var/www/vhosts/debacher.de/httpdocs/uwiki/includes/profiler/SectionProfiler.php on line xx

Wobei xx=99, 100 bzw. 101

Der Patch dazu ist relativ einfach, es werden einfach die drei Zeilen ersetzt:

	#	$totalCpu = max( $this->end['cpu'] - $this->start['cpu'], 0 );
	#	$totalReal = max( $this->end['real'] - $this->start['real'], 0 );
	#	$totalMem = max( $this->end['memory'] - $this->start['memory'], 0 );
		if ( is_array( $this->start ) ) {
			$totalCpu = max( $this->end['cpu'] - $this->start['cpu'], 0 );
			$totalReal = max( $this->end['real'] - $this->start['real'], 0 );
			$totalMem = max( $this->end['memory'] - $this->start['memory'], 0 );
		} else {
			$totalCpu = 0;
			$totalReal = 0;
			$totalMem = 0;
		}


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

Mailsystem.png

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 postfixadmin dovecot-antispam spamass-milter roundcube roundcube-plugins roundcube-plugins-extra mailutils
apt install dovecot-lmtpd dovecot-managesieved dovecot-mysql dovecot-pop3d dovecot-sqlite clamv clamav-daemon   


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 3.2 vor.

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 über http://<server>/postfixadmin/setup.php an, bzw. aktualisiert sie beim Aufruf der Seite).

CREATE TABLE `admin` (
 `username` varchar(255) NOT NULL,
 `password` varchar(255) NOT NULL,
 `superadmin` tinyint(1) NOT NULL DEFAULT '0',
 `created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `modified` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `active` tinyint(1) NOT NULL DEFAULT '1',
 `phone` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ,
 `email_other` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ,
 `token` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ,
 `token_validity` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 PRIMARY KEY (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Admins';

CREATE TABLE `alias` (
 `address` varchar(255) NOT NULL,
 `goto` text NOT NULL,
 `domain` varchar(255) NOT NULL,
 `created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `modified` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `active` tinyint(1) NOT NULL DEFAULT '1',
 PRIMARY KEY (`address`),
 KEY `domain` (`domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Aliases';

CREATE TABLE `alias_domain` (
 `alias_domain` varchar(255) NOT NULL DEFAULT ,
 `target_domain` varchar(255) NOT NULL DEFAULT ,
 `created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `modified` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `active` tinyint(1) NOT NULL DEFAULT '1',
 PRIMARY KEY (`alias_domain`),
 KEY `active` (`active`),
 KEY `target_domain` (`target_domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Domain Aliases';

CREATE TABLE `config` (
 `id` int NOT NULL AUTO_INCREMENT,
 `name` varchar(20) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT ,
 `value` varchar(20) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT ,
 PRIMARY KEY (`id`),
 UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=ucs2 COMMENT='PostfixAdmin settings';

CREATE TABLE `domain` (
 `domain` varchar(255) NOT NULL,
 `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 `aliases` int NOT NULL DEFAULT '0',
 `mailboxes` int NOT NULL DEFAULT '0',
 `maxquota` bigint NOT NULL DEFAULT '0',
 `quota` bigint NOT NULL DEFAULT '0',
 `transport` varchar(255) NOT NULL,
 `backupmx` tinyint(1) NOT NULL DEFAULT '0',
 `created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `modified` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `active` tinyint(1) NOT NULL DEFAULT '1',
 PRIMARY KEY (`domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Domains';

CREATE TABLE `domain_admins` (
 `username` varchar(255) NOT NULL,
 `domain` varchar(255) NOT NULL,
 `created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `active` tinyint(1) NOT NULL DEFAULT '1',
 KEY `username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Domain Admins';
 
CREATE TABLE `fetchmail` (
 `id` int unsigned NOT NULL AUTO_INCREMENT,
 `domain` varchar(255) DEFAULT ,
 `mailbox` varchar(255) NOT NULL,
 `src_server` varchar(255) NOT NULL,
 `src_auth` enum('password','kerberos_v5','kerberos','kerberos_v4','gssapi','cram-md5','otp','ntlm','msn','ssh','any') CHARACTER SET ucs2 C
 `src_user` varchar(255) NOT NULL,
 `src_password` varchar(255) NOT NULL,
 `src_folder` varchar(255) NOT NULL,
 `poll_time` int unsigned NOT NULL DEFAULT '10',
 `fetchall` tinyint unsigned NOT NULL DEFAULT '0',
 `keep` tinyint unsigned NOT NULL DEFAULT '0',
 `protocol` enum('POP3','IMAP','POP2','ETRN','AUTO') CHARACTER SET ucs2 COLLATE ucs2_general_ci DEFAULT NULL,
 `usessl` tinyint unsigned NOT NULL DEFAULT '0',
 `sslcertck` tinyint(1) NOT NULL DEFAULT '0',
 `sslcertpath` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT ,
 `sslfingerprint` varchar(255) DEFAULT ,
 `extra_options` text,
 `returned_text` text,
 `mda` varchar(255) NOT NULL,
 `date` timestamp NOT NULL DEFAULT '1999-12-31 23:00:00',
 `created` timestamp NOT NULL DEFAULT '1999-12-31 23:00:00',
 `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 `active` tinyint(1) NOT NULL DEFAULT '0',
 PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
 
CREATE TABLE `log` (
 `timestamp` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `username` varchar(255) NOT NULL,
 `domain` varchar(255) NOT NULL,
 `action` varchar(255) NOT NULL,
 `data` text NOT NULL,
 `id` int NOT NULL AUTO_INCREMENT,
 PRIMARY KEY (`id`),
 KEY `timestamp` (`timestamp`),
 KEY `domain_timestamp` (`domain`,`timestamp`)
) ENGINE=MyISAM AUTO_INCREMENT=455 DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Log';

CREATE TABLE `mailbox` (
 `username` varchar(255) NOT NULL,
 `password` varchar(255) NOT NULL,
 `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 `maildir` varchar(255) NOT NULL,
 `quota` bigint NOT NULL DEFAULT '0',
 `local_part` varchar(255) NOT NULL,
 `domain` varchar(255) NOT NULL,
 `created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `modified` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `active` tinyint(1) NOT NULL DEFAULT '1',
 `phone` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ,
 `email_other` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ,
 `token` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ,
 `token_validity` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 PRIMARY KEY (`username`),
 KEY `domain` (`domain`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Mailboxes';

CREATE TABLE `quota` (
 `username` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
 `path` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
 `current` bigint DEFAULT NULL,
 PRIMARY KEY (`username`,`path`)
) ENGINE=MyISAM DEFAULT CHARSET=ucs2;

CREATE TABLE `quota2` (
 `username` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
 `bytes` bigint NOT NULL DEFAULT '0',
 `messages` int NOT NULL DEFAULT '0',
 PRIMARY KEY (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=ucs2;

CREATE TABLE `vacation` (
 `email` varchar(255) NOT NULL,
 `subject` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 `body` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
 `activefrom` timestamp NOT NULL DEFAULT '1999-12-31 23:00:00',
 `activeuntil` timestamp NOT NULL DEFAULT '2038-01-17 23:00:00',
 `cache` text NOT NULL,
 `domain` varchar(255) NOT NULL,
 `interval_time` int NOT NULL DEFAULT '0',
 `created` datetime NOT NULL DEFAULT '2000-01-01 00:00:00',
 `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 `active` tinyint(1) NOT NULL DEFAULT '1',
 PRIMARY KEY (`email`),
 KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Postfix Admin - Virtual Vacation';

CREATE TABLE `vacation_notification` (
 `on_vacation` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
 `notified` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT ,
 `notified_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 PRIMARY KEY (`on_vacation`,`notified`),
 CONSTRAINT `vacation_notification_pkey` FOREIGN KEY (`on_vacation`) REFERENCES `vacation` (`email`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Postfix Admin - Virtual Vacation Notifications';


Nicht alle Tabellen werden in meiner Konfiguration wirklich benutzt, aber es ist einfacher alle anzulegen.

/etc/postfixadmin/dbconfig.inc.php

Die Datenbankanbindung wird in der Ubuntu-Version über diese Datei konfiguriert.

<?php
##
## database access settings in php format
## automatically generated from /etc/dbconfig-common/postfixadmin.conf
## by /usr/sbin/dbconfig-generate-include
##
## by default this file is managed via ucf, so you shouldn't have to
## worry about manual changes being silently discarded.  *however*,
## you'll probably also want to edit the configuration file mentioned
## above too.
##
$dbuser='postfix';
$dbpass='assword';
$basepath=;
$dbname='postfix';
$dbserver='localhost';
$dbport=;
$dbtype='mysqli';

/etc/postfixadmin/config.local.php

Die momentan aktuelle Version besitzt eine Reihe von neuen Funktionen. Schöne bei dieser Version ist die Konfiguration, die sich in einer Datei config.local.php sammeln lässt. Außerdem sind die Voreinstellungen deutlich dichter an meinen Wünschen. Es bleibt dann hier:

<?php
$CONF['configured'] = true;

// on submission it will be echoed out to you as a hashed value.
$CONF['setup_password'] = '53a0f62bf8dcf073112eb0a0ed8929a:d85f0fe1081dccf9738b01fa7b377005b2ee8d9e';
$CONF['default_language'] = 'de';

$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.

mkdir /usr/share/postfixadmin/templates_c
chown www-data.www-data /usr/share/postfixadmin/templates_c


Aktuell ist bei der Version 3.2 eine kleine Änderung zu beachten, der Alias-Eintrag in der VServer-Konfiguration muss jetzt auf das Unterverzeichnis public zeigen:

Alias /postfixadmin  /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

Eine Anpassung in /etc/default/spamassassin

# Cronjob
# Set to anything but 0 to enable the cron job to automatically update
# spamassassin's rules on a nightly basis
CRON=1

Der Schalter ENABLED=1 in dieser Datei wird nicht mehr unterstützt, stattdessen aktiviert man den Dienst mittels:

systemctl enable spamassassin 

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