This page provides details about setting up DAViCal (a CalDAV calendar and CardDAV contact sharing service) on Debian Linux - or, more precisely, on my personal Debian Linux server. Most of the information on this page can also be found, in one form or another, on the DAViCal website and the DAViCal wiki, but it was adapted from there to suit my personal needs (as is everything you find here on my personal HerzbubeWiki).

Disclaimer: There are no general purpose recipes on this page that you can just copy & paste without thinking. Information you find here may help you with setting up your own DAViCal instance, but please use your own judgment how you need to adapt things to your own environment.



On this wiki:


"Really Simple CalDAV Store". The original project name under which DAViCal was started.
Andrew's Web Libraries


Even though this page is about the CalDAV store DAViCal, I include a bit of research that I have made before deciding to go with DAViCal.

  • Q: Why use a CalDAV server instead of, for instance, the PHP based project WebCalendar?
  • A: WebCalendar exports .ics files, but CalDAV is server oriented

Other CalDAV servers:

  • These days there seem to be a number of viable OSS alternatives to DAViCal (e.g. ownCloud, SabreDAV, Baikal), but in 2009 when I did my original research the choices were rather limited. Most of the software that existed then was, if I recall correctly. out-of-date and no longer maintained, with the only possible exception of the Bedework CalDAV server.
  • A hopefully up-to-date comparison page can be found on Wikipedia

Other URLs:

Debian installation

Non-Debian APT source

Note: The information in this chapter is no longer accurate because DAViCal packages are now part of the official Debian distribution. I like to keep this chapter around for historical purposes, though.

DAViCal is available as a Debian package, but it must be installed from a non-Debian APT source. The first step is to tell APT to trust that source:

apt-key advanced --keyserver subkeys.pgp.net --recv-keys F6E0FA5CF0307507BB23A512EAFCFEBF8FEB8EBF

The PGP key ID to use can be found somewhere on the DAViCal website, usually the installation page.

Configure the new APT source by adding the following line to /etc/apt/sources.list:

deb http://debian.mcmillan.net.nz/debian lenny awm

Finally, run aptitude and update the update the list of available packages ("u")

Debian packages

Install the following Debian packages:


DAViCal requires PostgreSQL, so make sure that the following packages are also installed as dependencies of the DAViCal package. If this is not happening automatically, you will have to add them manually to the installation. I am mentioning this because once upon a time the DAViCal package dependencies were not so well set up and this used to be necessary.


PostgreSQL configuration

New database users

To grant the DAViCal service access to its database, a new database user must be created. The following command achieves this:

sudo -u postgres createuser --no-superuser --no-createdb --no-createrole --pwprompt --encrypted davical_app


  • sudo is necessary even if logged in as root, because the default configuration of PostgreSQL does not grant special privileges to root. The UNIX user postgres, however, is allowed to connect as the database super user (which "happens" to have the same name, postgres)
  • createuser is a wrapper around the SQL command "create role", which means that we should probably say that davical_app is the new database role (instead of the new database user)
  • --pwprompt prompts you for a password; --encrypted causes the password to be stored in the database in encrypted format. Use these two options only if you plan to use password authentication
  • --no-superuser etc.: The new role definitely is no super user. It only has minimal privileges, notably it does not have the right to create new databases, nor can it create new roles

In addition, DAViCal requires an administrative user for things such as database upgrades. This user is expected to be named davical_dba.

sudo -u postgres createuser  --no-superuser --no-createdb --no-createrole --pwprompt --encrypted davical_dba

Database user authentication

DAViCal needs to authenticate as the database user that was previously created. This is configured by adding an entry to


Information about this file is available here: http://www.postgresql.org/docs/8.4/interactive/auth-pg-hba-conf.html. Detail information about the various authentication methods is located here: http://www.postgresql.org/docs/8.4/interactive/auth-methods.html.

The DAViCal installation page suggests the following entry for a simple installation with no untrusted users on the system. The entry must be placed in front of the default access rule (which is listed here for clarity):

# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   davical         davical_app                             trust
local   all             postgres                                peer

Because of the "trust" authentication method, this entry allows anyone to connect to the davical database as the davical_app database user. Although I don't have a high-security environment, this is much too insecure for my taste. After all, every MySQL database application on my system already requires a password, so I want to have at least the same security for PostgreSQL. The entries I use therefore look like this (I need two entries becausem, of course, the DBA user also needs access):

