Wenn der persönliche Kalender und das persönliche Adressbuch nicht in der Cloud von Goolge, Apple und Co. landen soll, muss ein privater CardDAV-Server her. Dazu bieten sich unterschiedliche Möglichkeiten an. Nach einigen Tests bin ich mit DAViCal bei einem privaten CardDAV Server auf dem Raspberry Pi gelandet.

00| Warum DAViCal?

Ich habe mich für DAViCAl entschieden, da dieser Server im Gegensatz zu anderen CalDAV-Servern wie z.B. Baïkal mit DAViCal auch Berechtigungen auf Kalender und Adressbücher vergeben werden können. So kann man auch Kalender/Adressbücher einrichten, die von mehreren User benutzt werden.

Außerdem arbeitet DAViCal perfekt mit dem Web-Frontend InfCloud zusammen, so dass die Termine und Kontakte auch über ein Web-Frontend verwaltet werden können.

Anmerkung: Im Tutorial gehe ich davon aus, dass der Raspberry Pi unter der IP-Adresse 192.168.0.10 erreichbar ist. Die muss natürlich im folgenden ggf. angepasst werden.

01| Pakete installieren und lighttpd vorbereiten

In der Regel wird DAViCAl zusammen mit Apache verwendet. Um Ressourcen zu sparen habe ich mich jedoch für den schlankeren Web-Server lighttpd entschieden. Also werden zunächst folgende Pakete installiert:

apt-get update
apt-get upgrade
apt-get install lighttpd davical php5-cgi

Danach werden die entsprechenden Module im lighttpd aktiviert und ein Link Web-Root erstellt, der DAViCal für lighttpd verfügbar macht:

lighty-enable-mod accesslog fastcgi fastcgi-php simple-vhost ssl
ln -s /usr/share/davical/htdocs /var/www/caldav

DAViCal nutzt die Variable SERVER_NAME um die korrekte Konfigurationsdatei zu bestimmen (siehe auch unten). Daher muss die lighttpd-Konfiguration so angepasst werden, dass diese Variable auf jeden Fall gesetzt wird, auch wenn der Server über die IP-Adresse anstatt den Hostnamen aufgerufen wird. Daher müssen in der  Datei /etc/lighttpd/conf-available/10-simple-vhost.conf folgende Werte gesetzt:

simple-vhost.server-root = "/var/www"
simple-vhost.default-host = "192.168.0.10"
simple-vhost.document-root = ""

Die Konfiguration wird dann folgendermaßen aktiviert:

cd /etc/lighttpd
ln -s conf-available/10-simple-vhost.conf conf-enabled/10-simple-vhost.conf
service lighttpd force-reload

Zur einfacheren Einrichtung der Clients kann auch noch einige Redirects in der /etc/lighttpd/lighttpd.conf eingerichtet werden:

## Einige URL-Weiterleitungen zur einfachren Einrichtung von CalDav-Clients 

url.rewrite-once = (
  ## root URL nicht umschreiben, da ansonsten explizit /index.php 
  # eingegeben werden muss, für Admin-Zugriff
     "^\/caldav\/$" => "$0",

  ## .php, Stylesheets, Skripte und Bilder nicht umleiten.
     "^\/caldav\/.+\.(php|css|js|png|gif|jpg).*" => "$0",

  ## Rewrite for ?
     "^\/.well-known(.*)$" => "/caldav/caldav.php/.well-known$1",
  
  ## für iPhone
     "^\/principals\/users(.*)$" => "/caldav/caldav.php$1",

  ## Alles andere an caldav.php umleiten
     "^\/caldav\/(.+)" => "/caldav/caldav.php/$1"
)

Werden diese Änderungen vorgenommen, muss natürlich auch der lighttpd nochmal neu gestartet werden.

02| Datenbank einrichten

Da DAViCal auf Postgres aufsetzt muss zunächst die Datenbank eingerichtet werden. Dazu werden als erstes zwei neue Benutzer erstellt:

su postgres -c "createuser davical_app"
su postgres -c "createuser davical_dba"

In der Konfigurationsdatei /etc/postgresql/9.X/main/pg_hba.conf muss diesen Benutzern noch der Zugriff auf die Datenbank durch folgende Einträge ermöglicht werden:

local	davical	davical_dba 		trust
local	davical	davical_app		trust

Anschließend wird Postgres neu gestartet und die DAViCal-Datenbank erstellt und der Server nochmal gestartet werden:

/etc/init.d/postgresql restart
su postgres -c /usr/share/davical/dba/create-database.sh
/etc/init.d/postgresql restart
Wichtig: Bei der Einrichtung wird der Benutzer “admin” mit einem zufälligen Passwort angelegt und die Zugangsdaten werden nach der Einrichtung der Datenbank angezeigt. Dieser Benutzer wird später gebraucht, um über das DAViCal-Web-Frontend die Benutzer und Ressourcen zu verwalten.

Falls bei der Einrichtung der Datenbank was fehlschlagen sollte und der Benutzer nicht angezeigt werden sollte. kann eine halb eingerichtete Datenbank mit folgenden Kommandos wieder gelöscht werden:

su - postgres
dropdb davical

