DAViCal
This page provides details about setting up DAViCal, a CalDAV calendar and CardDAV contact sharing service, on Debian Linux. Most of the information on this page can also be found, in one form or another, on the DAViCal website and the DAViCal wiki.
References
External:
- DAViCal website: http://www.davical.org/
- DAViCal installation: http://www.davical.org/installation.php
- Client configuration: http://www.davical.org/clients.php
- Wiki: http://wiki.davical.org/
- Release notes: http://wiki.davical.org/w/Release_Notes
On this wiki:
Glossary
- RSCDS
- "Really Simple CalDAV Store". The original project name under which DAViCal was started.
- AWL
- Andrew's Web Libraries
Research
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:
- Bedework (CalDav server): http://www.bedework.org/
- Bongo: http://bongo-project.org/Roadmap
- Cosmo: http://chandlerproject.org/bin/view/Projects/CosmoHome
- ModCalDav: http://sourceforge.net/projects/modcaldav/
- Darwin Calendar Server howto: http://blogs.ittoolbox.com/emergingtech/macsploitation/archives/who-needs-leopard-server-calendar-server-on-linux-19982
Other URLs:
- Overview of shortcomings of iCal-over-HTTP: http://docs.opengroupware.org/Members/helge/moddavical/view
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 davical-doc postgresql postgresql-client
Notice that the postgresql server package needs to be explicitly installed. Also, postgresql-client should be installed as the davical package depends on PostgreSQL client packages with explicit version numbers (e.g. postgresql-client-8.4).
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:
su postgres -c "createuser --no-superuser --no-createdb --no-createrole --pwprompt --encrypted davical_app"
Discussion:
-
suis necessary even if logged in as root, because the default configuration of PostgreSQL does not grant special privileges to root. The UNIX userpostgres, however, is allowed to connect as the database super user (which "happens" to have the same name,postgres) -
createuseris a wrapper around the SQL command "create role", which means that we should probably say thatdavical_appis the new database role (instead of the new database user) -
--pwpromptprompts you for a password;--encryptedcauses the password to be stored in the database in encrypted format. Use these two options only if you plan to use password authentication -
--no-superuseretc.: 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.
su postgres -c "createuser --no-superuser --no-createdb --no-createrole --pwprompt --encrypted davical_dba"
New database
To create the new database for the DAViCal service, run the following command:
su postgres -c /usr/share/davical/dba/create-database.sh
Discussion:
- As above,
suis necessary - The
create-database.shscript 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 packagelibawl-phpis installed (which should be the case, it's a dependency of thedavicalpackage) - AWL = Andrew's Web Libraries
- 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!
Database user authentication
DAViCal needs to authenticate as the database user that was previously created. This is configured by adding an entry to
/etc/postgresql/8.4/main/pg_hba.conf
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 CIDR-ADDRESS METHOD local davical davical_app trust local all all ident
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 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 entry I use therefore looks like this:
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 rule:
/etc/init.d/postgresql-8.4 restart
Of course, the DBA user also needs access, so we need to add another line:
local davical davical_dba md5
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:
cal.herzbube.ch
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
/etc/apache2/sites-available/cal.herzbube.ch
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
# --------------------------------------------------------------------------------
# --------------------------------------------------------------------------------
# SSL Host
# --------------------------------------------------------------------------------
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName cal.herzbube.ch
ServerAlias cal.lan.herzbube.ch cal.wifi.herzbube.ch
ServerAdmin webmaster@herzbube.ch
ErrorLog /var/log/apache2/cal.herzbube.ch/error.log
CustomLog /var/log/apache2/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
Order allow,deny
Allow from all
php_admin_flag engine on
</Directory>
<IfModule mod_php5.c>
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"
</IfModule>
<IfModule mod_rewrite.c>
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]
</IfModule>
SSLEngine on
SSLCertificateFile /etc/ssl/certs/herzbube.ch.crt
SSLCertificateKeyFile /etc/ssl/private/herzbube.ch.key.unsecure
SSLCertificateChainFile /etc/ssl/certs/cacert.org.certchain
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
</VirtualHost>
</IfModule>
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
davicalAccountto/etc/ldap/schema/naef.schema(see OpenLDAP for details) - Augment those user accounts under
ou=users,dc=herzbube,dc=chwith the new object class that should be allowed to login to DAViCal
DAViCal configuration
General configuration
The DAViCal configuration generally resides in
/etc/davical/<domain>-conf.php
In my case the file is named
/etc/davical/cal.herzbube.ch-conf.php
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:
<?php $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:
<?php $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";
Discussion:
- 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 should 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' => 'localhost',
'port' => '389',
// 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',
);
include('drivers_ldap.php');
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
davical_dba
and gave it access to the davical database via an entry in pg_hba.conf. 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 /usr/share/davical/dba/update-davical-database
The problem here is that the updating script is not very flexible. Although the DAViCal wiki pages talk about storing the password in a file named /etc/davical/administration.yml, this doesn't really work. If the update script needs to apply several patches to the database scheme, it will start to ask for the password for each patch after the first. The only way I have found to prevent the script from asking is to store the password in the PostgreSQL password file
/var/lib/postgresql/.pgpass
File content:
*:*:davical:davical_dba:secret
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 createuser --no-superuser --no-createdb --no-createrole --pwprompt --encrypted davical_app createuser --no-superuser --no-createdb --no-createrole --pwprompt --encrypted davical_dba # recreate database createdb -O davical_dba davical # restore database content from backup 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:
su postgres -c "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
If LDAP authentication is used, 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
iCal
References:
- http://davical.org/clients.php?client=iCal
- http://wiki.davical.org/w/Setup_for_Apple_Users (for easy setup, which might be more trouble than it's worth)
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: It is also possible to create an account that does not use an SSL connection. Such an account uses a http (instead of an https) URL. When you add such an account, iCal warns you that username/password will be transmitted over an insecure connection. This warning can simply be confirmed/ignored, and the account will be created without problems.
iPhone
References:
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 (e.g. patrick, or calshare)
- 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
iPad
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 = addressbookshare
- Password = secret
- Server address = cal.herzbube.ch:443
Populating calendars
Calendar weeks
LDAP:
- Create a new LDAP user named
calshare
DAViCal:
- Login with the
calshareuser via the DAViCal web interface - This creates the user and an initial calendar
- Remove the initial calendar.
iCal:
- Create an account that connects to the
calshareuser
- Create a new calendar, label it "Calendar weeks"
- Google to find someone who provides an up-to-date .ics file that contains pseudo-events which mark the calendar week
- Download the .ics file
- Double click the .ics file. This will open iCal where you can select the previously created calendar as the target of the import
Troubleshooting
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 the PHP 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
(I am not sure if this is run as part of the Debian package upgrade process, but running it a second time does not hurt)
Since the Debian package Changelog does not contain any useful information, one mighth also check the release notes first. The notes for every release nicely state the software dependencies, and if there are changes to the database scheme.
0.9.7.6 -> 0.9.8
Tests
I did some testing for Andrew before he officially released 0.9.8. To achieve this, I manually installed a pre-release version (version 0.9.7.99-1) of the software like this:
- Download the following files
http://debian.mcmillan.net.nz/packages/davical/testing/libawl-php_0.39-0_all.deb http://debian.mcmillan.net.nz/packages/davical/testing/davical_0.9.7.99-1_all.deb
- 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
Upgrade
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
http://debian.mcmillan.net.nz/packages/awl/libawl-php_0.39-0_all.deb http://debian.mcmillan.net.nz/packages/davical/davical_0.9.8-0_all.deb http://debian.mcmillan.net.nz/packages/davical/davical-doc_0.9.8-0_all.deb
- 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 -> 0.9.8.4
After performing other system upgrades, DAViCal stopped working for unknown reasons. I then upgraded DAViCal to 0.9.8.4 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.
0.9.8.4 -> 0.9.9.4
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_dbaas the owner - Add access rights to
pg_hba.confof 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_dbawas 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
- For some reason, the DBA user
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 0.9.9.4 can be found here: http://wiki.davical.org/w/Release_Notes/0.9.9.4
0.9.9.4 -> 0.9.9.7
- 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
0.9.9.7 -> 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