Root-Server mit Ubuntu 16.04-Hetzner

Aus LT42-Wiki
Zur Navigation springenZur Suche springen

Schon seit einiger Zeit beobachte ich die Serverbörse von Hetzner. Die Rechner, die dort ankommen, waren ähnlich den Serversondermodellen von Strato schon eine Weile in Gebrauch und werden nun weiter vermittelt. Die Leistungswerte unterscheiden sich drastisch. Einige Rechner gibt es mit 2GB RAM und 320GB HDD für 24€/Monat. Einige Rechner mit 32GB RAM und 3TB HDD für denselben Preis. Wartet man einige Tage, werden die Rechner mitunter auch günstiger.

Der Rechner hat folgende Eckdaten:

  • Intel Core i7-2600 8x 3.40GHz (8x 6823.66 Bogomips)
  • 16 GB Arbeitsspeicher
  • 2x 3 TB im RAID1-Verbund Festplattenspeicher

Den Rechner gibt es für 24€/Monat ohne Einrichtungspauschale. Er ist mit einer 1GBit/s-Leistung angeschlossen. Bei Strato gibt es nur 100MBit/s

Installation

Hetzner liefert die Geräte im Rescue-Modus aus. Das ist ein Minimal-Linux mit Tools zur Rettung und dem Skript installimage, mit dem eine Betriebssystem-Installation vorgenommen werden kann. Das ist schon mal ein großer Unterschied zu Strato, die die Rechner selber installieren und dann zur Verfügung stellen.

Der Robot (Kundencenter) von Hetzner bietet allerlei Möglichkeiten, so kann der Rechner bequem mit einem Strg + Alt + Entf-Befehl gefüttert werden oder per ACPI neugestartet werden. Zudem bietet Hetzner die Möglichkeit eines Weckens über LAN (WOL) und man kann bequem eigene Monitoring-Dienste für den Rechner anlegen, sodass man bei Unregelmäßigkeiten per Mail informiert wird.

Die Installation des Rechners erfolgt dann über den Befehl installimage. Nach einer Auswahl des Betriebssystems kann man über eine Textdatei die RAID-Einstellungen, Festplattenpartitionierung und den Hostnamen konfigurieren. Das macht es besonders einfach, mehrere Rechner zu installieren oder sich die Konfiguration noch einmal abzuspeichern.

Nach dem Verlassen des Editors installiert der Rechner dann das Grundsystem, während man zugucken kann:

               Hetzner Online GmbH - installimage

 Your server will be installed now, this will take some minutes
            You can abort at any time with CTRL+C ...

        :  Reading configuration                           done 
        :  Loading image file variables                    done 
        :  Loading ubuntu specific functions               done 
  1/16  :  Deleting partitions                             done 
  2/16  :  Test partition size                             done 
  3/16  :  Creating partitions and /etc/fstab              done 
  4/16  :  Creating software RAID level 1                  done 
  5/16  :  Formatting partitions
        :    formatting /dev/md/0 with swap                done 
        :    formatting /dev/md/1 with ext2                done 
        :    formatting /dev/md/2 with ext4                done 
        :    formatting /dev/md/3 with xfs                 done 
        :    formatting /dev/md/4 with ext4                done 
        :    formatting /dev/md/5 with ext4                done 
  6/16  :  Mounting partitions                             done 
  7/16  :  Sync time via ntp                               done 
        :  Importing public key for image validation       done 
  8/16  :  Validating image before starting extraction     done 
  9/16  :  Extracting image (local)                        done 
 10/16  :  Setting up network config                       done 
 11/16  :  Executing additional commands
        :    Setting hostname                              done 
        :    Generating new SSH keys                       done 
        :    Generating mdadm config                       done 
        :    Generating ramdisk                            done 
        :    Generating ntp config                         done 
 12/16  :  Setting up miscellaneous files                  done 
 13/16  :  Configuring authentication
        :    Fetching SSH keys                             done 
        :    Disabling root password                       done 
        :    Disabling SSH root login without password     done 
        :    Copying SSH keys                              done 
 14/16  :  Installing bootloader grub                      done 
 15/16  :  Running some ubuntu specific functions          done 
 16/16  :  Clearing log files                              done 

                 INSTALLATION COMPLETE
  You can now reboot and log in to your new system with
 the same password as you logged in to the rescue system.

root@rescue ~ # reboot

Nach dem Neustart steht dann das neue System zur Verfügung. Die Installation hat letztlich mit Lektüre etwa 7 Minuten gedauert. Das ist ein enormer Fortschritt zu anderen Providern.

Grundlegendes

Die Installationsimages sind nicht unbedingt tagesaktuell, daher aktualisieren wir nach der Anmeldung als root erstmal die Software:

apt-get update
apt-get upgrade

Smartmontools

Für Informationen über die Festplatte bieten sich die Smartmontools an:

sudo apt-get update
sudo apt-get install smartmontools

Mit den Befehl folgenden Befehlen bekommen wir Informationen über die Fetplatten sda und sdb:

sudo smartctl -a /dev/sda
sudo smartctl -a /dev/sdb

Die Platten sind mit 40556 und 40555 Stunden (~4 1/2 Jahre) definitiv nicht neu, weisen aber auch keine fatalen Fehler auf. Die Platten in meinem gebrauchten Root-Server als Serversondermodell laufen nun schon 9 Jahre. Eine der beiden Platten wirft 17 Fehler im SATA Error Log, die sich alle innerhalb eines Zeitraums um 14707 Stunden Laufzeit anordnen. Das hatte ich bisher noch nicht, die Platten scheinen sonst aber in Ordnung zu sein, daher beobachte ich das nur sporadisch weiter.