03| Konfiguration von DAViCal

Im Verzeichnis /etc/davical wird die Datei localhost-conf.php mit folgenden Inhalt angelegt:

<?php
//  $c->domain_name = "calendar.example.net";
//  $c->enable_row_linking = true;

  $c->sysabbr     = 'DAViCal';
  $c->admin_email = 'admin@example.net';
  $c->system_name = "DAViCal Server";
  $c->default_locale = de_DE.UTF-8;
  $c->pg_connect[] = 'dbname=davical port=5432 user=davical_app';
Anmerkung: Es ist hier laut DAViCal-Anleitung korrekt, dass das schließende ?> nicht mit angegeben wird.

Jetzt ist es wichtig das für alle Server-Namen unter denen der Server angesprochen werden soll eine entsprechende Konfiguration existiert. Am einfachsten werden dazu ein paar Links angelegt:

cd /etc/davical
ln -s localhost-conf.php 192.168.0.10-conf.php
ln -s localhost-conf.php <server-name1>-conf.php
ln -s localhost-conf.php <server-name2>-conf.php
[...]

Nun ist eigentlich alles bereit für den ersten Zugriff auf das DAViCal-Admin-Backend unter http://192.168.0.10/caldav/.

Zur Anmeldung benötigt man nun das Passwort für den admin-User von oben. Sollte man es nicht notiert haben, kann es wie folgt nochmal abgerufen werden:

su - postgres
psql davical -c 'select username, password from usr;'

Funktioniert der Login, so sollte als erstes das Admin-Passwort gewechselt werden, damit es nicht mehr im Klartext in der Datenbank gespeichert ist.

Klappt die Anmeldung, so können nun Benutzer und Ressourcen angelegt und Berechtigungen vergeben werden. Eine Beschreibung wie DAViCal nun zu bedienen ist erspare ich mir an dieser Stelle. Entsprechende Hinweise gibt es auf der DAViCal-Seite ausreichend.

Wurden User und Kalender angelegt, so kann jetzt bereits versucht werden auf die Installation zuzugreifen (z. B. per Handy oder Sunbird). Wurden die Weiterleitungen zur Vereinfachung eingetragen so sollte in der Regel 192.168.0.10/caldav/ als URL bei der einrichtung ausreichen. Ggf. kann aber auch ein 192.168.0.10/caldav/caldav.php erforderlich sein.

04| Web-Frontend einrichten

Der Zugriff auf die Kalender und Adressbücher ist im DAViCal-Backend nicht möglich. Soll auch per Web-Browser auf den Kalender zugegriffen werden, so muss ein entsprechender Web-Client installiert werden. Hier bietet sich InfCloud an, der sehr gut mit DAViCal zusammenarbeitet:

