One of the many, many possible uses of a Raspberry Pi is synchronizing contacts and events between clients using the CalDav and CardDav standards.

There’s a plethora of available server applications to choose from:

My choice fell on Baïkal because of the support for SQLite and Nginx, so I would not have to install and maintain a full-blown database software. I like, how lightweight and simple the resulting system becomes.

As I’m using Arch Linux for all my Raspberry Pi needs the commands as well as the package names are going to be specific to Arch. I see that most Raspberries run Debian-based system, so you might actually get away by just replacing all occurrences of # pacman -S [package] with # apt-get install [package].

This tutorial also assumes you have a own domain name and are able to set and change DNS entries. You technically can use all described techniques described here only with IP addresses. I am going to only describe the domain way in here.

Security considerations

Edward Snowden aside, it is generally considered good practice not to transmit sensitive data (like contacts) in the clear. And, since I am going to set up quite a few services that make use of encryption in the near future the extra effort to create a CA pays off.

Out of sheer laziness, I prefer to use a GUI (like gnoMint or xca) to manage all the certificate and key management. But actual knowledge what the GUI is exactly doing won’t hurt either.

Generating the actual CA and the Server Certificate can be seen at the xca documentation.

After that, you should end up with the following files:

  • ca.crt

    This certificate establishes trust between your devices and the server. You are going to install this certificate onto your phones and computers.

  • server.crt

    This is the front facing part of your encryption setup. The common name field should contain the host and domain name your Pi is going to listen to, or alternatively the IP address.

  • server.key

    Private Server key. Do securely transmit this file to your server using SSH and make sure the file permissions allow access by the file owner only by removing all rights (read, write, execute) from group and other section: $ chmod go-rwx server.key.


The basic layout consists of three components: NGINX, PHP-FPM and Baïkal.

nginx (pronounced: Engine X) is a reverse proxy. Basically what it does, it speaks HTTP very well. It acts as front end and dispatches incoming requests to the PHP pool and responds with the answer while also taking care of the SSL stuff.

The PHP-FPM provides a PHP execution pool in which Baïkal is going to run.

Component overview

Essential files

  • /etc/nginx/vservers/baikal.nginx

  • /etc/php/php-fpm.conf

  • /etc/php/php.ini


Installing nginx is easily done with: # pacman -S nginx.

I like to separate the configurations for the different services so we remove the entire server { … } section from /etc/nginx/nginx.conf and append include vservers/*.nginx; as last line inside of the http section.

Next we create the vserver subdirectory using: # mkdir -p /etc/nginx/vserver.


Now, that nginx also serves requests for instances defined in the vserver directory we can define the settings for Baïkal by pasting the following into baikal.nginx in /etc/nginx/vservers/:

server {
    listen       [::]:443 ssl;
    server_name  yourdomain.tld;

    root  /usr/share/nginx/baikal/html;
    index index.php;

    ssl_certificate      server.crt;
    ssl_certificate_key  server.key;

    ssl_session_timeout  5m;

    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers  HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers   on;

    rewrite ^/.well-known/caldav /cal.php redirect;
    rewrite ^/.well-known/carddav /card.php redirect;

    charset utf-8;

    location ~ /(\.ht|Core|Specific) {
        deny all;
        return 404;

    location ~ ^(.+\.php)(.*)$ {
        fastcgi_index index.php;
        include        fastcgi_params;

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;

The [::] on the second line forces nginx to listen only for incoming IPv6 connections - you can omit if you wish to allow IPv4 connections.

Because the server block gets included into the nginx.conf, you have to place the .crt and .key files relative to it, into /etc/nginx/ !

Of course you’d have to alter the server name and ssl certificate directives.

Then we need to restart the nginx server with # systemctl restart nginx to apply our configuration changes. While we’re at it, we tell systemd to automatically start the nginx service on system boot using # systemctl enable nginx.


As with nginx, installing PHP is a piece of cake: # pacman -S php-fpm.

Socket for PHP NGINX communication.

In order to establish the connection between the PHP parser and the reverse Proxy we have to uncomment the localhost socket ( in /etc/php/php-fpm.conf like so:

listen =
;listen = /run/php-fpm/php-fpm.sock


Next we install the PHP-SQLite extension using # pacman -S php-sqlite and enable the extension by uncommenting the corresponding line in /etc/php/php.ini:

DNS Setup

In this step we are going to setup DNS entries pointing to your Baïkal installation. There should already be AAAA or A type entries pointing to your RPI’s IP address. If not, create them!

We also are going to need a CNAME type entry dav.yourdomain.tld pointing to the host entry (AAAA or A), for nginx match requests to this entry belonging to the Baïkal server entry.

While you are editing DNS entries we also add TXT entries to improve service discoverability for your clients:

_caldavs._tcp.yourdomain.tld 0 5 443 dav.yourdomain.tld
_carddavs._tcp.yourdomain.tld 0 5 443 dav.yourdomain.tld

Please do change all occurrences of yourdomain.tld in this section to match your own domain!


Now, that we have laid the groundwork we can begin to install Baïkal by downloading the latest regular package: $ wget

We then, unpack the archive using $ tar xf baikal-regular-0.2.7.tgz and move it into place using # mv baikal-regular /usr/share/nginx/baikal.

Now navigate to the setup utility using your web browser by entering the domain you set as server name in the baikal.nginx file and the CNAME and follow the instructions on the screen.

Accessing the administration interface

As a security feature Baïkal automatically locks down the entire administration interface, even from within the local network. To re-enable it we type the following line: # touch /usr/share/nginx/baikal/Specific/ENABLE_ADMIN.

Then create a user account for yourself to use and its corresponding address books and calendars.


For Android I recommend using DAVDroid. Though, it is obtainable from F-Droid for free, I suggest you buy it from Google Play to support the developer. Brave folks also can compile it themselves from Source (GPLv3).

Alternatively there’s CardDAV-Sync which does also work, but isn’t open source.

Installing CA

First of all, we have to install our CA. For that there is an annoying non-root and a clean root-requiring solution.

We can check if everything is working fine by browsing to the baikal installation:

Screenshot: Browser showing Baikal with working SSL

Because we have set up the well-known redirections, we are now able to just enter your domain (e.g. yourdomain.tld) and all available calendars and address books are automatically found.


On Linux there’s support for CardDAV and CalDAV via Evolution.

Screenshot: CardDav setup

Screenshot: CalDav setup

Once you have set up Evolution, you can access that data from all kind of third-party applications that support the EDS backend as data source. I for example use California and Contacts.


OSX 10.6.8 will fight synchronisation of PIM data by any means. I got it to sync by editing .plist files. It ended up removing attributes from my contacts after Adium tried to update the pictures. If anyone knows to fix this without updating to 10.7 please do let me know.

Things to do

The synchronisation of Tasks is currently under development and DAVDroid will be a supported backend for Mirakel. Alternatively, you can also try the already patched version.