For the last couple of years, I have self-hosted my calendar and address book data. Originally I just kept local calendars and address books in Evolution, but later I moved to a self-hosted CalDAV/CardDAV server and a plethora of clients.
CalDAV and CardDAV are standards for accessing, managing, and sharing calendaring and addressbook information based on the iCalendar format that are built atop the WebDAV standard, and WebDAV itself is a set of extensions to HTTP.
CalDAV and CardDAV essentially store iCalendar (.ics) and vCard (.vcf) files using WebDAV, but they provide some extra guarantees (e.g. files must be well-formed) and some additional methods for querying the data. For example, it is possible to retrieve all events between two dates with a single HTTP query, rather than the client having to check all the calendar files in a directory.
CalDAV and CardDAV are (unnecessarily) complex, in large part because they are built on top of WebDAV. Being able to use regular HTTP and WebDAV clients is quite neat, but results in extra complexity. In addition, because the standards are so large, clients and servers end up only implementing parts of it.
However, CalDAV and CardDAV have one big redeeming quality: they are the dominant standards for synchronising calendar events and addressbooks, and are supported by a wide variety of free and non-free applications. They're the status quo, until something better comes along. (and hey, at least there is a standard to begin with)
I have tried a number of servers over the years. In the end, I settled for calypso.
Calypso started out as friendly fork of Radicale, with some additional improvements. I like Calypso because it is:
- quite simple, understandable, and small (sloccount reports 1700 LOC)
- it stores plain .vcf and .ics files
- stores history in git
- easy to set up, e.g. no database dependencies
- written in Python
Its use of regular files and keeping history in Git is useful, because this means that whenever it breaks it is much easier to see what is happening. If something were to go wrong (i.e. a client decides to remove all server-side entries) it's easy to recover by rolling back history using git.
However, there are some downsides to Calypso as well.
It doesn't have good test coverage, making it harder to change (especially in a way that doesn't break some clients), though there are some recent efforts to make e.g. external spec compliance tests like caldavtester work with it.
Calypso's CalDAV/CardDAV/WebDAV implementation is a bit ad-hoc. The only WebDAV REPORTs it implements are calendar-multiget and addressbook-multiget. Support for properties has been added as new clients request them. The logic for replying to DAV requests is mixed with the actual data store implementation.
Because of this, it can be hard to get going with some clients and sometimes tricky to debug.
After attempting to fix a number of issues in Calypso, I kept running into issues with the way its code is structured. This is only fixable by rewriting sigifnicant chunks of it, so I opted to instead write a new server.
The goals of Xandikos are along the same lines as those of Calypso, to be a simple CalDAV/CardDAV server for personal use:
- easy to set up; at the moment, just running xandikos -d $HOME/dav --defaults is enough to start a new server
- use of plain .ics/.ivf files for storage
- history stored in Git
- clear separation between protocol implementation and storage
- be well tested
- standards complete
- standards compliant
The CalDAV/CardDAV implementation of Xandikos is mostly complete, but there still a number of outstanding issues.
- lack of authentication support; setting up authentication support in uwsgi or a reverse proxy is one way of working around this
- there is no useful UI for users accessing the DAV resources via a web browser
- test coverage
Xandikos has been tested with the following clients:
To run Xandikos, follow the instructions on the homepage:
./bin/xandikos --defaults -d $HOME/dav
A server should now be listening on localhost:8080 that you can access with your favorite client.