Setup a davical server on debian

For quite a long time I’ve been using owncloud to sync my calendars, contacts and files between different devices. However I never found it really satisfying. To me owncloud almway made the impression to be feature ladden but not really finished. An impression that got deepend by the last major updates. Features (or modules) got disabled by the update procedure and needed to be reenabled (and often reconfigured) manually. So after each updated I needed to reconfigure the syncing of my calendars, addresses, …. Not a good experience. So I’ve looked out for an alternative. To sync files I’m using a self-hosted install of seafile by now. For calendars and contacts I will give DAViCal a try. DAViCal is a CalDav/CardDAV server only made to manage your contacts and calendars – nothing else.

1. Install packages and dependecies

aptitude install davical

2. Grant davical access to the database

Edit /etc/postgresql/9.1/main/pg_hba.conf and add the following lines :

local   davical    davical_app   trust
local   davical    davical_dba   trust

This will grant the user davical_app and davical_dba unauthenticated access to the database davical locally. It is possible to secure this a bit more using password authenticated. But this has to be stored locally as well. To me this enough.
Note: You might have to replace 9.1 in /etc/postgresql/9.1/main/pg_hba.conf by your version number.

Restart the postgresql server:

/etc/init.d/postgresql restart

3. Create the database

Fortunately there is a script packaged with davical, so this is easy:

su postgres -c /usr/share/davical/dba/create-database.sh

The script will also generate a password for the user admin.

4. Configure an apache2 vhost

This is the config I use in /etc/apache2/sites-available/davical:

<VirtualHost *:443 >
        ServerName calendar.cbjck.de
        ServerAlias davical.cbjck.de
 
        DocumentRoot /usr/share/davical/htdocs
        DirectoryIndex index.php index.html
 
        Alias /images/ /usr/share/davical/htdocs/images/
 
 
                AllowOverride None
                Order allow,deny
                Allow from all
 
 
        php_value include_path /usr/share/awl/inc
        php_value magic_quotes_gpc 0
        php_value magic_quotes_runtime 0
        php_value register_globals 0
        php_value error_reporting "E_ALL &amp; ~E_NOTICE"
        php_value default_charset "utf-8"
 
        SSLEngine on
</VirtualHost>
 
<VirtualHost *:80 >
        ServerName calendar.cbjck.de
        ServerAlias davical.cbjck.de
 
        # Enforce SSL
        RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>

It creates a virtual host and enforces the use of SSL. Of course you can also leave that out and use a more simple approach.
Enable the new site and restart apache once you’re done:

a2ensite davical
/etc/init.d/apache2 restart

Going to the server address configured above should show you a site telling you to configure davical. So up to here everything works.

5. Basic configuration

As the page on your calender address will be telling you we first need to setup the database connection and an admin user in /etc/davical/davical.conf:

<?php
        $c->admin_email = 'admin@cbjck.de';
        $c->system_name = "cbjck.de CalDAV Server";
        $c->enable_row_linking = true;
        $c->default_locale = 'de_DE.UTF-8';
 
        $c->pg_connect[] = 'dbname=davical port=5432 user=davical_app';

Note there is no php end tag (?>).
Now you should be able to log in with username admin and the password created earlier.

6. User configuration (LDAP)

You can of course use the admin page of davical to create your users. However as I have all my user account in an LDAP I’d like to use them. Now this is a bit complex and depends highly on your LDAP setup. I’ll just show my configuration (in /etc/davical/config.php):

// LDAP authentication for existing users:
        $c->authenticate_hook['call'] = 'LDAP_check';
        $c->authenticate_hook['config'] = array(
                'host'          => 'localhost',              //host name of your LDAP Server, use URI notation for LDAP over SSL on port 636
                'port'          => '389',                     //port
//              'bindDN'        => 'cn=davical,dc=cbjck,dc=de',  //DN to bind request to this server (if required)
//              'passDN'        => 'PASSWORD',                 //Password of request bind
                'baseDNUsers'   => 'ou=people,dc=cbjck,dc=de', //where to look for valid user
                'filterUsers'   => '(&(objectClass=inetOrgPerson)(memberOf=ou=calendarusers,ou=groups,dc=cbjck,dc=de))',    //filter which must validate a user according to R$
                'baseDNGroups' => 'ou=calendarusers,ou=groups,dc=cbjck,dc=de', //where to look for groups
                'filterGroups' => 'objectClass=posixGroup',      //filter with same rules as filterUsers, could also be groupOfUniqueNames
                'protocolVersion' => 3,                          // important for simple auth (no sasl)
//              'startTLS'    => true,                         // securing your LDAP connection
                'mapping_field' => array(
                        'username' => 'uid',
                        'updated'  => 'modifyTimestamp',
                        'fullname' => 'cn',               // "Common Name"
//                      'user_no'  => 'uidNumber',        // set DAViCal user no to match Unix uid from LDAP (may cause sql_from_object problems if these user ids do not actu$
                        'email'    => 'maildrop',
//                      'active' => ,                  // switch calendar users on/off via ldap attribute
                ),
                'group_mapping_field' => array(
                        'username' => 'cn',
                        'updated' => 'modifyTimestamp',
                        'fullname' => 'cn' ,
                        'members' =>'memberUid'
                'default_value' => array(
                        'date_format_type' => 'E',
                        'locale' => 'de_DE'
                ),
                '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)
                ),              // map LDAP "modifyTimestamp" field to SQL "updated" field
                'scope' => 'subtree',                                     // Search scope to use, defaults to subtree (BOTH, user and group mappings)
        );
 
include('drivers_ldap.php');
 
// Save local admin user from being deleted
$c->do_not_sync_from_ldap = array( 'admin' => true);

As configuration is done in PHP code syntax is crucial. Any syntax error like a missing comma will result in blank pages without any further notice. The following command is quite useful to find errors:

php -l /etc/davical/config.php

Unfortunately davical cannot resolve group members from groupOfNames in LDAP as I’m using them. davical expects groups to be posixGroups to obtain uids from. For the moment I’ll be creating extra groups for davical until I find (a lot of) time to adjust my LDAP.

Leave a Reply

Your email address will not be published. Required fields are marked *