Selfhosted Mail-Server mit Kolab 3.1 und Centos 6.5

Schon immer wollte ich meine Mails, Kontakte und Termine auf einem Server zusammenführen und von überall zugänglich machen ohne Google oder Microsoft dabei mehr als nötig zu vertrauen – etwas das durch die Nachrichten der letzten Monate nur vernünftiger erscheint.

Ich habe verschiedene Optionen abgewogen, vom Shared-Hoster und vServer über ein modifiziertes NAS bis zum eigenständigen Server. Auch mit verschiedenen Linux-Distris hab ich experimentiert und viel gegoogelt. Natürlich gibt es Kompromisse zu schließen und mein Setup passt nicht automatisch für jeden, aber ich hoffe, einige Anregungen geben zu können.

Warum ein eigener Server?
Vorteile sind, die Daten liegen bei mir und nicht in einem anonymen Cloud-Rechenzentrum, ich habe die Kontrolle über den Rechner und habe gleichzeitig ein NAS für die im Haushalt benötigten Daten und Medien. Nachteil: Mit einem Consumer-DSL ohne fester IP-Adresse muss ich die Mails weiter über einen Mail-Provider abholen und einliefern. Da ich FTTH-Glasfaser hab, ist die Upload-Geschwindigkeit nicht so das Problem.

Meine Wahl des Servers viel auf ein Shuttle DS47 Barebone, das mit 8 GB SODIMM-Speicher und einer 60 GB mSATA SSD zu einem einigermaßen günstigen kompletten Rechner wird. Der Stromverbrauch liegt bei etwa 12 Watt und da der Rechner keinen Lüfter hat ist er absolut Wohnzimmer-tauglich. Mit einer 2,5“-Festplatte (Achtung nur 7 mm hohe passen so, dass auch der Deckel noch zu geht) sind NAS, Backups und ein Medienserver ebenfalls abgedeckt, dazu später mehr.

Kolab 3.1 ist die Groupware der Wahl, sie deckt im Webclient Roundcube Mail, Kontakte, Termine und Aufgaben ab. Das ganze basiert auf einem für meine Zwecke etwas überdimensionierten LDAP-Server, IMAP als Speicherort, postfix als MTA, mySQL und Apache, hat mit Chwala eine kleine Cloud-Lösung und ist soweit Exchange-kompatibel.

Warum Kolab und Centos?
Es gibt noch andere gute freie Groupware-Lösungen. Wichtig war mir eine Exchange Active Sync-Unterstützung und dass viele Standard-Komponenten verwendet werden.
Centos ist die freie Version von Red Hat Enterprise Linux (RHEL); ihm fehlt zwar jeder Schnickschnack aber Version 6 wird dafür bis 2019 unterstützt - das will man eigentlich auch für einen Server. Viele Pakete sind nicht in der letzten Version, allerdings werden Security- und Bugfixes von Red Hat in die gelieferten Versionen zurückportiert.

Installation

Das Shuttle Barebone ist schnell ausgepackt, die unnötige WLAN-Karte ausgebaut, und angeschlossen, das BIOS hab ich mit einem mit Freedos bootbaren USB-Stick auf die aktuelle Version 104 aktualisiert. Im BIOS noch ein paar Einstellungen vorgenommen – im Wesentlichen alles ausgeschaltet, was ich nicht brauche und die Boot-Reihenfolge angepasst sowie den mSATA-Port auf SSD gestellt.

Centos 6.4 war etwas zickiger zu installieren, mit UNetbootin habe ich sehr komfortabel einen bootbaren USB-Stick erstellt (mit Centos 6.5 reicht ein dd auf einem Linux-Rechner), das booten hat auch wunderbar geklappt, aber der Centos-Installer hat dann den Stick von dem er startete nicht zur Installation verwenden wollen. Da man aber als Quelle auch eine URL angeben kann und die DVDs auf den Distributions-Servern liegen, hab ich einfach „übers Internet“ installiert, hoffentlich ohne mir dabei was einzufangen… Ich hab mich mit dem Minimal Server begnügt um alles was installiert wird unter Kontrolle zu haben. Centos startet des LAN-Interface nicht automatisch, das wars erst mal mit der Konfiguration. Da der Server ohne Tastatur und Monitor „headless“ läuft und ich mich nur per SSH mit putty auf dem Server einlogge, um zu administrieren, benutze ich dafür den root-Account, „normale“ Benutzer gibt es auf dem Server genauso wenig wie eine grafische Oberfläche. Üben (und theoretisch den Server auf bestehender Hardware zu hosten) kann man problemlos mit dem in Windows 8 enthaltenen HyperV (Centos bringt dafür Treiber mit) oder jeder anderen Virtualisierungslösung.

