How to create a Calendar and Adressbook Server ‑ Baïkal

This article concentrates on setting up a calendar server on an already running nginx server and importing existing content into the newly created empty calendar / address book, ready for syncing across devices.

Initial situation

I rely a lot on my digital calendar, but currently it resides on my ungoogled phone only (through Offline Calendar). I would like to sync it with my desktop computer.

I already run a web server and quickly came to the conclusion that the best solution is to serve the calendar myself. (Windows/Apple users have a few locally syncing apps to choose from, but my desktop runs GNU/Linux.)
Plenty of material exists, both software and articles, though I noticed that the heyday of setting up your own calendar server seems to be over. Judging from commit histories, prime time seems to have ended around 3 years ago. Apparently nowadays everybody has accepted Google's offerings, and the few who haven't use OwnCloud/NextCloud, which includes a CalDAV server as well. Not me though (mostly because I don't believe my single core laptop server could take a full *Cloud install).


You already have a server up & running, preferably debian stretch stable (but I'm sure these instructions can easily be adjusted to other systems). You are using an Android-based (e.g. LineageOS) smartphone without Google integration.

Go into your calendar app and export the calendar to an .ics file. Go into your address book (Contacts) and export your contacts to a single, large .vcf file.

Options Dismissed

  1. I already tried all this over a year ago with radicale, but a) it deliberately implements only a subset of the CalDAV specification (and I remember having trouble with that on my Android phone) and b) I blindly followed some tricky advice from the documentation (the useradd command) which later resulted in massive data loss. The latter was mostly my own fault, but still, I did not want to try radicale again.
  2. My email provider offers a syncable calendar. I managed to import my current calendar into it, but it was all wrong and wonky. This was already an old problem over a year ago (it goes way beyond the mentioned contact photos), but the situation has not changed at all.
  3. DAViCal looks like a solid, if dated, choice. What I like most: They recommend to install the debian package from the repos and have a walkthrough for that. Unfortunately it supports only CalDAV, not CardDAV.
  4. calendarserver appears to be an open-sourced Apple product they have been using on their own systems. I was intrigued by this promise of high quality software, but installation instructions are geared towards developers, not users, and compilation did not succeed on the first try, so I quickly abandoned that.
  5. syncEvolution - this one's in the debian stretch repos, too. But it requires "setting up an account on a SyncML server", which after a few minutes I gave up on figuring out what it even is. This seems to be a framework for website development rather than a standalone software.


Baïkal seems to be a frontend for sabre/dav which appears to be more active than any of the above mentioned software... I had to choose something in the end, and commit to the setup process, and this seemed a suitable candidate (so far I haven't been disappointed).

Reading the installation instructions I was pleased that it specifically mentions Nginx, but also confused by the very specific requirement of PHP 5.5. Not "at least", nor "at most". My server has been using PHP 7.0 exclusively for a while. Hmmm... That made me go search for some other tutorial. I did find one, and it helped me, but it was so bad otherwise that I decided not to link it.

Anyhow, Baïkal works just fine with PHP 7.0.

Installing Prerequisites

apt install mysql-server php-fpm php-mysql php-sabre-dav

Remember, you already have a web server running? If not you might want to install nginx also, or nginx-light like me.

Please check that php7.0-fpm is running OK and enabled to start at boot:

systemctl status php7.0-fpm
systemctl start php7.0-fpm
systemctl enable php7.0-fpm

Installing Baïkal

Get the latest baikal release - at the time of this writing it was 0.4.6, so:

curl -L https://github.com/sabre-io/Baikal/releases/download/0.4.6/baikal-0.4.6.zip > baikal.zip
unzip baikal.zip 
rm baikal.zip

You might need to change ownership of the installation to the user your server is running as, e.g.:

sudo chown -R www-data:www-data baikal

Setting Up a New Nginx Site

Set up a new nginx site that has its root pointing to the html subfolder in the baikal folder you just created. The default outlined here is fine, but I changed the port number (let's assume 4567) and I'm letting it run only on ssl (utilizing the same certificate as for this site).
Assuming you installed Baïkal to /var/www/baikal, the root directive should be root /var/www/baikal/html;. You also need to change fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; to fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;.

The whole site configuration now looks like this:

# CalDAV and CardDAV server { listen 4567 ssl; include ssl.conf; root /var/www/baikal/html; index index.php; rewrite ^/.well-known/caldav /dav.php redirect; rewrite ^/.well-known/carddav /dav.php redirect; charset utf-8; location ~ /(\.ht|Core|Specific) { deny all; return 404; } location ~ ^(.+\.php)(.*)$ { try_files $fastcgi_script_name =404; include /etc/nginx/fastcgi_params; fastcgi_split_path_info ^(.+\.php)(.*)$; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } }

Restart nginx, and navigate your browse to the newly created nginx site, let's assume it's https://mysite.com:4567. It works!

Creating the MySQL Database

Note: On debian stable MySQL has been replaced with MariaDB. You might experience some differences, but essentially it should just work as a drop-in replacement.

mysql -u root -p
> create database baikal;
> create user 'baikaluser'@'localhost' identified by 'very_secret_password';
> grant all on baikal.* to 'baikaluser'@'localhost';
> exit;

Configuring Baïkal

Navigate to https://mysite.com:4567/admin/install. This will start a setup wizard.

First screen:

  • You most likely need to change "WebDAV authentication type" to "Basic"

Second screen:

  • Even if you use MariaDB, check the mark that says "Use MySQL"
  • Enter the details for the user & database you created in the previous step

That's it! Can you log in (yes, you are "admin", and previously entered an "Admin password")? If not, maybe you didn't change the "WebDAV authentication type" to "Basic"?

If you need to re-run the setup wizard, go to /var/www/baikal/Specific (or wherever you installed it to), move the files config.php config.system.php INSTALL_DISABLED and start over.

We won't be adding data here, but from our phone instead. A Web UI is not what we came here for.

Syncing Existing Calendars and Address Books

Assuming you have those on your Android/LineageOS/etc. ungoogled phone.

First you will need to install DAVx^5 or some other software that allows your phone to sync calnedars etc. with a *DAV server. I strongly recommend DAVx^5, which is the award-winning DAVDroid's new name). You can find various links on this page, also to F-Droid, which I am using as my only app store.

Once installed, create a new account, check "Login with URL and user name". If I remember correctly I just entered the URL to the server root, in our example: https://mysite.com:4567, and DAVx^5 figured out the rest. Or maybe I entered https://mysite.com:4567/cal.php. If that shouldn't work either, or you're using different software, have a look at this article.

In any case, you should have a new, empty "Default Calendar" and "Default Address Book" now. In your Calendar/Contacts app, choose the Import option and import the previously exported local calendar / address book to the new CalDAV calendar / CardDAV address book. Now all your entries should be duplicated. This is the point when you can disable the local calendar / adress book.