Firewall

Als Firewall lässt sich ufw nutzen. Das Paket muss nachinstalliert werden:

apt-get install ufw

und lässt sich dann einfach konfigurieren. ufw kann mit Softwarepaketen und einzelnen Ports umgehen:

ufw allow 22
ufw allow OpenSSH

Obiges zu setzen bevor die Firewall aktiviert wird, ist wichtig, da man sich sonst aus dem System aussperrt. Nach einer Aktivierung mittels

ufw enable

zeigt die Firewall auch automatisch Wirkung. Apache ist nun nicht mehr erreichbar. Das lässt sich mittels

ufw allow "Apache Full"

lösen.

Webserver Apache2

Zur Bereitstellung von Webseiten nutze ich Apache als Webserver mit PHP. Da der Server unter mehreren Namen erreichbar sein wird, richten wir VirtualHosts ein.

Die Installation läuft denkbar einfach über

sudo apt-get update
sudo apt-get install apache2 apache2-utils apache2-doc php php-mysql php-pear libapache2-mod-php7.0

Neben Apache gibt es ein paar Tools, Doku und neben PHP schon die Anbindung für MySQL und Apache. Apache kommt in der Version 2.4.18, bei PHP wird Version 7 installiert.

Nach der Installation geht es an die eigentliche Konfiguration des Webservers. Ziel ist es, das eine Reihe von Anwendungen (Roundcube, PHPMyAdmin, etc.) nur einmal installiert werden müssen und dann allen eingerichteten Domains zur Verfügung stehen. Gleichzeitig sollen Dummies, die den Server über seine IP oder einen nicht vorhandenen Namen ansprechen, keine Dienste nutzen können, sondern lediglich eine Fehler-Seite sehen. Die folgende Konfiguration habe ich in Teilen in ihrer Version vom 12. November 2014 aus dem Debacher-Wiki entnommen (CC-BY-SA). Wir legen also eine Grundkonfiguration für jeden "dummen" Aufruf an.

Die VHosts werden später unter /var/www/vhosts/ angelegt. Unter /var/www/vhosts/default/htdocs/ findet sich dann die Fehlerseite und unter /var/www/htdocs/ die entsprechenden Anwendungen. Die Ordner erstellen wir nun einmal. Dazu kopieren wir auch die Standard-Seite in das entsprechende Verzeichnis:

mkdir /var/www/htdocs
mkdir /var/www/vhosts
mkdir /var/www/vhosts/default
mv /var/www/html /var/www/vhosts/default/htdocs

Wichtig ist, dass wir die Datei vorher einmal sichern:

cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/000-default.conf.org
cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/default-ssl.conf.org


/etc/apache2/sites-available/000-default.conf

ServerName default
ServerAdmin webmaster@example.org

ServerTokens Major

DocumentRoot /var/www/htdocs/

# Aliase werden einmal zentral gesetzt. Diese Aliase sind von allen Domains aus erreichbar.
Alias /webmail   /var/www/htdocs/roundcube
Alias /ftp       /var/www/htdocs/webftp

<Directory "/var/www/vhosts">
       AllowOverride All
       Options +FollowSymLinks
       Order allow,deny
       Allow from all
       <IfModule mod_php5.c>
       </IfModule>
</Directory>

<IfModule mod_userdir.c>
       UserDir disabled
</IfModule>

<VirtualHost *:80>
       ServerName default
       UseCanonicalName Off
       DocumentRoot /var/www/vhosts/default/htdocs/
       ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"

       # Blocken der Anfragen an eingerichtete Dienste
       Alias /webmail      /var/www/htdocs/dummy
       Alias /pma          /var/www/htdocs/dummy
       Alias /webftp       /var/www/htdocs/dummy
       Alias /roundcube    /var/www/htdocs/dummy

       <IfDefine MAILMAN>
          ScriptAlias     /mailman/       /var/www/htdocs/dummy
          Alias           /mailmanicons/  /var/www/htdocs/dummy
          Alias           /pipermail/     /var/www/htdocs/dummy
       </IfDefine>

       <IfModule mod_ssl.c>
               SSLEngine off
       </IfModule>
       # Deaktivieren des Zugriffs auf die CGI-Skripte von irgendwo
       <Directory "/var/www/cgi-bin/">
               AllowOverride None
               Options None
               Order allow,deny
               Deny from all   
       </Directory>
       <Directory /var/www/vhosts/default/htdocs>
               AllowOverride All
               Options None
               Order allow,deny
               Allow from all  

               <IfModule mod_php5.c>
                 php_admin_flag engine on
                 php_admin_flag safe_mode off
               </IfModule>
       </Directory>

</VirtualHost>

/etc/apache2/sites-available/default-ssl.conf