Nach einem # yum update um das System auf den aktuellen Stand zu bringen geht es zu den Vorbereitungen der Kolab-Installation. Dafür ist v.a. SELinux permissive zu schalten und die IPTables-Firewall anzupassen sowie zu kontrollieren, dass der FQDN konsistent ist. Wer eine Fritzbox benutzt (genauer gesagt, deren DHCP- und DNS-Server, theoretisch könnte das der neue Server natürlich selbst übernehmen, aber diese Herausforderung hebe ich mir für nächstes Mal auf), hat keine Wahl (jedenfalls hab ich keine gefunden), die Domain heißt dann fritz.box, so dass der FQDN meines Servers server.fritz.box ist (siehe auch weiter unten). Für einen Server mit fester IP-Adresse und eigener Domain würde man natürlich diese hier angeben. Hier die Anleitung. Schließlich werden die Kolab-Repos yum bekannt gemacht. Hier die Anleitung. # yum install kolab spült alles Nötige für die Kolab-Installation auf die Platte. Das Script # setup-kolab richtet Kolab ein – hoffentlich ohne größere Fehler (einige Meldungen über nicht gestartete/startende Dienste kann man ignorieren), wenn da was schief geht hat man wohl verloren, das Script bis auf wenige Ausnahmen nur für die erstmalige Einrichtung geeignet und kann nicht mehrfach ausgeführt werden. Hier hat es aber problemlos geklappt, wichtig ist, die Ausgabe des Scripts aus SSH rauszukopieren und abzuspeichern, darin stehen alle Passwörter (für LDAP, mySQL, postfix und kolab), die man gelegentlich doch mal braucht. Wichtig ist. Dass die Domäne stimmt, als einzige Eingabe musste ich die Zeitzone mit Europe/Berlin machen.

Das Script informiert einen auch, dass man die mySQL-Installation absichern soll, dazu führt man das Script # /usr/bin/mysql_secure_installation aus. Generell startet das Installations-Script nicht alle Dienste zuverlässig, ein Reboot mit # reboot kann hier Wunder wirken und man sieht gleich, ob auch alles wieder hochkommt.

Kolab Webadmin

Der erste Weg führt nun mit einem Web-Browser zur URL http://server/kolab-webadmin. Dort meldet man sich mit dn=Directory Manager und dem Passwort aus dem Kolab-Installationsscript an. Unter Users legt man nun den ersten Benutzer an, den man auch die Manager-Rolle geben kann, damit man sich nicht immer mit dem DM anmelden muss. Die Haupt-Mailadresse ist dann @fritz.box, die in der deutschen Übersetzung etwas unglücklich zwei Mal als Sekundäre Mailadressen bezeichneten Felder nehmen interne und externe Aliase auf, dazu gleich mehr.

Jetzt erst mal ausprobieren, ob man sich mit dem neuen Benutzer an Roundcube anmelden kann, die URL lautet http://server/roundcubemail. Nach dem Login sollte die Web-Oberfläche erscheinen.

Bei Problemen führt der erste Weg in das Verzeichnis //var/log, wo alles fleißig Log-Files schreibt und man hoffentlich einen Hinweis findet. Beliebt sind Fehler in der Firewall-Konfiguration (einfach mit # service iptables stop ausschalten und nochmal probieren), der Apache-Konfiguration (mal im Verzeichnis httpd nachsehen) oder einem der Dienste.

Mails einsammeln und abliefern

Damit man Mails auf seinen neuen Server bekommt, muss ein Mail-Sammeldienst eingerichtet werden (wie oben dargestellt ist es nur mit einer festen IP-Adresse möglich, sich diese vom Absender direkt einliefern zu lassen, das würde Kolab standardmäßig einrichten, aber auch dann kann es Sinn machen, Mais aus all den benutzten Maildiensten abzuholen). Es gibt ein Roundcube fetchmail-Plugin, das das macht, damit habe ich aber keine Erfahrung. Stattdessen habe ich fetchmail eingerichtet, was - wenn man weiß wie - recht einfach funktioniert. # yum install fetchmail und eine Datei /etc/fetchmailrc.conf ist alles was es braucht, für erste Versuche eventuell das Löschen der Mails auf dem Server abstellen. Jetzt sollten in Roundcube auch erste (Test-)Mails auftauchen.

Da auch das Versenden von Mails ohne feste IP-Adresse und vernünftig gemanagten MX-DNS-Einträgen nicht möglich ist, muss die Mail bei gmail&Co zum Versand eingeliefert werden. Dazu muss die Mail-Adresse einmal in der Webadmin-Oberfläche zum anderen in den postfix-Innereien konfiguriert werden und postfix verklickert, dass Mails in Zukunft abhängig von der Absender-Adresse bei unterschiedlichen Diensten abgeliefert werden müssen. Seit Centos 6.5 mit aktiviertem ECDHE gibt es Probleme mit homtail.com/live.com, die ich versuche mit einer tls_policy-Datei zu lösen...