cd /var/www
wget https://www.inf-it.com/InfCloud_x.yy.z.zip
unzip InfCloud*.zip
mv infcloud/* .
rm -r infcloud
rm InfCloud*.zip

Nun muss die Konfiguration ein wenig angepasst werden, damit InfCloud auch korrekt auf DAViCal zugreift:

cp config.js config.orig.js
cat config.orig.js | sed "s/'\/caldav\.php\/'/\/caldav\/caldav.php\//g" | sed "s/Language='en_US'/Language='de_DE'/" > config.js
./cache_update.sh

Danach sollte eine Anmeldung am Web-Frontend http://192.168.0.10. Damit sollten dann auch die Kalender- und Adressbuchinhalte verwaltet werden können. Zur Anmeldung wird dabei der Benutzername und das Passwort des DAViCal-Users verwendet.

Eigentlich ist die Installation nun abgeschlossen. Allerdings kann bis jetzt nur unverschlüsselt auf den CalDav-Server zugegriffen werden. Daher wird im folgenden Schritt auch noch das SSL für lighttpd eingerichtet.

05| SSL einrichten

Damit SSL überhaupt aktiviert werden kann muss erstmal geprüft werden ob Lighttpd überhaupt SSL unterstützt:

/usr/sbin/lighttpd -v
lighttpd/1.4.31 (ssl) - a light and fast webserver
Build-Date: Mar 13 2014 05:17:02

Sieht die Ausgabe in etwa so aus wie oben (ssl), dann kann es mit der Konfiguration von SSL/TLS weitergehen. Ansonsten muss erst eine andere Version von lighttpd installiert werden.

Zunächst muss ein Schlüssel und ein Zertifikat erstellt werden. Ich verwende für die Schlüsselverwaltung XCA und habe das Vorgehen in einem eigenen Artikel beschrieben: Private CA für interne Web-Server erstellen.

Für lighttpd muss der private Schlüssel und das zugehörige Zertifikat in einer Datei vorliegen. Der Schlüsselaustausch kann dabei am Besten per Zwischenablage erfolgen. Also beispielsweise die Datei mit dem Kommando nano /etc/lighttpd/ssl/server-key-pub.pem  anlegen. Dann wird zuerst der private Schlüssel aus XCA per Zwischenablage im PEM-Format kopieren und in die Datei eingefügt. Danach wird dann das Server-Zertifikat auf die gleiche Weise übertragen und an das Ende der Datei angehängt und die Datei gespeichert. Anschließend müssen die Berechtigungen für die Datei noch korrekt gesetzt werden:

chown root:root /etc/lighttpd/ssl/server-key.pem
chmod 400 /etc/lighttpd/ssl/server-key.pem

Zusätzlich müssen auch noch die CA-Zertifikate in eine Datei geschrieben werden. Hier müssen alle Zertifikate der CAs in eine Datei geschrieben werden. Bei mir ist das meine Root CA  und zusätzlich auch die Zwischen-CA, mit der ich meine Server-Zertifikate ausstelle. Auch diese Datei wird am einfachsten per nano /etc/ssl/certs/myca.pem und über die Zwischenablage befüllt. Ich habe zunächst die Root CA und anschließend meine Server CA im PEM-Format in die Datei geschrieben und habe danach wieder die Berechtigungen angepasst:

chown root:root /etc/ssl/certs/ca-root.pem
chmod 644 /etc/ssl/certs/ca-root.pem

Wenn DH-Suiten verwendet werden sollen mit einer Schlüssellänge > 1024 Bit, dann ist zusätzlich noch ein DH-File zu erzeugen:

openssl dhparam -out dh4096.pem -outform PEM -2 4096

Das Kommando erzeugt einen File für 4096 Bit. Sollten 2048-Bit ausreichen so kann das Kommando entsprechend angepasst werden. Ich empfehle das Kommando auf einem System mit mehr Rechenleistung auszuführen und die Datei anschließend zu kopieren, da der Raspberry bei der Erstellung einiges zu rechnen hat.

Nun sind alle Dateien auf dem Raspberry vorhanden und die SSL-Konfiguration in der Datei /etc/lighttpd/conf-available/10-ssl.conf  kann angepasst werden.

Bei der SSL-Konfiguration ist vor allem die Wahl der Cipher-Suiten entscheidend für die Sicherheit. Wird hier allerdings zu strikt vorgegangen, dann können einige Clients sich nicht mehr verbinden. Ich habe dabei die besten Erfahrungen mit der Empfehlung von BetterCrypto.org gemacht. Die dort empfohlene Cipher-Liste habe ich noch etwas gekürzt und entsprechend in die Konfiguration aufgenommen:

# /usr/share/doc/lighttpd/ssl.txt

$SERVER["socket"] == "0.0.0.0:443" {
        ssl.engine  = "enable"
        ssl.use-sslv2 = "disable"
        ssl.use-sslv3 = "disable"
        ssl.pemfile = "/etc/lighttpd/ssl/pi2.klein-gedruckt.local_key_crt.pem"
        ssl.ca-file = "/etc/ssl/certs/ca.klein-gedruckt.local.pem"

        # Standard Lighttpd Cipher-Liste
        # ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM"
		
        # Angepasst auf Basis der Empfehlungen von BetterCrypto.org
        ssl.cipher-list = "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"

        ssl.honor-cipher-order = "enable"
        ssl.disable-client-renegotiation = "enable"
        ssl.dh-file = "/etc/lighttpd/ssl/dh4096.pem"
        ssl.ec-curve = "secp384r1"

        setenv.add-response-header = ( "Strict-Transport-Security" => "max-age=15768000") # six months
        # use this only if all subdomains support HTTPS!
        # setenv.add-response-header = ( "Strict-Transport-Security" => "max-age=15768000; includeSubDomains")
}

Jetzt muss die SSL-Konfiguration noch aktiviert und der lighttpd server neu gestartet werden:

ln -s /etc/lighttpd/conf-available/10-ssl.conf /etc/lighttpd/conf-enabled/10-ssl.conf
service lighttpd restart

Ist danach der lighttpd gestartet und können sowohl DAViCal als auch InfCloud per SSL/TLS aufgerufen werden, dann kann lighttpd so konfiguriert werden, dass alle unverschlüsselten Aufrufe auf HTTPS umgeleitet werden:

$HTTP["scheme"] == "http" {
	# capture vhost name with regex condition -> %0 in redirect pattern
	# must be the most inner block to the redirect rule
	$HTTP["host"] =~ ".*" {
		url.redirect = (".*" => "https://%0$0")
	}

	# Set the environment variable properly
	setenv.add-environment = (
		"HTTPS" => "on"
	)
}

06| Clients einrichten

Die Einrichtung der Clients ist immer etwas unterschiedlich. Auf der DAViCal-Seite gibt es eine recht ausführliche Anleitung zur Einrichtung unterschiedlicher Clients.

Bei Lightning ist es zum Beispiel wichtig, dass in der Kalender-URL direkt auf den Kalender verwiesen wird (z.B. https://192.168.0.10/caldav/caldav.php/username/calendar/). Dabei muss für jeden freigegebenen Kalender eine eigene URL in Lightning eingerichtet werden.

CalDav-Sync ist da etwas weniger wählerisch. Hier reicht die Angabe der URL zur DAViCal-Installation (z.B. https://192.168.0.10/caldav/). CalDav-Sync Android ermittelt dann automatisch welche Kalender für den Benutzer verfügbar sind.

[appbox googleplay org.dmfs.caldav.lib]