diff --git a/master.html b/master.html index 76416819..b7e3db1d 100644 --- a/master.html +++ b/master.html @@ -146,7 +146,6 @@
  • Limits
  • Running as a service
  • MacOS with launchd
  • -
  • Classic daemonization
  • Windows with "NSSM - the Non-Sucking Service Manager"
  • Reverse Proxy @@ -184,10 +183,7 @@
  • Layout
  • Locking
  • -
  • Logging -
  • +
  • Logging
  • Architecture
    @@ -308,7 +303,7 @@
    # Run the following command as root or
     # add the --user argument to only install for the current user
     $ python3 -m pip install --upgrade radicale
    -$ python3 -m radicale --config "" --storage-filesystem-folder=~/.var/lib/radicale/collections
    +$ python3 -m radicale --storage-filesystem-folder=~/.var/lib/radicale/collections

    Victory! Open http://localhost:5232/ in your browser! You can login with any username and password.

    @@ -316,8 +311,7 @@

    The first step is to install Python. Go to python.org and download the latest version of Python 3. Then run the installer. On the first window of the installer, check the "Add Python to PATH" box and click on "Install now". Wait a couple of minutes, it's done!

    Launch a command prompt and type:

    C:\Users\User> python -m pip install --upgrade radicale
    -C:\Users\User> python -m radicale --config "" --storage-filesystem-folder=~/radicale/collections
    -

    If you are using PowerShell replace --config "" with --config '""'.

    +C:\Users\User> python -m radicale --storage-filesystem-folder=~/radicale/collections

    Victory! Open http://localhost:5232/ in your browser! You can login with any username and password.

    @@ -330,7 +324,7 @@

    Installation instructions can be found on the Tutorial page.

    Configuration

    -

    Radicale tries to load configuration files from /etc/radicale/config, ~/.config/radicale/config and the RADICALE_CONFIG environment variable. A custom path can be specified with the --config /path/to/config command line argument.

    +

    Radicale tries to load configuration files from /etc/radicale/config and ~/.config/radicale/config. Custom paths can be specified with the --config /path/to/config command line argument or the RADICALE_CONFIG environment variable. Multiple configuration files can be separated by : (resp. ; on Windows). Paths that start with ? are optional.

    You should create a new configuration file at the desired location. (If the use of a configuration file is inconvenient, all options can be passed via command line arguments.)

    All configuration options are described in detail on the Configuration page.

    @@ -342,21 +336,19 @@
    The secure way

    The users file can be created and managed with htpasswd:

    # Create a new htpasswd file with the user "user1"
    -$ htpasswd -B -c /path/to/users user1
    +$ htpasswd -c /path/to/users user1
     New password:
     Re-type new password:
     # Add another user
    -$ htpasswd -B /path/to/users user2
    +$ htpasswd /path/to/users user2
     New password:
     Re-type new password:
    -

    bcrypt is used to secure the passwords. Radicale requires additional dependencies for this encryption method:

    -
    $ python3 -m pip install --upgrade radicale[bcrypt]

    Authentication can be enabled with the following configuration:

    -
    [auth]
    -type = htpasswd
    -htpasswd_filename = /path/to/users
    -# encryption method used in the htpasswd file
    -htpasswd_encryption = bcrypt
    +
    [auth]
    +type = htpasswd
    +htpasswd_filename = /path/to/users
    +# encryption method used in the htpasswd file
    +htpasswd_encryption = md5
    The simple but insecure way
    @@ -365,40 +357,39 @@ user2:password2

    Authentication can be enabled with the following configuration:

    -
    [auth]
    -type = htpasswd
    -htpasswd_filename = /path/to/users
    -# encryption method used in the htpasswd file
    -htpasswd_encryption = plain
    +
    [auth]
    +type = htpasswd
    +htpasswd_filename = /path/to/users
    +# encryption method used in the htpasswd file
    +htpasswd_encryption = plain

    Addresses

    -

    The default configuration binds the server to localhost. It can't be reached from other computers. This can be changed with the following configuration options:

    -
    [server]
    -hosts = 0.0.0.0:5232
    -

    More addresses can be added (separated by commas).

    +

    The default configuration binds the server to localhost. It can't be reached from other computers. This can be changed with the following configuration options (IPv4 and IPv6):

    +
    [server]
    +hosts = 0.0.0.0:5232, [::]:5232

    Storage

    Data is stored in the folder /var/lib/radicale/collections. The path can be changed with the following configuration:

    -
    [storage]
    -filesystem_folder = /path/to/storage
    +
    [storage]
    +filesystem_folder = /path/to/storage

    Security: The storage folder should not be readable by unauthorized users. Otherwise, they can read the calendar data and lock the storage. You can find OS dependent instructions in the Running as a service section.

    Limits

    Radicale enforces limits on the maximum number of parallel connections, the maximum file size (important for contacts with big photos) and the rate of incorrect authentication attempts. Connections are terminated after a timeout. The default values should be fine for most scenarios.

    -
    [server]
    -max_connections = 20
    -# 100 Megabyte
    -max_content_length = 100000000
    -# 30 seconds
    -timeout = 30
    -
    -[auth]
    -# Average delay after failed login attempts in seconds
    -delay = 1
    +
    [server]
    +max_connections = 20
    +# 100 Megabyte
    +max_content_length = 100000000
    +# 30 seconds
    +timeout = 30
    +
    +[auth]
    +# Average delay after failed login attempts in seconds
    +delay = 1

    Running as a service

    @@ -406,78 +397,71 @@ user2:password2
    Linux with systemd as a user

    Create the file ~/.config/systemd/user/radicale.service:

    -
    [Unit]
    -Description=A simple CalDAV (calendar) and CardDAV (contact) server
    -
    -[Service]
    -ExecStart=/usr/bin/env python3 -m radicale
    -Restart=on-failure
    -
    -[Install]
    -WantedBy=default.target
    +
    [Unit]
    +Description=A simple CalDAV (calendar) and CardDAV (contact) server
    +
    +[Service]
    +ExecStart=/usr/bin/env python3 -m radicale
    +Restart=on-failure
    +
    +[Install]
    +WantedBy=default.target

    Radicale will load the configuration file from ~/.config/radicale/config. You should set the configuration option filesystem_folder in the storage section to something like ~/.var/lib/radicale/collections.

    To enable and manage the service run:

    -
    # Enable the service
    -$ systemctl --user enable radicale
    -# Start the service
    -$ systemctl --user start radicale
    -# Check the status of the service
    -$ systemctl --user status radicale
    -# View all log messages
    -$ journalctl --user --unit radicale.service
    +
    # Enable the service
    +$ systemctl --user enable radicale
    +# Start the service
    +$ systemctl --user start radicale
    +# Check the status of the service
    +$ systemctl --user status radicale
    +# View all log messages
    +$ journalctl --user --unit radicale.service
    Linux with systemd system-wide

    Create the radicale user and group for the Radicale service. (Run useradd --system --home-dir / --shell /sbin/nologin radicale as root.) The storage folder must be writable by radicale. (Run mkdir -p /var/lib/radicale/collections && chown -R radicale:radicale /var/lib/radicale/collections as root.)

    Security: The storage should not be readable by others. (Run chmod -R o= /var/lib/radicale/collections as root.)

    Create the file /etc/systemd/system/radicale.service:

    -
    [Unit]
    -Description=A simple CalDAV (calendar) and CardDAV (contact) server
    -After=network.target
    -Requires=network.target
    -
    -[Service]
    -ExecStart=/usr/bin/env python3 -m radicale
    -Restart=on-failure
    -User=radicale
    -# Deny other users access to the calendar data
    -UMask=0027
    -# Optional security settings
    -PrivateTmp=true
    -ProtectSystem=strict
    -ProtectHome=true
    -PrivateDevices=true
    -ProtectKernelTunables=true
    -ProtectKernelModules=true
    -ProtectControlGroups=true
    -NoNewPrivileges=true
    -ReadWritePaths=/var/lib/radicale/collections
    -
    -[Install]
    -WantedBy=multi-user.target
    +
    [Unit]
    +Description=A simple CalDAV (calendar) and CardDAV (contact) server
    +After=network.target
    +Requires=network.target
    +
    +[Service]
    +ExecStart=/usr/bin/env python3 -m radicale
    +Restart=on-failure
    +User=radicale
    +# Deny other users access to the calendar data
    +UMask=0027
    +# Optional security settings
    +PrivateTmp=true
    +ProtectSystem=strict
    +ProtectHome=true
    +PrivateDevices=true
    +ProtectKernelTunables=true
    +ProtectKernelModules=true
    +ProtectControlGroups=true
    +NoNewPrivileges=true
    +ReadWritePaths=/var/lib/radicale/collections
    +
    +[Install]
    +WantedBy=multi-user.target

    Radicale will load the configuration file from /etc/radicale/config.

    To enable and manage the service run:

    -
    # Enable the service
    -$ systemctl enable radicale
    -# Start the service
    -$ systemctl start radicale
    -# Check the status of the service
    -$ systemctl status radicale
    -# View all log messages
    -$ journalctl --unit radicale.service
    +
    # Enable the service
    +$ systemctl enable radicale
    +# Start the service
    +$ systemctl start radicale
    +# Check the status of the service
    +$ systemctl status radicale
    +# View all log messages
    +$ journalctl --unit radicale.service

    MacOS with launchd

    To be written.

    -
    -

    Classic daemonization

    -

    Set the configuration option daemon in the section server to True. You may want to set the option pid to the path of a PID file.

    -

    After daemonization the server will not log anything. You have to configure Logging.

    -

    If you start Radicale now, it will initialize and fork into the background. The main process exits, after the PID file is written.

    -

    Security: You can set the umask with umask 0027 before you start the daemon, to protect your calendar data and log files from other users. Don't forget to set permissions of files that are already created!

    -

    Windows with "NSSM - the Non-Sucking Service Manager"

    First install NSSM and start nssm install in a command prompt. Apply the following configuration:

    @@ -510,14 +494,14 @@ user2:password2 }

    Example Apache configuration:

    -
    RewriteEngine On
    -RewriteRule ^/radicale$ /radicale/ [R,L]
    -
    -<Location "/radicale/">
    -    ProxyPass        http://localhost:5232/ retry=0
    -    ProxyPassReverse http://localhost:5232/
    -    RequestHeader    set X-Script-Name /radicale/
    -</Location>
    +
    RewriteEngine On
    +RewriteRule ^/radicale$ /radicale/ [R,L]
    +
    +<Location "/radicale/">
    +    ProxyPass        http://localhost:5232/ retry=0
    +    ProxyPassReverse http://localhost:5232/
    +    RequestHeader    set X-Script-Name /radicale/
    +</Location>

    Be reminded that Radicale's default configuration enforces limits on the maximum number of parallel connections, the maximum file size and the rate of incorrect authentication attempts. Connections are terminated after a timeout.

    Manage user accounts with the reverse proxy

    @@ -533,33 +517,33 @@ user2:password2 }

    Example Apache configuration:

    -
    RewriteEngine On
    -RewriteRule ^/radicale$ /radicale/ [R,L]
    -
    -<Location "/radicale/">
    -    AuthType      Basic
    -    AuthName      "Radicale - Password Required"
    -    AuthUserFile  "/etc/radicale/htpasswd"
    -    Require       valid-user
    -
    -    ProxyPass        http://localhost:5232/ retry=0
    -    ProxyPassReverse http://localhost:5232/
    -    RequestHeader    set X-Script-Name /radicale/
    -    RequestHeader    set X-Remote-User expr=%{REMOTE_USER}
    -</Location>
    +
    RewriteEngine On
    +RewriteRule ^/radicale$ /radicale/ [R,L]
    +
    +<Location "/radicale/">
    +    AuthType      Basic
    +    AuthName      "Radicale - Password Required"
    +    AuthUserFile  "/etc/radicale/htpasswd"
    +    Require       valid-user
    +
    +    ProxyPass        http://localhost:5232/ retry=0
    +    ProxyPassReverse http://localhost:5232/
    +    RequestHeader    set X-Script-Name /radicale/
    +    RequestHeader    set X-Remote-User expr=%{REMOTE_USER}
    +</Location>

    Security: Untrusted clients should not be able to access the Radicale server directly. Otherwise, they can authenticate as any user.

    Secure connection between Radicale and the reverse proxy

    SSL certificates can be used to encrypt and authenticate the connection between Radicale and the reverse proxy. First you have to generate a certificate for Radicale and a certificate for the reverse proxy. The following commands generate self-signed certificates. You will be asked to enter additional information about the certificate, the values don't matter and you can keep the defaults.

    -
    $ openssl req -x509 -newkey rsa:4096 -keyout server_key.pem -out server_cert.pem -nodes -days 9999
    -$ openssl req -x509 -newkey rsa:4096 -keyout client_key.pem -out client_cert.pem -nodes -days 9999
    +
    $ openssl req -x509 -newkey rsa:4096 -keyout server_key.pem -out server_cert.pem -nodes -days 9999
    +$ openssl req -x509 -newkey rsa:4096 -keyout client_key.pem -out client_cert.pem -nodes -days 9999

    Use the following configuration for Radicale:

    -
    [server]
    -ssl = True
    -certificate = /path/to/server_cert.pem
    -key = /path/to/server_key.pem
    -certificate_authority = /path/to/client_cert.pem
    +
    [server]
    +ssl = True
    +certificate = /path/to/server_cert.pem
    +key = /path/to/server_key.pem
    +certificate_authority = /path/to/client_cert.pem

    Example nginx configuration:

    location /radicale/ {
         proxy_pass https://localhost:5232/;
    @@ -579,14 +563,14 @@ user2:password2
     

    Be reminded that Radicale's default configuration enforces limits on the maximum upload file size.

    Security: The None authentication type disables all rights checking. Don't use it with REMOTE_USER. Use remote_user instead.

    Example uWSGI configuration:

    -
    [uwsgi]
    -http-socket = 127.0.0.1:5232
    -processes = 8
    -plugin = python3
    -module = radicale
    -env = RADICALE_CONFIG=/etc/radicale/config
    +
    [uwsgi]
    +http-socket = 127.0.0.1:5232
    +processes = 8
    +plugin = python3
    +module = radicale
    +env = RADICALE_CONFIG=/etc/radicale/config

    Example Gunicorn configuration:

    -
    gunicorn --bind '127.0.0.1:5232' --workers 8 --env 'RADICALE_CONFIG=/etc/radicale/config' radicale
    +
    gunicorn --bind '127.0.0.1:5232' --workers 8 --env 'RADICALE_CONFIG=/etc/radicale/config' radicale

    Manage user accounts with the WSGI server

    Set the configuration option type in the auth section to remote_user. Radicale uses the user name provided by the WSGI server and disables authentication over HTTP.

    @@ -601,7 +585,7 @@ user2:password2 .Radicale.tmp-*

    The configuration option hook in the storage section must be set to the following command:

    -
    git add -A && (git diff --cached --quiet || git commit -m "Changes by "%(user)s)
    +
    git add -A && (git diff --cached --quiet || git commit -m "Changes by "%(user)s)

    The command gets executed after every change to the storage and commits the changes into the git repository.

    @@ -613,7 +597,7 @@ user2:password2
  • Mozilla Thunderbird with CardBook and Lightning
  • InfCloud, CalDavZAP and CardDavMATE
  • -

    Many clients do not support the creation of new calendars and address books. You can use Radicale's web interface (e.g. http://localhost:5232) to create and manage collections.

    +

    Many clients do not support the creation of new calendars and address books. You can use Radicale's web interface (e.g. http://localhost:5232) to create and manage address books and calendars.

    In some clients you can just enter the URL of the Radicale server (e.g. http://localhost:5232) and your user name. In others, you have to enter the URL of the collection directly (e.g. http://localhost:5232/user/calendar).

    DAVx⁵

    @@ -646,53 +630,53 @@ user2:password2
    Direct editing of the storage

    To create a new collection, you have to create the corresponding folder in the file system storage (e.g. collection-root/user/calendar). To tell Radicale and clients that the collection is a calendar, you have to create the file .Radicale.props with the following content in the folder:

    -
    {"tag": "VCALENDAR"}
    +
    {"tag": "VCALENDAR"}

    The calendar is now available at the URL path /user/calendar. For address books the file must contain:

    -
    {"tag": "VADDRESSBOOK"}
    +
    {"tag": "VADDRESSBOOK"}

    Calendar and address book collections must not have any child collections. Clients with automatic discovery of collections will only show calendars and addressbooks that are direct children of the path /USERNAME/.

    Delete collections by deleting the corresponding folders.

    HTTP requests with curl

    To create a new calendar run something like:

    -
    $ curl -u user -X MKCOL 'http://localhost:5232/user/calendar' --data \
    +
    $ curl -u user -X MKCOL 'http://localhost:5232/user/calendar' --data \
    +'<?xml version="1.0" encoding="UTF-8" ?>
    +<create xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:I="http://apple.com/ns/ical/">
    +  <set>
    +    <prop>
    +      <resourcetype>
    +        <collection />
    +        <C:calendar />
    +      </resourcetype>
    +      <C:supported-calendar-component-set>
    +        <C:comp name="VEVENT" />
    +        <C:comp name="VJOURNAL" />
    +        <C:comp name="VTODO" />
    +      </C:supported-calendar-component-set>
    +      <displayname>Calendar</displayname>
    +      <C:calendar-description>Example calendar</C:calendar-description>
    +      <I:calendar-color>#ff0000ff</I:calendar-color>
    +    </prop>
    +  </set>
    +</create>'
    +

    To create a new address book run something like:

    +
    $ curl -u user -X MKCOL 'http://localhost:5232/user/addressbook' --data \
     '<?xml version="1.0" encoding="UTF-8" ?>
    -<create xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:I="http://apple.com/ns/ical/">
    +<create xmlns="DAV:" xmlns:CR="urn:ietf:params:xml:ns:carddav">
       <set>
         <prop>
           <resourcetype>
             <collection />
    -        <C:calendar />
    +        <CR:addressbook />
           </resourcetype>
    -      <C:supported-calendar-component-set>
    -        <C:comp name="VEVENT" />
    -        <C:comp name="VJOURNAL" />
    -        <C:comp name="VTODO" />
    -      </C:supported-calendar-component-set>
    -      <displayname>Calendar</displayname>
    -      <C:calendar-description>Example calendar</C:calendar-description>
    -      <I:calendar-color>#ff0000ff</I:calendar-color>
    -    </prop>
    -  </set>
    -</create>'
    -

    To create a new address book run something like:

    -
    $ curl -u user -X MKCOL 'http://localhost:5232/user/addressbook' --data \
    -'<?xml version="1.0" encoding="UTF-8" ?>
    -<create xmlns="DAV:" xmlns:CR="urn:ietf:params:xml:ns:carddav">
    -  <set>
    -    <prop>
    -      <resourcetype>
    -        <collection />
    -        <CR:addressbook />
    -      </resourcetype>
    -      <displayname>Address book</displayname>
    -      <CR:addressbook-description>Example address book</CR:addressbook-description>
    -    </prop>
    -  </set>
    -</create>'
    + <displayname>Address book</displayname> + <CR:addressbook-description>Example address book</CR:addressbook-description> + </prop> + </set> +</create>'

    The collection /USERNAME will be created automatically, when the user authenticates to Radicale for the first time. Clients with automatic discovery of collections will only show calendars and address books that are direct children of the path /USERNAME/.

    Delete the collections by running something like:

    -
    $ curl -u user -X DELETE 'http://localhost:5232/user/calendar'
    +
    $ curl -u user -X DELETE 'http://localhost:5232/user/calendar'
    @@ -700,43 +684,33 @@ user2:password2

    Configuration

    Radicale can be configured with a configuration file or with command line arguments.

    An example configuration file looks like:

    -
    [server]
    -# Bind all addresses
    -hosts = 0.0.0.0:5232
    -
    -[auth]
    -type = htpasswd
    -htpasswd_filename = /path/to/users
    -htpasswd_encryption = bcrypt
    -[storage]
    -filesystem_folder = ~/.var/lib/radicale/collections
    -

    Radicale tries to load configuration files from /etc/radicale/config, ~/.config/radicale/config and the RADICALE_CONFIG environment variable. This behaviour can be overwritten by specifying a path with the --config /path/to/config command line argument.

    +
    [server]
    +# Bind all addresses
    +hosts = 0.0.0.0:5232, [::]:5232
    +
    +[auth]
    +type = htpasswd
    +htpasswd_filename = /path/to/users
    +htpasswd_encryption = md5
    +[storage]
    +filesystem_folder = ~/.var/lib/radicale/collections
    +

    Radicale tries to load configuration files from /etc/radicale/config and ~/.config/radicale/config. Custom paths can be specified with the --config /path/to/config command line argument or the RADICALE_CONFIG environment variable. Multiple configuration files can be separated by : (resp. ; on Windows). Paths that start with ? are optional.

    The same example configuration via command line arguments looks like:

    -
    python3 -m radicale --config "" --server-hosts 0.0.0.0:5232 --auth-type htpasswd --htpasswd-filename /path/to/htpasswd --htpasswd-encryption bcrypt
    -

    The --config "" argument is required to stop Radicale from trying to load configuration files. Run python3 -m radicale --help for more information.

    +
    python3 -m radicale --server-hosts 0.0.0.0:5232,[::]:5232 --auth-type htpasswd --htpasswd-filename /path/to/htpasswd --htpasswd-encryption md5
    +

    Add the argument --config "" to stop Radicale from loading the default configuration files. Run python3 -m radicale --help for more information.

    In the following, all configuration categories and options are described.

    server

    -

    Most configuration options in this category are only relevant in standalone mode. All options beside max_content_length and realm are ignored, when Radicale runs via WSGI.

    +

    The configuration options in this category are only relevant in standalone mode. All options are ignored, when Radicale runs via WSGI.

    hosts

    A comma separated list of addresses that the server will bind to.

    -

    Default: 127.0.0.1:5232

    -
    -
    -
    daemon
    -

    Daemonize the Radicale process. It does not reset the umask.

    -

    Default: False

    -
    -
    -
    pid
    -

    If daemon mode is enabled, Radicale will write its PID to this file.

    -

    Default:

    +

    Default: localhost:5232

    max_connections

    The maximum number of parallel connections. Set to 0 to disable the limit.

    -

    Default: 20

    +

    Default: 8

    max_content_length
    @@ -768,26 +742,6 @@ user2:password2

    Path to the CA certificate for validating client certificates. This can be used to secure TCP traffic between Radicale and a reverse proxy. If you want to authenticate users with client-side certificates, you also have to write an authentication plugin that extracts the user name from the certifcate.

    Default:

    -
    -
    protocol
    -

    SSL protocol used. See python's ssl module for available values.

    -

    Default: PROTOCOL_TLSv1_2

    -
    -
    -
    ciphers
    -

    Available ciphers for SSL. See python's ssl module for available ciphers.

    -

    Default:

    -
    -
    -
    dns_lookup
    -

    Reverse DNS to resolve client address in logs.

    -

    Default: True

    -
    -
    -
    realm
    -

    Message displayed in the client when a password is needed.

    -

    Default: Radicale - Password Required

    -

    encoding

    @@ -827,18 +781,20 @@ user2:password2
    user1:password1
     user2:password2
     
    -

    bcrypt : This uses a modified version of the Blowfish stream cipher. It's very secure. The passlib python module is required for this. Additionally you may need one of the following python modules: bcrypt, py-bcrypt or bcryptor.

    -

    md5 : This uses an iterated md5 digest of the password with a salt. The passlib python module is required for this.

    -

    sha1 : Passwords are stored as SHA1 hashes. It's insecure!

    -

    ssha : Passwords are stored as salted SHA1 hashes. It's insecure!

    -

    crypt : This uses UNIX crypt(3). It's insecure!

    -

    Default: bcrypt

    +

    bcrypt : This uses a modified version of the Blowfish stream cipher. It's very secure. The installation of radicale[bcrypt] is required for this.

    +

    md5 : This uses an iterated md5 digest of the password with a salt.

    +

    Default: md5

    delay

    Average delay after failed login attempts in seconds.

    Default: 1

    +
    +
    realm
    +

    Message displayed in the client when a password is needed.

    +

    Default: Radicale - Password Required

    +

    rights

    @@ -873,21 +829,11 @@ user2:password2

    Folder for storing local collections, created if not present.

    Default: /var/lib/radicale/collections

    -
    -
    filesystem_locking
    -

    Lock the storage. This must be disabled if locking is not supported by the underlying file system. Never start multiple instances of Radicale or edit the storage externally while Radicale is running if disabled.

    -

    Default: True

    -
    max_sync_token_age

    Delete sync-token that are older than the specified time. (seconds)

    Default: 2592000

    -
    -
    filesystem_fsync
    -

    Sync all changes to disk during requests. (This can impair performance.) Disabling it increases the risk of data loss, when the system crashes or power fails!

    -

    Default: True

    -
    hook

    Command that is run after changes to storage. Take a look at the Versioning page for an example.

    @@ -907,32 +853,23 @@ user2:password2

    logging

    -
    -
    debug
    -

    Set the default logging level to debug.

    -

    Default: False

    -
    -
    -
    full_environment
    -

    Log all environment variables (including those set in the shell).

    -

    Default: False

    +
    +
    level
    +

    Set the logging level.

    +

    Available levels: debug, info, warning, error, critical

    +

    Default: warning

    mask_passwords

    Don't include passwords in logs.

    Default: True

    -
    -
    config
    -

    Logging configuration file. See the Logging page.

    -

    Default:

    -

    headers

    In this section additional HTTP headers that are sent to clients can be specified.

    An example to relax the same-origin policy:

    -
    Access-Control-Allow-Origin = *
    +
    Access-Control-Allow-Origin = *
    @@ -940,33 +877,33 @@ user2:password2

    This page describes the format of the rights file for the from_file authentication backend. The configuration option file in the rights section must point to the rights file.

    The recommended rights method is owner_only. If access to calendars and address books outside of the home directory of users (that's /USERNAME/) is granted, clients won't detect these collections and will not show them to the user. This is only useful if you access calendars and address books directly via URL.

    An example rights file:

    -
    # The user "admin" can read and write any collection.
    -[admin]
    -user = admin
    -collection = .*
    -permission = rw
    -
    -# Block access for the user "user" to everything.
    -[block]
    -user = user
    -collection = .*
    -permission =
    -
    -# Authenticated users can read and write their own collections.
    -[owner-write]
    -user = .+
    -collection = %(login)s(/.*)?
    -permission = rw
    -
    -# Everyone can read the root collection
    -[read]
    -user = .*
    -collection =
    -permission = r
    +
    # The user "admin" can read and write any collection.
    +[admin]
    +user = admin
    +collection = .*
    +permission = rw
    +
    +# Block access for the user "user" to everything.
    +[block]
    +user = user
    +collection = .*
    +permission =
    +
    +# Authenticated users can read and write their own collections.
    +[owner-write]
    +user = .+
    +collection = %(login)s(/.*)?
    +permission = rw
    +
    +# Everyone can read the root collection
    +[read]
    +user = .*
    +collection =
    +permission = r

    The titles of the sections are ignored (but must be unique). The keys user and collection contain regular expressions, that are matched against the user name and the path of the collection. Permissions from the first matching section are used. If no section matches, access gets denied.

    The user name is empty for anonymous users. Therefore, the regex .+ only matches authenticated users and .* matches everyone (including anonymous users).

    The path of the collection is separated by / and has no leading or trailing /. Therefore, the path of the root collection is empty.

    -

    %(login)s gets replaced by the user name and %(path)s by the path of the collection. You can also get groups from the user regex in the collection regex with {0}, {1}, etc.

    +

    %(login)s gets replaced by the user name and %(path)s by the path of the collection. You can also get groups from the user regex in the collection regex with {1}, {2}, etc.

    Storage

    @@ -992,10 +929,10 @@ user2:password2
    Linux shell scripts

    Use the flock utility.

    -
    # Exclusive
    -$ flock --exclusive /path/to/storage/.Radicale.lock COMMAND
    -# Shared
    -$ flock --shared /path/to/storage/.Radicale.lock COMMAND
    +
    # Exclusive
    +$ flock --exclusive /path/to/storage/.Radicale.lock COMMAND
    +# Shared
    +$ flock --shared /path/to/storage/.Radicale.lock COMMAND
    Linux and MacOS
    @@ -1009,61 +946,7 @@ user2:password2

    Logging

    -

    Radicale logs to stderr. The verbosity of the log output can be controlled with --debug command line argument or the debug configuration option in the logging section.

    -

    This is the recommended configuration for use with modern init systems (like systemd) or if you just test Radicale in a terminal.

    -

    You can configure Radicale to write its logging output to files (and even rotate them). This is useful if the process daemonizes or if your chosen method of running Radicale doesn't handle logging output.

    -

    A logging configuration file can be specified in the config configuration option in the logging section. The file format is explained in the Python Logging Module.

    -
    -

    Logging to a file

    -

    An example configuration to write the log output to the file /var/log/radicale/log:

    -
    [loggers]
    -keys = root
    -
    -[handlers]
    -keys = file
    -
    -[formatters]
    -keys = full
    -
    -[logger_root]
    -# Change this to DEBUG or INFO for higher verbosity.
    -level = WARNING
    -handlers = file
    -
    -[handler_file]
    -class = FileHandler
    -# Specify the output file here.
    -args = ('/var/log/radicale/log',)
    -formatter = full
    -
    -[formatter_full]
    -format = %(asctime)s - [%(thread)x] %(levelname)s: %(message)s
    -

    You can specify multiple logger, handler and formatter if you want to have multiple simultaneous log outputs.

    -

    The parent folder of the log files must exist and must be writable by Radicale.

    -

    Security: The log files should not be readable by unauthorized users. Set permissions accordingly.

    -
    -
    Timed rotation of disk log files
    -

    An example handler configuration to write the log output to the file /var/log/radicale/log and rotate it. Replace the section handler_file from the file logging example:

    -
    [handler_file]
    -class = handlers.TimedRotatingFileHandler
    -# Specify the output file and parameter for rotation here.
    -# See https://docs.python.org/3/library/logging.handlers.html#logging.handlers.TimedRotatingFileHandler
    -# Example: rollover at midnight and keep 7 files (means one week)
    -args = ('/var/log/radicale/log', 'midnight', 1, 7)
    -formatter = full
    -
    -
    -
    Rotation of disk log files based on size
    -

    An example handler configuration to write the log output to the file /var/log/radicale/log and rotate it . Replace the section handle_file from the file logging example:

    -
    [handler_file]
    -class = handlers.RotatingFileHandler
    -# Specify the output file and parameter for rotation here.
    -# See https://docs.python.org/3/library/logging.handlers.html#logging.handlers.RotatingFileHandler
    -# Example: rollover at 100000 kB and keep 10 files (means 1 MB)
    -args = ('/var/log/radicale/log', 'a', 100000, 10)
    -formatter = full
    -
    -
    +

    Radicale logs to stderr. The verbosity of the log output can be controlled with --debug command line argument or the level configuration option in the logging section.

    Architecture

    @@ -1117,16 +1000,22 @@ user2:password2

    Code Architecture

    -

    The radicale package offers 9 modules.

    -

    __main__ : The main module provides a simple function called run. Its main work is to read the configuration from the configuration file and from the options given in the command line; then it creates a server, according to the configuration.

    -

    __init__ : This is the core part of the module, with the code for the CalDAV/CardDAV server. The server inherits from a WSGIServer server class, which relies on the default HTTP server class given by Python. The code managing the different HTTP requests according to the CalDAV/CardDAV normalization is written here.

    -

    config : This part gives a dict-like access to the server configuration, read from the configuration file. The configuration can be altered when launching the executable with some command line options.

    -

    xmlutils : The functions defined in this module are mainly called by the CalDAV/CardDAV server class to read the XML part of the request, read or alter the calendars, and create the XML part of the response. The main part of this code relies on ElementTree.

    -

    log : The start function provided by this module starts a logging mechanism based on the default Python logging module. Logging options can be stored in a logging configuration file.

    -

    auth : This module provides a default authentication manager equivalent to Apache's htpasswd. Login + password couples are stored in a file and used to authenticate users. Passwords can be encrypted using various methods. Other authentication methods can inherit from the base class in this file and be provided as plugins.

    -

    rights : This module is a set of Access Control Lists, a set of methods used by Radicale to manage rights to access the calendars. When the CalDAV/CardDAV server is launched, an Access Control List is chosen in the set, according to the configuration. The HTTP requests are then filtered to restrict the access depending on who is authenticated. Other configurations can be written using regex-based rules. Other rights managers can also inherit from the base class in this file and be provided as plugins.

    -

    storage : In this module are written the classes representing collections and items in Radicale, and the class storing these collections and items in your filesystem. Other storage classes can inherit from the base class in this file and be provided as plugins.

    +

    The radicale package offers the following modules.

    +

    __init__ : Contains the entry point for WSGI.

    +

    __main__ : Provides the entry point for the radicale executable and includes the command line parser. It loads configuration files from the default (or specified) paths and starts the internal server.

    +

    app : This is the core part of Radicale, with the code for the CalDAV/CardDAV server. The code managing the different HTTP requests according to the CalDAV/CardDAV specification can be found here.

    +

    auth : Used for authenticating users based on username and password, mapping usernames to internal users and optionally retrieving credentials from the environment.

    +

    config : Contains the code for managing configuration and loading settings from files.

    +

    ìtem : Internal represenation of address book and calendar entries. Based on VObject.

    +

    log : The logger for Radicale based on the default Python logging module.

    +

    rights : This module is used by Radicale to manage access rights to collections, address books and calendars.

    +

    server : The integrated HTTP server for standalone use.

    +

    storage : This module contains the classes representing collections in Radicale and the code for storing and loading them in the filesystem.

    web : This module contains the web interface.

    +

    utils : Contains general helper functions.

    +

    httputils : Contains helper functions for working with HTTP.

    +

    pathutils : Helper functions for working with paths and the filesystem.

    +

    xmlutils : Helper functions for working with the XML part of CalDAV/CardDAV requests and responses. It's based on the ElementTree XML API.

    @@ -1134,54 +1023,59 @@ user2:password2

    Radicale can be extended by plugins for authentication, rights management and storage. Plugins are python modules.

    Getting started

    -

    To get started we walk through the creation of a simple authentication plugin, that accepts login attempts if the username and password are equal.

    +

    To get started we walk through the creation of a simple authentication plugin, that accepts login attempts with a static password.

    The easiest way to develop and install python modules is Distutils. For a minimal setup create the file setup.py with the following content in an empty folder:

    -
    #!/usr/bin/env python3
    -
    -from distutils.core import setup
    -
    -setup(name="radicale_silly_auth", packages=["radicale_silly_auth"])
    -

    In the same folder create the sub-folder radicale_silly_auth. The folder must have the same name as specified in packages above.

    -

    Create the file __init__.py in the radicale_silly_auth folder with the following content:

    -
    from radicale.auth import BaseAuth
    -
    -
    -class Auth(BaseAuth):
    -    def is_authenticated(self, user, password):
    -        # Example custom configuration option
    -        foo = ""
    -        if self.configuration.has_option("auth", "foo"):
    -            foo = self.configuration.get("auth", "foo")
    -        self.logger.info("Configuration option %r is %r", "foo", foo)
    -
    -        # Check authentication
    -        self.logger.info("Login attempt by %r with password %r",
    -                         user, password)
    -        return user == password
    +
    #!/usr/bin/env python3
    +
    +from distutils.core import setup
    +
    +setup(name="radicale_static_password_auth", packages=["radicale_static_password_auth"])
    +

    In the same folder create the sub-folder radicale_static_password_auth. The folder must have the same name as specified in packages above.

    +

    Create the file __init__.py in the radicale_static_password_auth folder with the following content:

    +
    from radicale.auth import BaseAuth
    +from radicale.log import logger
    +
    +PLUGIN_CONFIG_SCHEMA = {"auth": {
    +    "password": {"value": "", "type": str}}}
    +
    +
    +class Auth(BaseAuth):
    +    def __init__(self, configuration):
    +        super().__init__(configuration.copy(PLUGIN_CONFIG_SCHEMA))
    +
    +    def login(self, user, password):
    +        # Get password from configuration option
    +        static_password = self.configuration.get("auth", "password")
    +        # Check authentication
    +        logger.info("Login attempt by %r with password %r",
    +                    user, password)
    +        if password == static_password:
    +            return user
    +        return ""

    Install the python module by running the following command in the same folder as setup.py:

    -
    python3 -m pip install --upgrade .
    -

    To make use this great creation in Radicale, set the configuration option type in the auth section to radicale_silly_auth:

    -
    [auth]
    -type = radicale_silly_auth
    -foo = bar
    +
    python3 -m pip install --upgrade .
    +

    To make use this great creation in Radicale, set the configuration option type in the auth section to radicale_static_password_auth:

    +
    [auth]
    +type = radicale_static_password_auth
    +password = secret

    You can uninstall the module with:

    -
    python3 -m pip uninstall radicale_silly_auth
    +
    python3 -m pip uninstall radicale_static_password_auth

    Authentication plugins

    -

    This plugin type is used to check login credentials. The module must contain a class Auth that extends radicale.auth.BaseAuth. Take a look at the file radicale/auth.py in Radicale's source code for more information.

    +

    This plugin type is used to check login credentials. The module must contain a class Auth that extends radicale.auth.BaseAuth. Take a look at the file radicale/auth/__init__.py in Radicale's source code for more information.

    Rights management plugins

    -

    This plugin type is used to check if a user has access to a path. The module must contain a class Rights that extends radicale.rights.BaseRights. Take a look at the file radicale/rights.py in Radicale's source code for more information.

    +

    This plugin type is used to check if a user has access to a path. The module must contain a class Rights that extends radicale.rights.BaseRights. Take a look at the file radicale/rights/__init__.py in Radicale's source code for more information.

    Web plugins

    -

    This plugin type is used to provide the web interface for Radicale. The module must contain a class Web that extends radicale.web.BaseWeb. Take a look at the file radicale/web.py in Radicale's source code for more information.

    +

    This plugin type is used to provide the web interface for Radicale. The module must contain a class Web that extends radicale.web.BaseWeb. Take a look at the file radicale/web/__init__.py in Radicale's source code for more information.

    Storage plugins

    -

    This plugin is used to store collections and items. The module must contain a class Collection that extends radicale.storage.BaseCollection. Take a look at the file radicale/storage.py in Radicale's source code for more information.

    +

    This plugin is used to store collections and items. The module must contain a class Storage that extends radicale.storage.BaseStorage. Take a look at the file radicale/storage/__init__.py in Radicale's source code for more information.

    @@ -1197,7 +1091,7 @@ user2:password2

    Hack

    -

    Interested in hacking? Feel free to clone the git repository on Github if you want to add new features, fix bugs or update the documentation.

    +

    Interested in hacking? Feel free to clone the git repository on GitHub if you want to add new features, fix bugs or update the documentation.

    Documentation

    @@ -1221,35 +1115,7 @@ user2:password2

    Source Packages

    -

    You can download the Radicale package for each release:

    - +

    You can find the source packages of all releases on GitHub.

    Linux Distribution Packages