<IfModule mod_ssl.c>
<VirtualHost _default_:443>
	ServerAdmin webmaster@example.org
 
	DocumentRoot /var/www/htdocs
	<Directory /var/www/>
		Options -Indexes +FollowSymLinks +MultiViews
		AllowOverride None
		Order allow,deny
		allow from all
	</Directory>
 
	ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
	<Directory "/usr/lib/cgi-bin">
		AllowOverride None
		Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
		Order allow,deny
		Allow from all
	</Directory>
 
	ErrorLog ${APACHE_LOG_DIR}/error.log
 
	# Possible values include: debug, info, notice, warn, error, crit,
	# alert, emerg.
	LogLevel warn
 
	CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined  

       # Blocken der Anfragen an eingerichtete Dienste
       Alias /webmail      /var/www/htdocs/dummy
       Alias /pma          /var/www/htdocs/dummy
       Alias /webftp       /var/www/htdocs/dummy
       Alias /roundcube    /var/www/htdocs/dummy

       <IfDefine MAILMAN>
          ScriptAlias     /mailman/       /var/www/htdocs/dummy
          Alias           /mailmanicons/  /var/www/htdocs/dummy
          Alias           /pipermail/     /var/www/htdocs/dummy
       </IfDefine>

	Alias /doc/ "/usr/share/doc/"
	<Directory "/usr/share/doc/">
		Options Indexes MultiViews FollowSymLinks
		AllowOverride None
		Order deny,allow
		Deny from all
		Allow from 127.0.0.0/255.0.0.0 ::1/128
	</Directory>
 	SSLEngine on
 	SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
 	SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key  
	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
	<FilesMatch "\.(cgi|shtml|phtml|php)$">
		SSLOptions +StdEnvVars
	</FilesMatch>
	<Directory /usr/lib/cgi-bin>
		SSLOptions +StdEnvVars
	</Directory>
 
	BrowserMatch "MSIE [2-6]" \
		nokeepalive ssl-unclean-shutdown \
		downgrade-1.0 force-response-1.0
	# MSIE 7 and newer should be able to use keepalive
	 BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown

</VirtualHost>
</IfModule>

Entscheidend ist, dass die angegebenen Pfade tatsächlich existieren, sonst gibt Apache beim nächsten Start eine Fehlermeldung aus. Sollten die Verzeichnisrechte nicht richtig gesetzt sein, kann das mittels

sudo chown -R www-data.www-data /var/www/
sudo chmod -R 0770 /var/www/

nachgeholt werden.

Nun geht es an die Konfiguration der Server-Adresse. Ruft man den Server über seinen Reverse-DNS auf, kann man so beeinflussen, was angezeigt wird.


/etc/apache2/sites-available/reverse.server.example.com.conf

<VirtualHost *:80>
   ServerName reverse.server.example.com
   UseCanonicalName Off
   DocumentRoot /var/www/vhosts/default/htdocs

   CustomLog  /var/log/apache2/access.log combined
   ErrorLog   /var/log/apache2/error.log

   ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
   # Soll PHPMyAdmin verfügbar sein, kann der Pfad hier aktiviert werden. 
#   Alias /pma /var/www/htdocs/phpMyAdmin
   Alias  /webstat /var/www/vhosts/default/webstat
   <IfModule mod_ssl.c>
       SSLEngine off
   </IfModule>

   <Directory "/var/www/cgi-bin/">
       AllowOverride None
       Options None
       Order allow,deny
       Allow from all
   </Directory>

   <Directory /var/www/vhosts/default/htdocs>
       AllowOverride All
       Options None
       Order allow,deny
       Allow from all 

       <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 reverse.server.example.com
       UseCanonicalName Off  
       DocumentRoot /var/www/vhosts/default/htdocs 

       CustomLog  /var/log/apache2/access.log combined
       ErrorLog   /var/log/apache2/error.log 

       ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
#       Alias /pma /var/www/htdocs/phpMyAdmin
#       Alias /webftp /var/www/htdocs/webftp   

       SSLEngine on

       SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNUL
       SSLCertificateFile /var/www/vhosts/default/ssl/server.crt
       SSLCertificateKeyFile /var/www/vhosts/default/ssl/server.key
       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

       <Directory "/var/www/cgi-bin/">
               AllowOverride None
               Options None
               Order allow,deny
               Allow from all  
       </Directory>

       <Directory /var/www/vhosts/default/httpsdocs>
               SSLRequireSSL
               AllowOverride None
               Options None
               Order allow,deny
               Allow from all  
      </Directory>
 </VirtualHost>

</IfModule>

Damit ist die Grundkonfiguration von Apache abgeschlossen. Für jeden neuen VirtualHost legen wir ab dann eine Datei als /etc/apache2/sites-avaiable/<domain>.conf an.

Wichtig ist: Der Ubuntu-Apache unterscheidet zwischen aktivierten und verfügbaren Konfigurationen. Wir müssen also jede Datei noch einmal extra unter /etc/apache2/sites-enabled/ einbinden. Dazu einfach einen symbolischen Link erstellen:

sudo ln -s /etc/apache2/sites-available/<domain>.conf /etc/apache2/sites-enabled/<domain>.conf

Das muss selbstverständlich auch mit der Standardkonfiguration gemacht werden, sofern das nicht schon standardmäßig passiert ist.

