Using Radicale calendar server with lighttpd through WSGI


Install Radicale on my Sheevaplug running Debian Squeeze. I use Lighttpd server with WSGI.

Radicale comes with a flup setup, so I'll try use that.

I'll also use the server's authentication system, instead of Radicale's. I just want to use private calendars, for now.


The WSGI app is running in a virtualenv in /var/www/radicale/. Best is to do this as the user that runs the webserver, to have all the correct rights. Or chmod it to this user's rights.

$ virtualenv --no-site-packages /var/www/radicale/venv/

then, switch to the virtualenv environment:

$ source /var/www/radicale/venv/bin/activate

and install radicale and flup

$ pip install radicale flup


Then, setup the radicale config (/etc/radicale/config/):

# CalDAV server hostnames separated by a comma
# IPv4 syntax: address:port
# IPv6 syntax: [address]:port
# IPv6 adresses are configured to only allow IPv6 connections
hosts =
# Daemon flag
daemon = False
# File storing the PID in daemon mode
pid =
# SSL flag, enable HTTPS protocol
ssl = False
# SSL certificate path
# certificate = /etc/apache2/ssl/server.crt
# SSL private key
# key = /etc/apache2/ssl/server.key
# Reverse DNS to resolve client address in logs
dns_lookup = True

# Encoding for responding requests
request = utf-8
# Encoding for storing local collections
stock = utf-8

# Access method
# Value: None | htpasswd | LDAP | PAM | courier
type = None

# Usernames used for public collections, separated by a comma
public_users =
# Usernames used for private collections, separated by a comma
private_users = private

# Htpasswd filename
# htpasswd_filename = /etc/radicale/users
# Htpasswd encryption method
# Value: plain | sha1 | crypt
# htpasswd_encryption = crypt

# LDAP server URL, with protocol and port
# ldap_url = ldap://localhost:389/
# LDAP base path
# ldap_base = ou=users,dc=example,dc=com
# LDAP login attribute
# ldap_attribute = uid
# LDAP filter string
# placed as X in a query of the form (&(...)X)
# example: (objectCategory=…)(objectClass=…)(memberOf=…)
# leave empty if no additional filter is needed
# ldap_filter =
# LDAP dn for initial login, used if LDAP server does not allow anonymous searches
# Leave empty if searches are anonymous
# ldap_binddn =
# LDAP password for initial login, used with ldap_binddn
# ldap_password =
# LDAP scope of the search
# ldap_scope = OneLevel

# PAM group user should be member of
# pam_group_membership = radicale

# Path to the Courier Authdaemon socket
# courier_socket =

# Storage backend
type = filesystem

# Folder for storing local collections, created if not present
filesystem_folder = /var/www/radicale/collections

# Logging configuration file 
# If no config is given, simple information is printed on the standard output 
# For more information about the syntax of the configuration file, see: 
config = /etc/radicale/logging 
# Set the default logging level to debug 
debug = False
# Store all environment variables (including those set in the shell) 
full_environment = True

Most of the config is actually ignored (as server and authentication is done by lighttpd). In case of troubles, set debug and full_environment to True and setup the logging as described in the radicale doc in /etc/radicale/logging.

WSGI application wrapping

We then need a WSGI application that launches Radicale, that will be run by lighttpd. I made this in /var/www/radicale/

#! /var/www/radicale/venv/bin/python

import sys
import radicale
from flup.server.fcgi import WSGIServer

import site

radicale.log.start()"Starting Radicale FastCGI server")

application = radicale.Application()
server = WSGIServer(application)"Stopping Radicale FastCGI server")

For debugging, you can also add the argument bindAddress=("", 1234) for WSGIServer and launch radicale by hand, this way, you get the radicale log in the console. In that case, you need to use the "host"/"port" argument in the server setup for lighttpd.

lighttpd vhost configuration

I use lighttpd to serve the WSGI app through fastCGI as a virtual host with SSL at It's configured through /etc/lighttpd/radicale.conf, included by lighttpd.conf:

$HTTP["host"] =~  "radicale\.lampshade\.ch" {
        server.document-root = "/var/www/radicale/"
        accesslog.filename      = "/var/log/lighttpd/radicale-access.log"

        fastcgi.server    = ( "/" => 
                                        "radicale-fcgi" =>
                                                "socket" => "/var/tmp/fcgi/radicale-fcgi.sock",
                                                "bin-path" => "/var/www/radicale/",
                                                "check-local" => "disable",
                                                "max-procs" => 1,
                                                "fix-root-scriptname" => "enable",
                                                "bin-copy-environment" => (
                                                        "PATH", "SHELL", "USER"

        auth.backend = "htpasswd"
        auth.backend.htpasswd.userfile = "/var/www/radicale/radicaleusers"
        auth.require = (
                "/urs/" => (
                        "method" => "basic",
                        "realm" => "Password protected area",
                        "require" => "user=urs",

        $SERVER["socket"] == ":443" {
                ssl.engine = "enable"
                ssl.pemfile = "/etc/lighttpd/ssl/server.pem"

User authentication is done by Lighttpd on the /urs/ directory, no public calendar are accessible. Be careful to add the "fix-root-scriptname" => "enable", to have the correct SCRIPT_NAME and PATH_INFO env variables set in the WSGI app environment.

Next step

Configure all the clients to use those calendars!

  • Created: 21/05/12 15:20
  • Modified: 22/05/12 17:02