NAS und Medienserver

Darüber hinaus habe ich (etwas größenwahnsinnig) Samba 4 eingerichtet, um von meinen Windows-PCs aus auf das „NAS“ zugreifen zu können und alle Fotos, Musik und Filme auf die Server-Platte verlagert. Mit minidlna mache ich die Musik für die Webradios in der Wohnung zugänglich (die Installation unter Centos ist etwas umständlich und es gibt nur eine recht alte Version); auch die Filme für das TV. Audio des Servers ist an die Stereo-Anlage angeschlossen, mit den Alsa-Tools hab ich die Ausgabe freigeschaltet und mit dem mpd-Dienst kann ich die Musik abspielen – über ein Web-Client wie netjukebox (hier gefällt mir allerdings nicht, dass nur die Filenamen ausgewertet werden und nicht die liebevoll gepflegten ID3-Tags, da bin ich noch am Basteln) von jedem PC oder Handy aus gesteuert – sogar aufs Handy gestreamt wenn ich das möchte.

minidlna loggt eine Warnung: inotify.c:206: warn: WARNING: Inotify max_user_watches [8192] is low or close to the number of used watches [1082] and I do not have permission to increase this limit. Please do so manually by writing a higher value into /proc/sys/fs/inotify/max_user_watches die mit # sysctl -w fs.inotify.max_user_watches=100000 schnell behoben ist.

Backup und Monitoring

Eine über USB3 angeschlossene Platte dient als Backup, sowie die Offline-Ordner-Funktionalität von Windows, Mondo Rescue erstellt wöchentlich ein bootfähiges iso und rsync täglich ein differentielles und über Hardlinks platzsparendes Backup. Da ich um 3 Uhr früh keine Verfügbarkeit garantieren muss, fahre ich alle Dienste per Script runter, mache das Backup, und fahre die Dienste wieder hoch (andernfalls kann es gut sein, dass die mySQL-Datenbank oder die IMAP-Store in einem inkonsistenten Zustand gesichert wird). Die Platten überwache ich mit smartctl.

Um die Uhr des Servers zu stellen, wurde ein ntp-Client eingerichtet. Monit übernimmt das Monitoring des Systems, über eine Webseite kann ich (solange der Apache läuft und DynDNS funktioniert, gut auch für meinen Geschmack etwas viele Bedingungen) immer sehen, ob alles läuft, Fehler geloggt werden oder Systemressourcen knapp werden; Dienste werden sogar automatisch neu gestartet oder DynDNS angepingt, wenn die Fritzbox das mal nicht macht.

https

Natürlich soll man von außen nicht per http sondern verschlüsselt mit https auf die Webmail zugreifen. Der offizielle Weg führt über dieses Script. Das kannte ich nicht und brauche ich nicht, da ich nur im lokalen Netzwerk mit was anderem als https auf den Server zugreife. Dazu wird der Apache so konfiguriert, dass zum einen bestimmte Sachen von außen gar nicht erreichbar sind, oder von außen ggf. ein Passwort erfordern und vor allem nur über https erreichbar sind. Aus dem eigenen Netzwerk dagegen habe ich keine Einschränkungen eingerichtet. Da bereits mod_nss statt mod_ssl aktiviert war, hab ich dies benutzt.

DynDNS mit selfhost.de
DynDNS als kostenloser Dienst ist ziemlich tot, aber es gibt noch genügend andere Anbieter um eine feste URL auf eine dynamische IP-Adresse zu lenken (für Mail reicht das aber nicht!). Ich habe bei selfhost.de eine zufällige URL auf meinen DSL-Anschluss umgeleitet, die Fritzbox aktualisiert automatisch und monit überwacht, dass das auch klappt (siehe monit-Scripts).

  Erster Schritt ist in /etc/httpd/conf.d/nss.conf anzupassen, statt Port 8443 nehme ich 443, das wird also (mehrfach) ersetzt. Dann werden die die Zeile mit NSSCipherSuite für die Elliptical Curve Cryptography aktiviert (und die darüber deaktiviert) und schließlich der Zertifikats-Spitzname kontrolliert oder gesetzt: NSSNickname Dyn-Server-Cert.

# certutil -D -n "Dyn-Server-Cert" -d /etc/httpd/alias/ # altes Zertifikat löschen
# certutil -S -n "Dyn-Server-Cert" -s "CN=k---.selfhost.eu" -c "cacert" -t "u,u,u" -m 1008 -v 120 -d /etc/httpd/alias/ -8 "k---.selfhost.eu,server.fritz.box,server"
# -m hochzählen!!!!

Als Alternate Name gebe ich zusätzlich den lokalen Namen des Servers an, damit lokal auch https://server funktioniert. Natürlich ist das kein Zertifikat, das von einer gültigen Stammzertifizierungsstelle stammt, sondern self-signed, aber für meine Zwecke reicht das.