Eine Beispiel-Konfiguration für VirtualHosts findet sich ebenfalls im Debacher-Wiki (CC-by-sa). Dabei muss <dummy> mit der Domain ersetzt werden (in VI durch :%s/<dummy>/example.org. Die Verzeichnisse werden dann unterhalb von /var/www/vhosts/<dummy> angelegt. Hier ist es sinnig, nach Seiten mit aktiviertem SSL und Seiten ohne SSL zu unterscheiden. Wichtig ist, dass alle Konfigurationsdateien mit .conf enden, da sie sonst von Apache ignoriert werden.

/etc/apache/sites-available/dummy.conf

<VirtualHost *:80>
 ServerName   www.<dummy>:80
 ServerAlias <dummy>
 UseCanonicalName Off
 DocumentRoot /var/www/vhosts/<dummy>/htdocs

 CustomLog  /var/log/apache2/<dummy>.access.log combined
 ErrorLog   /var/log/apache2/<dummy>.error.log

 CustomLog /var/log/apache2/vhosts.access.log vhost_combined

 ScriptAlias  /cgi-bin/ /var/www/vhosts/<dummy>/cgi-bin/
 Alias  /webstat /var/www/vhosts/<dummy>/webstat

 <IfModule mod_ssl.c>
       SSLEngine off
 </IfModule>

 <Directory /var/www/vhosts/<dummy>/htdocs>

   <IfModule mod_php5.c>
       php_admin_flag engine on
       php_admin_flag safe_mode off
       php_admin_value include_path "/var/www/vhosts/<dummy>/htdocs:.:/tmp:./:/usr/share/php5/PEAR/"
       php_admin_value open_basedir "/var/www/vhosts/<dummy>/htdocs:/tmp:.:/usr/share/php5/PEAR/"

   </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
      Order allow,deny
      Allow from all  
 </Directory>

</VirtualHost>

/etc/apache/sites-available/dummy-ssl.conf

<IfModule mod_ssl.c>

<VirtualHost *:443>
 ServerName   www.<dummy>:443
 ServerAlias <dummy>
 UseCanonicalName Off
 DocumentRoot /var/www/vhosts/<dummy>/htdocs

 CustomLog  /var/log/apache2/<dummy>.access.log combined
 ErrorLog   /var/log/apache2/<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>/htdocs>

   <IfModule mod_php5.c>
       php_admin_flag engine on
       php_admin_flag safe_mode off
       php_admin_value include_path "/var/www/vhosts/<dummy>/htdocs:.:/tmp:./:/usr/share/php5/PEAR/"
       php_admin_value open_basedir "/var/www/vhosts/<dummy>/htdocs:/tmp:.:/usr/share/php5/PEAR/"
   </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
      Order allow,deny
      Allow from all
 </Directory>
  SSLProtocol all -SSLv2
  SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM
  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
  SSLCertificateFile /etc/letsencrypt/live/<dummy>/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/<dummy>/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/<dummy>/chain.pem
  SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
  CustomLog /var/log/apache2/<dummy>.ssl.log  "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

</VirtualHost>

</IfModule>

Hier habe ich für die SSL-Konfiguration eine Datei erstellt, die die obigen zusammenfasst. Der HTTP-Aufruf wird dann auf SSL umgeleitet:

<VirtualHost *:80>
		ServerAdmin webmaster@example.org
		ServerName example.org
		ServerAlias www.example.org
		DocumentRoot /var/www/vhosts/example.org/htdocs
		Redirect permanent / https://example.org/

		Alias /.well-known /var/www/vhosts/example.org/htdocs/.well-known
		<Directory /var/www/vhosts/example.org/htdocs/.well-known/>
				Options FollowSymLinks MultiViews
				AllowOverride None
				Order allow,deny
				allow from all
		</Directory>
		
		ErrorLog /var/log/apache2/example.org.error.log
		LogLevel warn
		CustomLog /var/log/apache2/example.org.access.log combined
</VirtualHost>

<VirtualHost *:443>
		ServerAdmin webmaster@example.org
		ServerName example.org
		ServerAlias www.example.org dummy.domain.lt42.de
		SSLEngine on 
		# Ab Apache 2.4.8
		#SSLCertificateFile /etc/letsencrypt/live/example.org/fullchain.pem
		#SSLCertificateKeyFile /etc/letsencrypt/live/example.org/privkey.pem

		SSLCertificateFile /etc/letsencrypt/live/example.org/cert.pem
		SSLCertificateKeyFile /etc/letsencrypt/live/example.org/privkey.pem
		SSLCertificateChainFile /etc/letsencrypt/live/example.org/chain.pem
		DocumentRoot /var/www/vhosts/example.org/htdocs
		<Directory /var/www/vhosts/example.org/htdocs/>
				Options FollowSymLinks MultiViews
				AllowOverride All
				Order allow,deny
				allow from all
		</Directory>
		Alias /webstat /var/www/vhosts/example.org/webstat
		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 
		ErrorLog /var/log/apache2/example.org.error.log
		LogLevel warn
		CustomLog /var/log/apache2/example.org.access.log combined
</VirtualHost>

Der Vorteil bei obiger Lösung ist, dass dann nur noch eine Datei pro Domain existieren muss.

Damit ist die Einrichtung des Webservers abgeschlossen.


Datenbank-Server

Als Datenbank-Server benutze ich MySQL. Die Installation läuft ebenfalls über APT:

sudo apt-get install mysql-server mysql-client

Falls die Abfrage während der Installation nicht schon kommt, kann man dem root-Nutzer mittels

sudo mysqladmin -u root password "newpwd"

ein neues Passwort setzen.


Mailserver

Die Einrichtung des Mailservers ist immer wieder spannend, da bei Updates immer wieder kleine Änderungen durchgeführt werden. Ich verwende Postfix als MTA und Dovecot als IMAP-Server. Zusätzlich arbeiten wir mit Virtuellen Hosts, damit ein Mailserver für mehrere Domains verantwortlich sein kann. Die Domains und ihre Mail-Accounts können dann über den Postfixadmin bequem im Netz verwaltet werden. Außerdem werden die Mails natürlich gefiltert.

Zunächst installieren wir Postfix und dessen Anbindung an MySQL:

sudo apt-get install postfix postfix-mysql


Falls bei der Installation ein Konfigurations-Dialog auftritt, wählen wir hier einfach erstmal "Keine Konfiguration" aus.

Dann erstellen wir im MySQL-Server eine neue Datenbank "mail" und einen neuen Benutzer "mail" mit allen Rechten:

root@server:/# mysql -u root -p
mysql> CREATE DATABASE mail;
mysql> GRANT ALL PRIVILEGES ON mail.* TO 'mail'@'localhost' IDENTIFIED BY 'mail';
mysql> quit

Die Konfiguration liegt in /etc/postfix wir wechseln also in das Verzeichnis und bearbeiten die (vielleicht neue) Datei main.cf

root@server:/# cd /etc/postfix
root@server:/# vi main.cf

Dann richten wir die Datei wie folgt ein (denken Sie dran myhostname und myorigin an Ihre eigenen Bedürfnisse anzupassen). Mit Dovecot 2.0 hat sich einiges an der SASL-Authentifizierung geändert; das ist hier schon eingearbeitet:

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
append_dot_mydomain = no
#delay_warning_time = 4h
myhostname = mail.example.com
myorigin = /etc/mailname
mydestination = mydestination = $myhostname, mail.example.com, h23XXXXX.stratoserver.net, localhost.stratoserver.net, localhost
relayhost =
mynetworks = 127.0.0.0/8 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = ipv4
alias_maps = hash:/etc/aliases
virtual_mailbox_domains = proxy:mysql:$config_directory/mysql_virtual_domains_maps.cf
virtual_mailbox_base = /var/vmail
virtual_mailbox_maps = proxy:mysql:$config_directory/mysql_virtual_mailbox_maps.cf
virtual_alias_maps = proxy:mysql:$config_directory/mysql_virtual_alias_maps.cf
virtual_minimum_uid = 150
virtual_uid_maps = static:150
virtual_gid_maps = static:8
virtual_transport = dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = 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.dnsbl.sorbs.net, reject_unknown_client

smtpd_helo_restrictions = permit_mynetworks, reject_invalid_hostname

smtpd_sender_restrictions = reject_unknown_sender_domain

smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination 


# tls config
#smtpd_use_tls = yes
#smtp_tls_note_starttls_offer = yes
#smtpd_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem
#smtpd_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem
#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
#dovecot_destination_recipient_limit = 1
## Verschlüsselung der Transportebene
#smtpd_tls_security_level = may
#smtp_tls_security_level = may

Der Modus "may" bedeutet hier "Opportunistic TLS", d.h., dass eine TLS-Verbindung genutzt wird, sofern beide Server sich damit verstehen. Bietet der gegenübersprechende Server kein TLS an, wird auch keins genutzt. Postfix-Doku

Diese Konfiguration legt die Mails in /var/vmail ab und benutzt den Benutzer vmail mit der UID 150 (legen wir gleich an):

sudo useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c 'Virtual mailbox' vmail
sudo mkdir /var/vmail
sudo chmod 770 /var/vmail/
sudo chown vmail:mail /var/vmail/

Jetzt fangen wir an, die Maps zu konfigurieren. Hiermit bringen wir Postfix bei, wir er die Datenbank nach Mail-Adressen abfragen muss. Dafür müssen wir einige Dateien anlegen:

sudo touch /etc/postfix/mysql_virtual_alias_maps.cf
sudo touch /etc/postfix/mysql_virtual_domains_maps.cf
sudo touch /etc/postfix/mysql_virtual_mailbox_limit_maps.cf
sudo touch /etc/postfix/mysql_virtual_mailbox_maps.cf

/etc/postfix/mysql_virtual_alias_maps.cf

user = mail
password = mail
hosts = localhost
dbname = mail
table = alias
select_field = goto
where_field = address
additional_conditions = and active = '1'
#query = SELECT goto FROM alias WHERE address='%s' AND active = '1'

/etc/postfix/mysql_virtual_domains_maps.cf

user = mail
password = mail
hosts = localhost
dbname = mail
table = domain
select_field = domain
where_field = domain
additional_conditions = and backupmx = '0' and active = '1'
#query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'

/etc/postfix/mysql_virtual_mailbox_limit_maps.cf

user = mail
password = mail
hosts = localhost
dbname = mail
table = mailbox
select_field = quota
where_field = username
additional_conditions = and active = '1'
#query = SELECT quota FROM mailbox WHERE username='%s' AND active = '1'

/etc/postfix/mysql_virtual_mailbox_maps.cf

user = mail
password = mail
hosts = localhost
dbname = mail
table = mailbox
select_field = CONCAT(domain,'/',maildir)
where_field = username
additional_conditions = and active = '1'
#query = SELECT CONCAT(domain,'/',maildir) FROM mailbox WHERE username='%s' AND active = '1'

Wichtig ist es, hier den Benutzernamen und das Passwort an die MySQL-Einstellungen anzupassen.

Als letzte Postfix-Konfiguration müssen wir in der master.cf ganz unten die Pipe für Dovecot einrichten:

dovecot unix - n n - - pipe flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/deliver -d $(recipient)
submission inet n - - - - smtpd
 -o smtpd_tls_security_level=encrypt
 -o smtpd_sasl_auth_enable=yes
 -o smtpd_sasl_type=dovecot
 -o smtpd_sasl_path=private/auth
 -o smtpd_sasl_security_options=noanonymous
 -o smtpd_sasl_local_domain=$myhostname
 -o smtpd_client_restrictions=permit_sasl_authenticated,reject
 -o smtpd_sender_login_maps=hash:/etc/postfix/virtual
 -o smtpd_sender_restrictions=reject_sender_login_mismatch
 -o smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject

Nachdem ich Probleme hatte, Mails mit Thunderbird ordentlich abzuliefern und immer wieder auf den Fehler:

5.7.1 <mail@domain.tld>: Sender address rejected: not owned by user mail@domain.tld

gestoßen bin, ist mir aufgefallen, dass folgende Zeile in der master.cf den Fehler zu verursachen scheint:

-o smtpd_sender_restrictions=reject_sender_login_mismatch

Sollte der Fehler also auftreten, kommentieren wir diese Zeile einfach aus.

Gegen die Fehlermeldung, dass die /etc/aliases nicht gefunden wurde, führen wir einmal

sudo newaliases

aus.

Dovecot

Nun beginnen wir, den zweiten Teil des Mailservers anzupassen. Hierfür installieren wir Dovecot über apt:

sudo apt-get install dovecot-imapd dovecot-pop3d dovecot-mysql

Wir können hier auch das Paket "dovecot-pop3d" weglassen, wenn wir keine POP3-Anmeldung am Server brauchen.

Die Abfrage nach einem SSL-Zertifikat können wir entweder mit Ja beantworten. Dann richtet Dovecot ein selbstsigniertes SSL-Zertifikat ein. Falls wir eines haben, sagen wir Nein.

Zur Sicherheit sichern wir die originale Konfigurationsdatei via

sudo mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.org

Anschließend können wir mit der Konfiguration von Dovecot unter /etc/dovecot/dovecot.conf beginnen. Diese Konfiguration kann einfach so kopiert werden. Es bringt auch eine SSL-Unterstützung mit, die aber von Haus aus deaktiviert ist. Natürlich müssen der Hostname und der Postmaster angepasst werden.

auth_mechanisms = plain login
disable_plaintext_auth = no
first_valid_uid = 150
hostname = mail.example.org
last_valid_uid = 150
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_location = maildir:/var/vmail/%d/%u
passdb {
  args = /etc/dovecot/dovecot-sql.conf
  driver = sql
}
postmaster_address = xxx@example.com
service auth {
  unix_listener /var/spool/postfix/private/auth {
    group = postfix
    mode = 0660
    user = postfix
  }
  unix_listener auth-userdb {
    group = mail
    mode = 0600
    user = vmail
  }
}
service imap-login {
  executable = imap-login
  inet_listener imap {
    port = 143
  }
}
service pop3-login {
  executable = pop3-login
  inet_listener pop3 {
    port = 110
  }
}
# Hier kann bei Bedarf die SSL-Verschlüsselung eingeschaltet werden.
ssl = no
#ssl_cert = </etc/letsencrypt/live/example.org/fullchain.pem
#ssl_key = </etc/letsencrypt/live/example.org/privkey.pem
userdb {
  args = /etc/dovecot/dovecot-sql.conf
  driver = sql
}
protocol imap {
  mail_max_userip_connections = 10
}
protocols = imap pop3

Nun müssen wir Dovecot nur noch sagen, wie sich Dovecot die Anmelde-Daten beschaffen kann. Dafür bearbeiten wir die Datei /etc/dovecot/dovecot-sql.conf:

driver = mysql
connect = host=localhost dbname=mail user=mail password=mail
# The new name for MD5 is MD5-CRYPT so you might need to change this depending on version
default_pass_scheme = MD5
# Get the mailbox
user_query = SELECT '/var/vmail/%d/%n' as home, 'maildir:/var/vmail/%d/%n' as mail, 150 AS uid, 8 AS gid, concat('dirsize:storage=', quota) AS quota FROM mailbox WHERE username = '%u' AND active = '1'
# Get the password
password_query  = SELECT username as user, password, '/var/vmail/%d/%n' as userdb_home, 'maildir:/var/vmail/%d/%n' as userdb_mail, 150 as userdb_uid, 8 as userdb_gid FROM mailbox WHERE username = '%u' AND active = '1'
# If using client certificates for authentication, comment the above and uncomment the following
#password_query = SELECT null AS password, '%u' AS user

Hier müssen wir möglicherweise die Felder user= und password= an unsere Zwecke anpassen.

Dann setzen wir noch die Rechte für Dovecot:

sudo chmod 600 /etc/dovecot/*.conf
sudo chown vmail /etc/dovecot/*.conf

Dovecot ist jetzt konfiguriert. Momentan noch ohne SSL, aber das kommt später.

Postfix Admin

Zum Anlegen der Domains und Postfächer nutzen wir den Postfixadmin, der passenderweise auch gleich das Datenbank-Schema für die gerade erstellte Konfiguration mitbringt.

Wir laden den PostfixAdmin von der Webseite herunter und entpacken ihn in ein eingerichtetes Verzeichnis z.B. einer Subdomain (z.B. mail.<domain>)

sudo mkdir /var/www/vhosts/mail.<domain>/htdocs
cd /var/www/vhosts/mail.<domain>/htdocs
wget -O pfa.tgz https://sourceforge.net/projects/postfixadmin/files/latest/download
tar xfz pfa.tgz

Nun passen wir noch den Postfix Admin an unsere Zwecke an. Dazu wechseln wir in das vorhin angelegte Verzeichnis postfixadmin-X.X.X/ und editieren die Standardkonfiguration:

cd ./postfixadmin-X.X.X/
vi config.inc.php

Hier passen wir folgende Parameter an:

$CONF['postfix_admin_url'] = ‘'var/www/vhosts/mail.<domain>/postfixadmin/';
$CONF['database_type'] = 'mysqli';
$CONF['database_user'] = 'mail';
$CONF['database_password'] = 'mail';
$CONF['database_name'] = 'mail';

(Natürlich an die eigenen Zwecke angepasst)

Sind wir mit der Konfiguration fertig, setzen wir den Parameter

$CONF['configured'] = false;

auf true und können unter der angelegten Domain den Installer starten. (postfixadmin/setup.php)

Hier müssen zwei PHP-Pakete nachinstalliert werden:

sudo apt-get install php-mbstring php-imap

Danach einmal Apache neu laden:

sudo service apache2 reload

Ist alles installiert, können wir einen Super-Admin einrichten, der alle Domains, Accounts und Administrator-Account im Postfixadmin konfigurieren kann.

Nun ist der Mailserver eingerichtet. Wir starten nun die Services neu:

service postfix restart
service dovecot restart
service apache2 restart
service mysql restart

Nun können wir unter http://mail.example.org/postfixadmin/ einen neuen Benutzer und eine neue Domain anlegen und einige Tests durchführen. Damit ist der Mailserver eingerichtet.

Roundcube

RoundCube könnte prinzipiell über die Paketquellen installiert werden. Ich bin hängen geblieben und installiere immer noch manuell mit den Paketen von www.roundcube.net. Wir entpacken das Verzeichnis nach /var/www/htdocs/roundcube, da die Installation ja von allen Domains aus erreichbar sein soll. Seit Version 3.1 bietet Postfix endlich auch eine lokale Installationsdatei an. Dann kann man bequemer Updates einspielen.

/var/www/htdocs/roundcube/config/config.local.php

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

// on submission it will be echoed out to you as a hashed value.
$CONF['setup_password'] = 'changeme';
$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@example.de';
$CONF['page_size'] = '20';

$CONF['default_aliases'] = array (
   'abuse' => 'abuse@example.de',
   'hostmaster' => 'hostmaster@example.de',
   'postmaster' => 'postmaster@example.de',
   'webmaster' => 'webmaster@example.de'
);

$CONF['quota'] = 'YES';
$CONF['footer_text'] = 'Zurück zu example.de';
$CONF['footer_link'] = 'http://example.de';
 
// Welcome Message
// This message is send to every newly created mailbox.
// Change the text between EOM.
$CONF['welcome_text'] = <<<EOM
Herzlich Willkommen,  

zum neuen E-Mail Postfach. 

Bei Fragen oder Problemen bitte
Lukas Thiel ansprechen
EOM;

$CONF['show_undeliverable_exceptions']=array("example.de","lt42.de");
$CONF['used_quotas'] = 'YES';
$CONF['maxquota'] = '2048';
$CONF['domain_quota_default'] = '0';

Beim ersten Aufruf erschien

ERROR: the templates_c directory doesn't exist or isn't writeable for the webserver

Nach einem Erstellen des Verzeichnissen und der Anpassung der Rechte an www-data, klappt das aber auch.

Sieve

Ich wollte meine Mails gerne mit Hilfe von Sieve filtern. Bisher habe ich die Abwesenheitsbenachrichtigungen immer mit dem Postfixadmin-Virtual-Vacation realisiert, das ist aber unschön. Sieve klingt da schöner und kann auch mehr.

Zuerst installieren wir das Paket mit APT:

apt-get update
apt-get install dovecot-managesieved

Dann geht es an die Einrichtung von Dovecot. Dafür bearbeiten wir die Datei /etc/dovecot/dovecot.conf und fügen folgende Zeilen an:

managesieve_notify_capability = mailto
managesieve_sieve_capability = fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date
# Mail-Filterung mit Sieve
service managesieve-login { 
 inet_listener sieve {
  port = 4190
 }
}

protocol lda {
 mail_plugins = $mail_plugins sieve
}

plugin {
 sieve = /var/vmail/%d/%n/.dovecot.sieve
 sieve_dir = /var/vmail/%d/%n/sieve
}

Falls Sie Ihre Mails mit LMTP zustellen, muss in der Zeile "protocol lda" natürlich "protocol lmtp" stehen.

Nun fügen wir sieve noch als Protokoll für Dovecot hinzu. Dazu fügen wir an die Zeile

protocols = imap pop3

noch sieve an, also

protocols = imap pop3 sieve

Nach einem Neustart von Dovecot, sollte alles funktionieren. Nun geht es an die Erstellung der Filter. Dazu bringt beispielweise Thunderbird ein Tool mit, allerdings finde ich die Lösung per Webmailer wesentlich schöner. Passenderweise bringt auch Roundcube von Haus aus eine Möglichkeit zur Bearbeitung von Sieve-Scripten mit.

Zum Aktivieren wechseln wir in das Roundcube-Installationsverzeichnis und bearbeiten die config/config.inc.php. Dort muss lediglich folgendes Array erweitert werden:

$config['plugins'] = array();

wird zu

$config['plugins'] = array('managesieve');

Wichtig ist, dass der Name mit dem Namen des Ordners in plugins/ übereinstimmt. Nach der Installation können wir im Roundcube unter Einstellungen/Filter die Filter bearbeiten.

Passwort ändern mit Roundcube

Ich wollte schon lange alle möglichen Einstellungen für Benutzer unter ein Dach bringen. Bisher habe ich Benutzern immer einen Link zum Webmailer und einen für den Postfixadmin gegeben, damit sie ihr Passwort ändern können. Doch Roundcube bringt einige spannende Plugins (s.o. Sieve) mit, die diese Arbeit ebenso übernehmen können.

Für das Ändern des Passwort bedienen wir uns dem mitgelieferten Plugin password. Zuerst kopieren wir uns die Datei plugins/password/config.inc.php.dist (von der Roundcube-Wurzel aus) in plugins/password/config.inc.php und bearbeiten die folgenden zwei Zeilen:

$config['password_db_dsn'] = 'mysql://benutzer:passwort@localhost/db';
$config['password_query'] = 'UPDATE mailbox SET password=%c WHERE username=%u';

Die Zugangsdaten sind in diesem Fall die gleichen, wie bei Postfix und Dovecot, was naheliegt, da wir ja an die Mail-Datenbank heran wollen. In unserem Fall waren das mail, mail und mail. Im password_query tragen wir dann den SQL-Befehl zum Update des Passwortes ein. Dieses lässt sich aus dem Datenbank-Aufbau erahnen.

Zum Abschluss speichern wir die Datei und binden das Plugin wie oben auch in der config/config.inc.php in dem Array $config['plugins'] ein. Dann können wir unser Passwort im Roundcube ändern.

Amavis

Natürlich sollen die Mails auf SPAM und Viren überprüft werden. Dafür kommt Amavis mit ClamAV (Virenscanner) und SpamAssassin (Spamscanner) zum Einsatz. Die Konfiguration ist trivial und orientiert sich an dieser. Zuerst installieren wir mit

sudo apt-get update
sudo apt-get install amavis clamav clamav-daemon spamassassin

Die Konfiguration muss an einigen Stellen gedreht werden. 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

Viren- und Spamprüfung aktivieren wir dann in /etc/amavis/conf.d/15-content_filter_mode

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


Zusätzlich wird SpamAssassin in einen Daemon-Modus gefahren und es werden nächtliche Aktualisierungen via cron aktiviert: /etc/default/spamassassin:

# /etc/default/spamassassin
# Duncan Findlay

# WARNING: please read README.spamd before using.
# There may be security risks.

# If you're using systemd (default for jessie), the ENABLED setting is
# not used. Instead, enable spamd by issuing:
# systemctl enable spamassassin.service
# Change to "1" to enable spamd on systems using sysvinit:
ENABLED=1

# Options
# See man spamd for possible options. The -d option is automatically added.

# SpamAssassin uses a preforking model, so be careful! You need to
# make sure --max-children is not set to anything higher than 5,
# unless you know what you're doing. 

OPTIONS="--create-prefs --max-children 5 --helper-home-dir" 

# Pid file
# Where should spamd write its PID to file? If you use the -u or
# --username option above, this needs to be writable by that user.
# Otherwise, the init script will not be able to shut spamd down.
PIDFILE="/var/run/spamd.pid"

# Set nice level of spamd
#NICE="--nicelevel 15"

# 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

Spielkram bietet /etc/amavis/conf.d/20-debian_defaults, wo wir mit

# SPAM-Tag in der Betreff-Zeile
$sa_spam_subject_tag = '[AlphaCentauri-Trash SPAM] ';
# Empfänger für Virus-Benachrichtigungen
$virus_admin = "virusadmin\@example.org"; # due to D_DISCARD default
# und die X-Virus-Scanned-Zeile in den Mails beeinflussen können:
$X_HEADER_LINE = "by Thiel-SpamAndVirusFilter Debian $myproduct_name at $mydomain";

Nach einem Neustart der Dienste mittels

service clamav-freshclam restart
service clamav-daemon restart
service amavis restart
service spamassassin restart

sollte das System laufen.

Bei mir mussten noch das Perl-Modul DBD::mysql mittels

sudo cpan
cpan[1] install DBD::mysql

und eine Bibliothek für MySQL mittels

sudo apt-get install libmysqlclient-dev 

nachinstalliert werden.


Dann geben wir die Ports in der Firewall frei:

sudo ufw allow Postfix
sudo ufw allow "Postfix SMTPS"
sudo ufw allow "Postfix Submission"
sudo ufw allow "Dovecot IMAP"
sudo ufw allow "Dovecot Secure IMAP"

MailMan

Die Konfiguration von Mailman ist ausführlich bei Uwe Debacher dokumentiert, daher spare ich mir das an dieser Stelle. Meine Installation ist baugleich.

DNS Reverse

Es empfiehlt sich, bei Hetzner einen Reverse DNS-Eintrag zu hinterlegen. Die DNS-Abfrage der IP-Adresse läuft dann nicht mehr auf einen generischen Namen, sondern über einen eigenen DNS-Namen. Wichtig ist, dass der Name natürlich auch wieder in die IP-Adresse auflöst.

Im Postfix und im Dovecot stellen wir dann den Hostnamen um. Vorteil ist, dass der Server dann eine höhere Reputation bekommt, als unter der Standard-Domain. Zusätzlich klingt das natürlich auch professioneller.

Nachtrag 29.11.2018

Ich habe nun TLSv1.0 und TLSv1.1 auf meinem Server deaktiviert. Dafür musste ich die Config jedes einzelnen VHosts einmal anfassen und habe die folgenden Zeilen auskommentiert:

#SSLProtocol All -SSLv2 -SSLv3
#SSLHonorCipherOrder on
#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

und zentral (und neu) gesetzt in /etc/apache2/mods-available/ssl.conf :

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
SSLHonorCipherOrder on
SSLProtocol TLSv1.2

Damit ist in

nmap --script ssl-enum-ciphers -p 443 lt42.de | grep TLSv

dann nur noch TLSv2 aktiv.

Das schießt erstmal veraltete Nextcloud-Clients ab, hier empfiehlt sich ein manuelles Update auf die neuste Version.

Zudem ist es sinnvoll (bei Ubuntu 16.04) OpenSSL manuell zu aktualisieren:

cd /tmp/
wget https://www.openssl.org/source/openssl-1.1.1.tar.gz
tar xvf openssl-1.1.1.tar.gz
cd openssl-1.1.1
./config -Wl,--enable-new-dtags,-rpath,'$(LIBRPATH)'
make
make test
make install
mv /usr/bin/openssl /root
ln -s /usr/local/bin/openssl /usr/bin/openssl

damit fertig.

openssl version

sollte dann 1.1.1 ausgeben