local   davical         davical_dba                             md5
local   davical         davical_app                             md5

Note: The authentication method "md5" requires the client to supply an MD5-encrypted password for authentication. This is mainly of interest to address password sniffing if the client connects to the database over TCP/IP. Since in the current case DAViCal connects using Unix-domain sockets, it would probably be OK to use authentication method "password" (which allows the password to be transmitted in clear text).

Restart the database server to activate the new authentication rules:

/etc/init.d/postgresql-8.4 restart

A few additional notes regarding the question "trust or md5", or "am I too paranoid"?

  • The DAViCal rules are restricted to "local" connections, which means connections that are made va Unix domain socket
  • The important thing, therefore, is that the domain socket file is protected:
root@pelargir:/usr/share/davical/dba# l /var/run/postgresql/
total 8
drwxrwsr-x  3 postgres postgres 120 Jun 15 13:26 .
drwxr-xr-x 23 root     root     820 Jun 15 10:34 ..
drwxr-s---  2 postgres postgres 140 Jun 15 13:43 9.4-main.pg_stat_tmp
-rw-r--r--  1 postgres postgres   5 Jun 15 13:26 9.4-main.pid
srwxrwxrwx  1 postgres postgres   0 Jun 15 13:26 .s.PGSQL.5432
-rw-------  1 postgres postgres  70 Jun 15 13:26 .s.PGSQL.5432.lock
  • As you can see, the domain socket file is world-readable. That makes sense, after all every local process should be able to connect to the PostgreSQL server
  • But it also means that any regular non-privileged system user can log in and execute, for instance, the following command
psql --username davical_dba --dbname=davical -c '\d'
  • So the non-privileged user has full administrator access to the davical database!
  • I think it is now obvious that I am not overly paranoid when I insist on using "md5" instead of "trust"


When DAViCal is upgraded to a new version, it usually requires also that the database scheme is upgraded. DAViCal provides an upgrade script for that purpose. The upgrade script wants to work with the DBA role we created above, but the problem is that the script relies on a PostgreSQL access rule that provides "trust" access, i.e. a rule that does not require the user to specify a password.

The DAViCal wiki pages talk about storing the DBA password in a file named /etc/davical/administration.yml, but this doesn't seem to work, presumably because the upgrade script is poorly written.

So what happens when no "trust" access rule exists, and no password is provided? Simple: PostgreSQL interactively asks for the password. This in itself isn't too bad, the problem starts when the upgrade script needs to apply several patches to the database scheme: If this happens the script (or rather: PostgreSQL) will ask for the DBA password for each patch after the first.

The only way to prevent this is to store the password in the PostgreSQL password file .pgpass. Because the upgrade script is run as the "postgres" user, the password file must be stored in that user's home directory:


The .pgpass file's content looks like this:


The file must be protected like this:

root@pelargir:~# l /var/lib/postgresql/.pgpass 
-rw------- 1 postgres postgres 51 Jun 13 23:03 /var/lib/postgresql/.pgpass

New database

To create the new database for the DAViCal service, run the following command:

sudo -u postgres /usr/share/davical/dba/create-database.sh


  • As explained above in the "New database users" section, sudo is necessary
  • The create-database.sh script calls the AWL database scripts as part of itself and it expects them to be located in /usr/share/awl/dba. This path exists if the Debian package libawl-php is installed (which should be the case, it's a dependency of the davical package)
  • The script works with the DBA role, therefore the access rules in pg_hba.conf and the .pgpass file (explained in the two previous sections) must already be in place
  • The new database created by the script is called davical
  • When the script has finished, it prints the password that was automatically generated for the DAViCal administrator user "admin". Make a note of this!

DNS configuration

To allow DAViCal its own Apache virtual host (see next section), a new DNS name must be added. Add the following public CNAME:


Apache configuration

Although it appears to be possible to configure Apache so that DAViCal lives in a sub-location of an existing virtual host (e.g. under /davical), the best results (= those with the least trouble) are achieved when DAViCal has an entire virtual host for its own.

Therefore, edit the file


and add the following Virtual Host configuration. Note that we only define an SSL host because we want to completely disable non-https access (http connections to cal.herzbube.ch will be answered by the default vhost which forbids all access).

# --------------------------------------------------------------------------------
# cal.herzbube.ch
# --------------------------------------------------------------------------------
<VirtualHost *:80>
  ServerName cal.herzbube.ch
  Redirect permanent "/" "https://cal.herzbube.ch/"

# --------------------------------------------------------------------------------
# SSL Host
# --------------------------------------------------------------------------------
<VirtualHost *:443>
  ServerName cal.herzbube.ch
  ServerAdmin webmaster@herzbube.ch
  ErrorLog ${APACHE_LOG_DIR}/cal.herzbube.ch/error.log
  CustomLog ${APACHE_LOG_DIR}/cal.herzbube.ch/access.log combined

  DocumentRoot /usr/share/davical/htdocs
  Alias /robots.txt /var/www/cal.herzbube.ch/robots.txt

  DirectoryIndex index.php index.html
  Alias /images/ /usr/share/davical/htdocs/images/

  <Directory /usr/share/davical/htdocs/>
    AllowOverride None
    Require all granted
    php_admin_flag engine on

  php_value include_path /usr/share/awl/inc
  php_value magic_quotes_gpc 0
  php_value register_globals 0
  php_value error_reporting "E_ALL & ~E_NOTICE"
  php_value default_charset "utf-8"

  RewriteEngine On
  # Not if it's the root URL.  You might want to comment this out if you
  # want to use an explicit /index.php for getting to the admin pages.
  RewriteCond %{REQUEST_URI} !^/$
  # Not if it explicitly specifies a .php program, stylesheet or image
  RewriteCond %{REQUEST_URI} !\.(php|css|js|png|gif|jpg)
  # Everything else gets rewritten to /caldav.php/...
  RewriteRule ^(.*)$ /caldav.php$1  [NC,L]

  Include conf-available/pelargir-herzbube.ch-vhosts-ssl.conf

To activate the new virtual host:

mkdir /var/log/apache2/cal.herzbube.ch
a2ensite cal.herzbube.ch
apache2ctl restart

OpenLDAP configuration

To enable LDAP authentication for DAViCal, I make the following changes to the OpenLDAP configuration:

  • Add a new object class davicalAccount to /etc/ldap/schema/naef.schema (see OpenLDAP for details)
  • Augment those user accounts under ou=users,dc=herzbube,dc=ch with the new object class that should be allowed to login to DAViCal

DAViCal configuration

General configuration

The DAViCal configuration generally resides in


In my case the file is named


The configuration file is a regular PHP file which sets (or overrides) some specific variables. Various pages on the DAViCal wiki document different configuration aspects, but this is the main page.

The minimal configuration tells DAViCal how to connect to its database:

  $c->pg_connect[] = 'dbname=davical port=5432 user=davical_app password=secret';

Notice that the PHP tag (<?php) is not closed (?>).

A more complete configuration (i.e. the one I use) is this:

  $c->pg_connect[] = 'dbname=davical port=5432 user=davical_app password=secret';
  $c->system_name = "herzbube.ch CalDAV Server";
  $c->readonly_webdav_collections = true;
  $c->admin_email = "herzbube@herzbube.ch";


  • The LDAP authentication part is missing here and is discussed further down
  • readonly_webdav_collections: I'm not entirely sure what this does. The DAViCal wiki mentions that the default for this option is false for backwards compatibility, and that it may be desirable to set it to false during initial setup because it is supposed to make it easier for people to "convert their data". "After this it is recommended to turn it off so that clients which have been misconfigured are readily identifiable.". All this lets me assume that it's ok for me to set this option to true.

Securing the configuration

Because the configuration file contains one or more passwords, it must be secured so that it is not world-readable:

chmod 640 /etc/davical/cal.herzbube.ch-conf.php
chgrp www-data /etc/davical/cal.herzbube.ch-conf.php

LDAP authentication

Documentation for setting up LDAP authentication can be found here:

By default DAViCal authenticates its users against its own internal user/password list, which is stored in a table in DAViCal's PostgreSQL database. This can be changed by setting the following two configuration options:

$c->authenticate_hook['call'] = 'foo';
$c->authenticate_hook['config'] = array(

For authentication against LDAP, I add the following snippet to /etc/davical/cal.herzbube.ch-conf.php:

$c->authenticate_hook['call'] = 'LDAP_check';
$c->authenticate_hook['config'] = array(
  'host' => 'ldapi:///',

  // DN and password for initial bind
  // Note: Comment these out for anonymous initial bind
  'bindDN'=> 'cn=readonly-users,ou=users,dc=herzbube,dc=ch',
  'passDN'=> 'secret',

  // Version of LDAP protocol to use
  'protocolVersion' => '3',
  // Where to look for valid user
  'baseDNUsers'=> 'ou=users,dc=herzbube,dc=ch',
  // Only look at entries that match this filter
  'filterUsers' => 'objectClass=davicalAccount',
  // The next two options are not used at the moment and
  // can therefore remain commented out
//  'baseDNGroups' => 'ou=groups,dc=herzbube,dc=ch',
//  'filterGroups' => 'objectClass=groupOfUniqueNames',
  // Map DAViCal attributes (from database table "usr") to LDAP
  // attributes. Notes:
  // - "updated" must be set
  // - "modifyTimestamp" is an internal attribute of OpenLDAP
  'mapping_field' => array("username" => "uid",
                           "updated" => "modifyTimestamp",
                           "fullname" => "displayName",
                           "email" =>"davicalEmail"
  // Set default values for all users
  // Note: Fields that are also defined in mapping_field will
  // override fields defined here
  'default_value' => array("date_format_type" => "E",
                           "locale" => "en_EN"),

  // Map parts of the OpenLDAP timestamp to parts of the
  // DAViCal timestamp in the SQL attribute "updated". 
  // Example for an OpenLDAP timestamp: 20070503162215Z
  'format_updated' => array('Y' => array(0,4),
                            'm' => array(4,2),
                            'd' => array(6,2),
                            'H' => array(8,2),
                            'M' => array(10,2),
                            'S' => array(12,2)),

  // Whether or not to use TLS.
  // Note: Comment this out to disable TLS (setting to "no"
  // does not work)
//  'startTLS' => 'yes',

  // Search scope to use, defaults to subtree.
  // Allowed values: base, onelevel, subtree.
  'scope' => 'subtree',


Database upgrades

When DAViCal is upgraded, the database scheme often needs an upgrade as well. For this purpose we earlier created the database administrative user


and gave it access to the davical database via an entry in pg_hba.conf. We also created a .pgpass file to work around the poorly written upgrade script.

The general DB upgrade procedure works like this:

cd /tmp   # cwd must not be /root because user postgres has no access there
sudo -u postgres bash

PostgreSQL upgrades

When PostgreSQL is upgraded to a new version, the upgrade process described on the PostgreSQL page on this wiki must be followed.

In addition, the DAViCal database needs to be moved from the old to the new PostgreSQL cluster:

# create backup on old cluster
sudo -u postgres pg_dump --clean davical >/tmp/davical.sql
# recreate roles on new cluster
sudo -u postgres createuser --no-superuser --no-createdb --no-createrole --pwprompt --encrypted davical_app
sudo -u postgres createuser  --no-superuser --no-createdb --no-createrole --pwprompt --encrypted davical_dba
# recreate database
sudo -u postgres createdb -O davical_dba davical
# restore database content from backup
sudo -u postgres psql -d davical </tmp/davical.sql

Web browser access

Initial login

If everything has been set up correctly, it should now be possible to point your web browser at http://cal.herzbube.ch/. You should be able to log in as the administration user "admin", using the initial password that was printed out after the database creation script has run (see the corresponding section further above). If the password is unknown, it can be retrieved with this command:

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

Note: Once you change the initial password (which is recommended) it won't be readable in this way - only the initial configuration leaves passwords readable like this.

New users

Without LDAP authentication, new users can be created in the DAViCal web interface.

With LDAP authentication, however, users must not be created in DAViCal. Instead, they must be created in the LDAP directory. A subsequent login of that user to the DAViCal web interface will sync the user's data in DAViCal with the information obtained from LDAP.

Client configuration



Open the preferences dialog and do the following

  • Select the "Accounts" tab
  • Click "+" button to add a new account
  • Account details:
    • Description = Full User Name
    • User name = username
    • Password = password
    • Account URL = https://cal.herzbube.ch/caldav.php/username/
  • After the account has been added, there are a couple of additional options that can now be configured, e.g. how frequently calendars should be synchronized

Note: If you specify an http (instead of an https) URL, the new account will not use an SSL connection. When you add such an account, iCal warns you that username/password will be transmitted over an insecure connection. Of course you need to take this warning seriously, but if you know what you are doing then you can simply confirm/ignore the warning and the account will be created without problems.



Open the preferences app and do the following

  • Select the entry "Mail, Contacts, Calendars"
  • Select the entry "Add Account"
  • Select "Other"
  • Select "Add CalDAV account"
  • Account details:
    • Server = cal.herzbube.ch
    • Username = username
    • Password = <secret>
    • Description = Full User Name
  • Select "Continue" button
  • The iPhone now tells you that the connection could not be made over SSL (probably because it tries over port 8443 instead over the standard port 443), and asks whether it should try to add the account without SSL. Say "yes" to this question (actually select "continue" button)
  • The iPhone now tells you that checking the account has failed, however now it has become possible to change a couple of advanced settings. Select the entry "Advanced settings"
  • Advanced settings
    • Use SSL = true
    • Port = 443
    • Account URL = https://cal.herzbube.ch:443/caldav.php/username/
  • After finishing the advanced settings, return to the previous configuration page
  • Select "Continue" button
  • The iPhone now tries again to check the account. This should now work and after a moment the account should be successfully created


Configuring the iPad works pretty much the same as with the iPhone, therefore refer to the section above.

Address Book

  • Launch the Address Book app
  • Open the preferences dialog
  • Switch to the "Accounts" tab
  • Click the "+" button to add a new account
  • Select the following properties for the new account
    • Account type = CardDAV
    • Username = username
    • Password = secret
    • Server address = cal.herzbube.ch:443

Populating calendars

Calendar weeks

This section is relevant only if your calendar client has no built-in support for calendar weeks. This used to be the case for iCal and the Calendar app on iOS devices, but modern versions now finally show calendar weeks on their own.


  • Create a new LDAP user named calshare


  • Login with the calshare user via the DAViCal web interface
  • This creates the user and an initial calendar
  • Remove the initial calendar.


  • Create an account that connects to the calshare user
  1. Create a new calendar, label it "Calendar weeks"
  2. Google to find someone who provides an up-to-date .ics file that contains pseudo-events which mark the calendar week
  3. Download the .ics file
  4. Double click the .ics file. This will open iCal where you can select the previously created calendar as the target of the import


PHP error reporting

PHP's error reporting has been severely cut down in the Apache virtual host configuration. The first step in diagnosing any problems should be to comment out the following line in /etc/apache2/sites-available/cal.herzbube.ch:

php_value error_reporting "E_ALL & ~E_NOTICE"

Debugging configuration

DAViCal can also be told to write debug output to the Apache error log (in my case /var/log/apache2/davical/error.log). This is done by adding the following setting to DAViCal's configuration file:

$c->dbg['ALL'] = 1;

This example is extreme because it logs everything! I have seen a few comments that suggest that such heavy logging might have side effects and lead to other problems. To get a more moderate amount of logging, change the "ALL" string to something else. This page on the DAViCal wiki has more details.

Testing + Upgrading

General upgrade procedure

These days DAViCal has official Debian package, so an upgrade should be not more complicated than upgrading the Debian package, and possibly run the DB upgrade script

sudo -u postgres /usr/share/davical/dba/update-davical-database

(running the DB upgrade script is not part of the Debian package upgrade process, at least it wasn't as of Debian package version 1.1.4-1; but running the DB upgrade script multiple times does not hurt)

Make sure to read the Debian package Changelog first. If this does not contain any useful information, or you want to make sure you get the full story, you can also check the official release notes. The official notes for every release nicely state the software dependencies, and if there are changes to the database scheme. -> 0.9.8


I did some testing for Andrew before he officially released 0.9.8. To achieve this, I manually installed a pre-release version (version of the software like this:

  • Download the following files
  • Install them in this order
dpkg -i libawl-php_0.39-0_all.deb
dpkg -i davical_0.9.7.99-1_all.deb
  • Upgrade the database
sudo -u postgres /usr/share/davical/dba/update-davical-database


After doing the manual tests and running the pre-release version for maybe a month, I upgraded to the final release 0.9.8 like this (note that I upgraded even libawl, although the pre-release already installed the same version; I am not taking any unnecessary risks here):

  • Download the following files
  • Install them in this order
dpkg -i libawl-php_0.39-0_all.deb
dpkg -i davical_0.9.8-0_all.deb
dpkg -i davical-doc_0.9.8-0_all.deb
  • Upgrade the database
sudo -u postgres /usr/share/davical/dba/update-davical-database

The release notes for version 0.9.8 can be found here: http://wiki.davical.org/w/Release_Notes/0.9.8

0.9.8 ->

After performing other system upgrades, DAViCal stopped working for unknown reasons. I then upgraded DAViCal to via aptitude, but the problem persisted. Enabling more verbose warnings (i.e. commenting out php_value error_reporting "E_ALL & ~E_NOTICE") revealed two problems related to changes in the new PHP 5.3:

  • A problem with the PHP variable open_basedir. The mailing list suggests that the following line in the Apache configuration can be removed:
php_value open_basedir 1
  • A problem with the PHP date functions. This Debian bug report explains why PHP now generates log warnings when no default timezone is hardcoded in php.ini. The bug report also promises a patch that will fix the problem, so at the moment I don't do anything about this issue

After fixing the first problem, everything again works as expected. ->

This upgrade also was part of the upgrade from server osgiliath to pelargir. This also meant that the PostgreSQL version moved from 8.4 to 9.0.

  • Set up the new PostgreSQL server 9.0 for use with DAViCal
    • Create normal and administrative database users
    • Create database specifying davical_dba as the owner
    • Add access rights to pg_hba.conf of the 9.0 server
    • Restart the server
  • Dump the database in 8.4 (uses the non-default port 5433 on the new server pelargir!)
  • Shut down the 8.4 server to avoid confusion
  • Restore the database in 9.0
  • Since the 9.0 server uses the default port, the DAViCal configuration does not need to be updated
  • Upgrade the database in 9.0
    • For some reason, the DBA user davical_dba was not set up correctly in a number of ways
    • Password was not set, or unknown -> I specified a new, known password
    • Some tables/objects in the database were not owned by davical_dba; had to correct this first by running the upgrade script, then followed by another statement to explicitly set ownership of a sequence
cd /tmp
sudo -u postgres bash
/usr/share/davical/dba/update-davical-database --nopatch --dbuser postgres --owner davical_dba
psql davical
alter sequence dav_id_seq owner to davical_dba;
    • Finally run the upgrade script
sudo -u postgres /usr/share/davical/dba/update-davical-database

The release notes for version can be found here: http://wiki.davical.org/w/Release_Notes/ ->

  • The problem during this upgrade was that package dependencies forced a new PostgreSQL version 9.1 to be installed
  • I followed the PostgreSQL upgrade process detailed on the PostgreSQL page on this wiki
  • After PostgreSQL was upgraded and the DAViCal database moved to the new cluster, the actual DAViCal upgrade was simple:
sudo -u postgres /usr/share/davical/dba/update-davical-database -> 1.1.1-1

This upgrade went very smooth:

  • Upgrade the regular Debian package
  • Run the regular DB upgrade script (not sure if it has been necessary to run this manually, possibly this is already part of the Debian package upgrade process)
sudo -u postgres /usr/share/davical/dba/update-davical-database

1.1.1-1 ->

I made this upgrade without taking any notes. In fact, there may have been several in-between upgrades, but I couldn' tell. -> 1.1.4-1

This upgrade was triggered because on iOS devices it was no longer possible to edit contact addresses (other contact information, yes, but whenever I touched a contact, its address would be lost). This problem may have existed since I updated my devices to iOS 9, but it could also have existed before in iOS 8.

Anyway, upgrading to 1.1.4-1 fixed the problem. As before upgrading the Debian package went smoothly. I then had a hunch and manually ran the DB upgrade script:

sudo -u postgres /usr/share/davical/dba/update-davical-database

Indeed, this was applying patch 1.2.12.sql, so now it is confirmed that the DB upgrade must be manually run and is not part of the Debian package upgrade process. Side note: It is not clear whether the patch 1.2.12.sql is part of version 1.1.4-1, or if I missed running the DB upgrade script in an earlier Debian package upgrade.