diff --git a/master.html b/master.html index cdc0a4d3..aa489529 100644 --- a/master.html +++ b/master.html @@ -176,23 +176,23 @@ connection between Radicale and the reverse proxy
  • Manage user accounts with the WSGI server
  • -
  • Versioning with Git
  • +
  • Versioning collections with +Git
  • Documentation
  • Supported @@ -202,11 +202,13 @@ Clients
  • OneCalendar
  • GNOME Calendar, Contacts
  • Evolution
  • +
  • KDE +PIM Applications
  • Thunderbird
  • InfCloud, CalDavZAP and CardDavMATE
  • Command line
  • -
  • Authentication and Rights
  • +
  • Authorization and Rights
  • Storage
  • Plugins -

    Hint: instead of downloading from PyPI look for packages provided by -used distribution, they -contain also startup scripts to run daemonized.

    What's New?

    @@ -315,17 +315,21 @@ on GitHub.

    Simple 5-minute setup

    You want to try Radicale but only have 5 minutes free in your calendar? Let's go right now and play a bit with Radicale!

    -

    When everything works, you can get a client and start creating calendars and -address books. The server, configured with settings from this section, -only binds to localhost (is not reachable over the network) and you can -log in with any user name and password. When everything works, you may -get a local client and start creating calendars and address books. If -Radicale fits your needs, it may be time for some basic configuration to support remote -clients and desired authentication type.

    +

    The server, configured with settings from this section, only binds to +localhost (i.e. it is not reachable over the network), and you can log +in with any username and password. When everything works, you may get a +local client and start creating +calendars and address books. If Radicale fits your needs, it may be time +for some basic configuration to +support remote clients and desired authentication type.

    Follow one of the chapters below depending on your operating system.

    Linux / *BSD

    +

    Hint: instead of downloading from PyPI, look for packages provided by +your distribution. They +contain also startup scripts integrated into your distributions, that +allow Radicale to run daemonized.

    First, make sure that python 3.9 or later and pip are installed. On most distributions it should be enough to install the package python3-pip.

    @@ -336,7 +340,7 @@ enough to install the package python3-pip.

    python3 -m pip install --user --upgrade https://github.com/Kozea/Radicale/archive/master.tar.gz

    If install is not working and instead error: externally-managed-environment is displayed, create -and activate a virtual environment in advance

    +and activate a virtual environment in advance.

    python3 -m venv ~/venv
     source ~/venv/bin/activate

    and try to install with

    @@ -348,12 +352,13 @@ user

    as system user (or as root)
    -

    Alternative one can install and run as system user or as root (not -recommended)

    -
    # Run the following command as root (not required)
    -# or non-root system user (can require --user in case of dependencies are not available system-wide and/or virtual environment)
    +

    Alternatively, you can install and run as system user or as root (not +recommended):

    +
    # Run the following command as root (not recommended) or non-root system user
    +# (the later may require --user in case dependencies are not available system-wide and/or virtual environment)
     python3 -m pip install --upgrade https://github.com/Kozea/Radicale/archive/master.tar.gz
    -

    Start the service manually, data is stored in a system folder

    +

    Start the service manually, with data stored in a system folder under +/var/lib/radicale/collections:

    # Start, data is stored in a system folder (requires write permissions to /var/lib/radicale/collections)
     python3 -m radicale --storage-filesystem-folder=/var/lib/radicale/collections --auth-type none
    @@ -369,14 +374,13 @@ now". Wait a couple of minutes, it's done!

    python -m radicale --storage-filesystem-folder=~/radicale/collections --auth-type none
    Common
    -

    Victory! Open http://localhost:5232 in your browser! +

    Success!!! Open http://localhost:5232 in your browser! You can log in with any username and password as no authentication is -required by example option --auth-type none. But this is -INSECURE, see Configuration/Authentication for -more.

    +required by example option --auth-type none. This is +INSECURE, see Configuration/Authentication for more details.

    Just note that default configuration for security reason binds the server to localhost (IPv4: 127.0.0.1, IPv6: -::1). See Addresses and Configuration/Server for more.

    +::1). See Addresses and Configuration/Server for more details.

    @@ -397,23 +401,26 @@ passed via command line arguments.)

    All configuration options are described in detail in the Configuration section.

    Authentication

    -

    In its default configuration since 3.5.0 Radicale rejects by default -all authentication by type = denyall (introduced with -3.2.2) until explicitly configured.

    -

    Before 3.5.0 it didn't check usernames or passwords if not explicitly -configured, and if the server is reachable over a network, you should -change this as soon as possible.

    +

    In its default configuration since version 3.5.0, Radicale rejects +all authentication attempts by using config option +type = denyall (introduced with 3.2.2) as default until +explicitly configured.

    +

    Versions before 3.5.0 did not check usernames or passwords at all, +unless explicitly configured. If such a server is reachable over a +network, you should change this as soon as possible.

    First a users file with all usernames and passwords must be created. It can be stored in the same directory as the configuration file.

    The secure way

    The users file can be created and managed with htpasswd:

    -

    Note: some OS contain unpatched htpasswd (< 2.4.59) -without supporting SHA-256 or SHA-512 (e.g. Ubuntu LTS 22), in this case -use '-B' for "bcrypt" hash method or stay with insecure MD5 (default) or -SHA-1 ('-s').

    -

    Note that support of SHA-256 or SHA-512 was introduced with 3.1.9

    +

    Note: some OSes or distributions contain outdated versions of +htpasswd (< 2.4.59) without support for SHA-256 or +SHA-512 (e.g. Ubuntu LTS 22). In these cases use htpasswd's +command line option -B for the bcrypt hash +method (recommended), or stay with the insecure (not recommended) MD5 +(default) or SHA-1 (command line option -s).

    +

    Note: support of SHA-256 and SHA-512 was introduced with 3.1.9

    # Create a new htpasswd file with the user "user1" using SHA-512 as hash method
     $ htpasswd -5 -c /path/to/users user1
     New password:
    @@ -444,7 +451,7 @@ user2:password2

    Addresses

    -

    The default configuration binds the server to localhost. It can't be +

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

    [server]
    @@ -458,7 +465,7 @@ the following configuration:

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

    Security: The storage folder should not be readable +

    Security: The storage folder shall 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.

    @@ -492,89 +499,87 @@ operating system and requirements.

    Recommendation: check support by Linux Distribution Packages instead of manual setup / initial configuration.

    Create the radicale user and group for the Radicale -service. (Run -useradd --system --user-group --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.)

    -

    If a dedicated cache folder is configured (see option 'storage' -> -'filesystem_cache_folder'), it also must be also writable by -radicale. (Run -mkdir -p /var/cache/radicale && chown -R radicale:radicale /var/cache/radicale -as root.)

    +service by running (as root:

    +
    useradd --system --user-group --home-dir / --shell /sbin/nologin radicale
    +

    The storage folder must be writable by the radicale +user by running (as root):

    +
    mkdir -p /var/lib/radicale/collections && chown -R radicale:radicale /var/lib/radicale/collections
    +

    If a dedicated cache folder is configured (see option filesystem_cache_folder), it also +must be also writable by radicale. To achieva that, run +(as root):

    +
    mkdir -p /var/cache/radicale && chown -R radicale:radicale /var/cache/radicale
    -

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

    +

    Security: The storage shall not be readable by +others. To make sure this is the case, run (as root):

    +
    chmod -R o= /var/lib/radicale/collections

    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/
    -# Replace with following in case of dedicated cache folder should be used
    -#ReadWritePaths=/var/lib/radicale/ /var/cache/radicale/
    -
    -[Install]
    -WantedBy=multi-user.target
    -

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

    +
    [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/
    +# Replace with following in case dedicated cache folder should be used
    +#ReadWritePaths=/var/lib/radicale/ /var/cache/radicale/
    +
    +[Install]
    +WantedBy=multi-user.target
    +

    In this system-wide implementation, Radicale will load the +configuration from the file /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

    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
    -

    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 +

    [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
    +

    In this user-specific configuration, Radicale will load the +configuration from the file ~/.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

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

    @@ -639,31 +644,31 @@ below.

    }

    Example Apache configuration extension:

    See also for latest examples: https://github.com/Kozea/Radicale/tree/master/contrib/apache/

    -
    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
    -    RequestHeader    set X-Forwarded-Port "%{SERVER_PORT}s"
    -    RequestHeader    set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
    -    <IfVersion >= 2.4.40>
    -    Proxy100Continue Off
    -    </IfVersion>
    -</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
    +    RequestHeader    set X-Forwarded-Port "%{SERVER_PORT}s"
    +    RequestHeader    set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
    +    <IfVersion >= 2.4.40>
    +    Proxy100Continue Off
    +    </IfVersion>
    +</Location>

    Example Apache .htaccess configuration:

    -
    DirectoryIndex disabled
    -RewriteEngine On
    -RewriteRule ^(.*)$ http://localhost:5232/$1 [P,L]
    -
    -# Set to directory of .htaccess file:
    -RequestHeader set X-Script-Name /radicale
    -RequestHeader set X-Forwarded-Port "%{SERVER_PORT}s"
    -RequestHeader unset X-Forwarded-Proto
    -<If "%{HTTPS} =~ /on/">
    -RequestHeader set X-Forwarded-Proto "https"
    -</If>
    +
    DirectoryIndex disabled
    +RewriteEngine On
    +RewriteRule ^(.*)$ http://localhost:5232/$1 [P,L]
    +
    +# Set to directory of .htaccess file:
    +RequestHeader set X-Script-Name /radicale
    +RequestHeader set X-Forwarded-Port "%{SERVER_PORT}s"
    +RequestHeader unset X-Forwarded-Proto
    +<If "%{HTTPS} =~ /on/">
    +RequestHeader set X-Forwarded-Proto "https"
    +</If>

    Example lighttpd configuration:

    server.modules += ( "mod_proxy" , "mod_setenv", "mod_rewrite" )
     
    @@ -686,7 +691,7 @@ terminated after a timeout.

    Set the configuration option type in the auth section to http_x_remote_user. Radicale uses the username provided in the X-Remote-User HTTP header -and disables HTTP authentication.

    +and disables its internal HTTP authentication.

    Example nginx configuration:

    location /radicale/ {
         proxy_pass           http://localhost:5232/;
    @@ -709,42 +714,41 @@ and disables HTTP authentication.

    } }

    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/
    -    <IfVersion >= 2.4.40>
    -    Proxy100Continue Off
    -    </IfVersion>
    -    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/
    +    <IfVersion >= 2.4.40>
    +    Proxy100Continue Off
    +    </IfVersion>
    +    RequestHeader    set X-Script-Name /radicale
    +    RequestHeader    set X-Remote-User expr=%{REMOTE_USER}
    +</Location>

    Example Apache .htaccess configuration:

    -
    DirectoryIndex disabled
    -RewriteEngine On
    -RewriteRule ^(.*)$ http://localhost:5232/$1 [P,L]
    -
    -AuthType     Basic
    -AuthName     "Radicale - Password Required"
    -AuthUserFile "/etc/radicale/htpasswd"
    -Require      valid-user
    -
    -# Set to directory of .htaccess file:
    -RequestHeader set X-Script-Name /radicale
    -RequestHeader set X-Remote-User expr=%{REMOTE_USER}
    +
    DirectoryIndex disabled
    +RewriteEngine On
    +RewriteRule ^(.*)$ http://localhost:5232/$1 [P,L]
    +
    +AuthType     Basic
    +AuthName     "Radicale - Password Required"
    +AuthUserFile "/etc/radicale/htpasswd"
    +Require      valid-user
    +
    +# Set to directory of .htaccess file:
    +RequestHeader set X-Script-Name /radicale
    +RequestHeader set X-Remote-User expr=%{REMOTE_USER}

    Security: Untrusted clients should not be able to access the Radicale server directly. Otherwise, they can authenticate as any user by simply setting related HTTP header. This can be prevented by -restrict listen to loopback interface only or at least a local firewall -rule.

    +listening to the loopback interface only or local firewall rules.

    @@ -753,24 +757,24 @@ rule.

    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
    +will be asked to enter additional information about the certificate, +these values do not really 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

    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
    -

    If you're using the Let's Encrypt's Certbot, the configuration should +

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

    If you are using the Let's Encrypt Certbot, the configuration should look similar to this:

    -
    [server]
    -ssl = True
    -certificate = /etc/letsencrypt/live/{Your Domain}/fullchain.pem
    -key = /etc/letsencrypt/live/{Your Domain}/privkey.pem
    +
    [server]
    +ssl = True
    +certificate = /etc/letsencrypt/live/{Your Domain}/fullchain.pem
    +key = /etc/letsencrypt/live/{Your Domain}/privkey.pem

    Example nginx configuration:

    location /radicale/ {
         proxy_pass https://localhost:5232/;
    @@ -788,60 +792,60 @@ look similar to this:

    environment variable, otherwise no configuration file is loaded and the default configuration is used.

    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' --env 'RADICALE_CONFIG=/etc/radicale/config' \
    -         --workers 8 radicale
    +
    gunicorn --bind '127.0.0.1:5232' --env 'RADICALE_CONFIG=/etc/radicale/config' \
    +         --workers 8 radicale

    Manage user accounts with the WSGI server

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

    +auth section to remote_user. This way Radicale +uses the username provided by the WSGI server and disables its internal +authentication over HTTP.

    -
    -

    Versioning with Git

    +
    +

    Versioning collections with Git

    This tutorial describes how to keep track of all changes to calendars and address books with git (or any other version control system).

    The repository must be initialized in the collection base directory of the user running radicale daemon.

    -
    ## assuming "radicale" user is starting "radicale" service
    -# change to user "radicale"
    -su -l -s /bin/bash radicale
    -
    -# change to collection base directory defined in [storage] -> filesystem_folder
    -#  assumed here /var/lib/radicale/collections
    -cd /var/lib/radicale/collections
    -
    -# initialize git repository
    -git init
    -
    -# set user and e-mail, here minimum example
    -git config user.name "$USER"
    -git config user.email "$USER@$HOSTNAME"
    -
    -# define ignore of cache/lock/tmp files
    -cat <<'END' >.gitignore
    -.Radicale.cache
    -.Radicale.lock
    -.Radicale.tmp-*
    -END
    +
    ## assuming "radicale" user is starting "radicale" service
    +# change to user "radicale"
    +su -l -s /bin/bash radicale
    +
    +# change to collection base directory defined in [storage] -> filesystem_folder
    +#  assumed here /var/lib/radicale/collections
    +cd /var/lib/radicale/collections
    +
    +# initialize git repository
    +git init
    +
    +# set user and e-mail, here minimum example
    +git config user.name "$USER"
    +git config user.email "$USER@$HOSTNAME"
    +
    +# define ignore of cache/lock/tmp files
    +cat <<'END' >.gitignore
    +.Radicale.cache
    +.Radicale.lock
    +.Radicale.tmp-*
    +END

    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.

    Log of git can be investigated using

    -
    su -l -s /bin/bash radicale
    -cd /var/lib/radicale/collections
    -git log
    +
    su -l -s /bin/bash radicale
    +cd /var/lib/radicale/collections
    +git log

    In case of problems, make sure you run radicale with --debug switch and inspect the log output. For more information, please visit section on @@ -860,18 +864,20 @@ logging.

    Configuration

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

    +

    Configuration files have INI-style syntax comprising key-value pairs +grouped into sections with section headers enclosed in brackets.

    An example configuration file looks like:

    -
    [server]
    -# Bind all addresses
    -hosts = 0.0.0.0:5232, [::]:5232
    -
    -[auth]
    -type = htpasswd
    -htpasswd_filename = ~/.config/radicale/users
    -htpasswd_encryption = autodetect
    -
    -[storage]
    -filesystem_folder = ~/.var/lib/radicale/collections
    +
    [server]
    +# Bind all addresses
    +hosts = 0.0.0.0:5232, [::]:5232
    +
    +[auth]
    +type = htpasswd
    +htpasswd_filename = ~/.config/radicale/users
    +htpasswd_encryption = autodetect
    +
    +[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 @@ -882,34 +888,32 @@ configuration files can be separated by : (resp. optional.

    The same example configuration via command line arguments looks like:

    -
    python3 -m radicale --server-hosts 0.0.0.0:5232,[::]:5232 \
    -        --auth-type htpasswd --auth-htpasswd-filename ~/.config/radicale/users \
    -        --auth-htpasswd-encryption autodetect
    +
    python3 -m radicale --server-hosts 0.0.0.0:5232,[::]:5232 \
    +        --auth-type htpasswd --auth-htpasswd-filename ~/.config/radicale/users \
    +        --auth-htpasswd-encryption autodetect

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

    -

    One can also use command line options in startup scripts using -following examples:

    -
    ## simple variable containing multiple options
    -RADICALE_OPTIONS="--logging-level=debug --config=/etc/radicale/config --logging-request-header-on-debug --logging-rights-rule-doesnt-match-on-debug"
    -/usr/bin/radicale $RADICALE_OPTIONS
    -
    -## variable as array method #1
    -RADICALE_OPTIONS=("--logging-level=debug" "--config=/etc/radicale/config" "--logging-request-header-on-debug" "--logging-rights-rule-doesnt-match-on-debug")
    -/usr/bin/radicale ${RADICALE_OPTIONS[@]}
    -
    -## variable as array method #2
    -RADICALE_OPTIONS=()
    -RADICALE_OPTIONS+=("--logging-level=debug")
    -RADICALE_OPTIONS+=("--config=/etc/radicale/config")
    -/usr/bin/radicale ${RADICALE_OPTIONS[@]}
    -

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

    +

    You can also use command-line options in startup scripts as shown in +the following examples:

    +
    ## simple variable containing multiple options
    +RADICALE_OPTIONS="--logging-level=debug --config=/etc/radicale/config --logging-request-header-on-debug --logging-rights-rule-doesnt-match-on-debug"
    +/usr/bin/radicale $RADICALE_OPTIONS
    +
    +## variable as array method #1
    +RADICALE_OPTIONS=("--logging-level=debug" "--config=/etc/radicale/config" "--logging-request-header-on-debug" "--logging-rights-rule-doesnt-match-on-debug")
    +/usr/bin/radicale ${RADICALE_OPTIONS[@]}
    +
    +## variable as array method #2
    +RADICALE_OPTIONS=()
    +RADICALE_OPTIONS+=("--logging-level=debug")
    +RADICALE_OPTIONS+=("--config=/etc/radicale/config")
    +/usr/bin/radicale ${RADICALE_OPTIONS[@]}
    +

    The following describes all configuration sections and options.

    -

    server

    -

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

    +

    [server]

    +

    The configuration options in this section are only relevant in +standalone mode; they are ignored, when Radicale runs on WSGI.

    hosts

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

    @@ -982,7 +986,7 @@ Format: OpenSSL cipher list (see also "man openssl-ciphers")

    -

    encoding

    +

    [encoding]

    request

    Encoding for responding requests.

    @@ -995,53 +999,59 @@ Format: OpenSSL cipher list (see also "man openssl-ciphers")

    -

    auth

    +

    [auth]

    type

    The method to verify usernames and passwords.

    -

    Available backends:

    -

    none : Just allows all usernames and passwords.

    -

    denyall (>= 3.2.2) : Just denies all -usernames and passwords.

    -

    htpasswd : Use an Apache -htpasswd file to store usernames and passwords.

    -

    remote_user : Takes the username from the -REMOTE_USER environment variable and disables HTTP -authentication. This can be used to provide the username from a WSGI -server which authenticated the client upfront. Required to validate, -otherwise client can supply the header itself which is unconditionally -trusted then.

    -

    http_x_remote_user : Takes the username from the -X-Remote-User HTTP header and disables HTTP authentication. -This can be used to provide the username from a reverse proxy which -authenticated the client upfront. Required to validate, otherwise client -can supply the header itself which is unconditionally trusted then.

    -

    ldap (>= 3.3.0) : Use a LDAP or AD server to -authenticate users by relaying credentials from client and handle -result.

    -

    dovecot (>= 3.3.1) : Use a Dovecot server to -authenticate users by relaying credentials from client and handle -result.

    -

    imap (>= 3.4.1) : Use an IMAP server to -authenticate users by relaying credentials from client and handle -result.

    -

    oauth2 (>= 3.5.0) : Use an OAuth2 server to -authenticate users by relaying credentials from client and handle -result. Oauth2 authentication (SSO) directly on client is not supported. -Use herefore http_x_remote_user in combination with SSO -support in reverse proxy (e.g. Apache+mod_auth_openidc).

    -

    pam (>= 3.5.0) : Use local PAM to -authenticate users by relaying credentials from client and handle -result..

    -

    Default: none (< 3.5.0) denyall -(>= 3.5.0)

    +

    Available types are:

    +
      +
    • none
      +Just allows all usernames and passwords.

    • +
    • denyall (>= 3.2.2)
      +Just denies all usernames and passwords.

    • +
    • htpasswd
      +Use an Apache +htpasswd file to store usernames and passwords.

    • +
    • remote_user
      +Takes the username from the REMOTE_USER environment +variable and disables Radicale's internal HTTP authentication. This can +be used to provide the username from a WSGI server which authenticated +the client upfront. Requires validation, otherwise clients can supply +the header themselves, which then is unconditionally trusted.

    • +
    • http_x_remote_user
      +Takes the username from the X-Remote-User HTTP header and +disables Radicale's internal HTTP authentication. This can be used to +provide the username from a reverse proxy which authenticated the client +upfront. Requires validation, otherwise clients can supply the header +themselves, which then is unconditionally trusted.

    • +
    • ldap (>= 3.3.0)
      +Use a LDAP or AD server to authenticate users by relaying credentials +from clients and handle results.

    • +
    • dovecot (>= 3.3.1)
      +Use a Dovecot server to authenticate users by relaying credentials from +clients and handle results.

    • +
    • imap (>= 3.4.1)
      +Use an IMAP server to authenticate users by relaying credentials from +clients and handle results.

    • +
    • oauth2 (>= 3.5.0)
      +Use an OAuth2 server to authenticate users by relaying credentials from +clients and handle results. OAuth2 authentication (SSO) directly on +client is not supported. Use herefore http_x_remote_user in +combination with SSO support in reverse proxy (e.g. +Apache+mod_auth_openidc).

    • +
    • pam (>= 3.5.0)
      +Use local PAM to authenticate users by relaying credentials from client +and handle result..

    • +
    +

    Default: none (< 3.5.0) / +denyall (>= 3.5.0)

    cache_logins

    (>= 3.4.0)

    Cache successful/failed logins until expiration time. Enable this to avoid overload of authentication backends.

    -

    Default: false

    +

    Default: False

    cache_successful_logins_expiry
    @@ -1062,29 +1072,35 @@ avoid overload of authentication backends.

    htpasswd_encryption
    -

    The encryption method that is used in the htpasswd file. Use the htpasswd +

    The encryption method that is used in the htpasswd file. Use htpasswd or similar to generate this files.

    Available methods:

    -

    plain : Passwords are stored in plaintext. This is -obviously not secure! The htpasswd file for this can be created by hand -and looks like:

    +
      +
    • plain
      +Passwords are stored in plaintext. This is not recommended. as it is +obviously insecure! The htpasswd file for this can be +created by hand and looks like:

      user1:password1
      -user2:password2
      -

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

      -

      md5 : This uses an iterated MD5 digest of the password -with a salt (nowadays insecure).

      -

      sha256 (>= 3.1.9) : This uses an iterated -SHA-256 digest of the password with a salt.

      -

      sha512 (>= 3.1.9) : This uses an iterated -SHA-512 digest of the password with a salt.

      -

      argon2 (>= 3.5.3) : This uses an iterated -ARGON2 digest of the password with a salt. The installation of -argon2-cffi is required for this.

      -

      autodetect (>= 3.1.9) : This selects -autodetection of method per entry.

      -

      Default: md5 (< 3.3.0) +user2:password2

    • +
    • bcrypt
      +This uses a modified version of the Blowfish stream cipher, which is +considered very secure. The installation of Python's +bcrypt module is required for this to work.

    • +
    • md5
      +Use an iterated MD5 digest of the password with salt (nowadays +insecure).

    • +
    • sha256 (>= 3.1.9)
      +Use an iterated SHA-256 digest of the password with salt.

    • +
    • sha512 (>= 3.1.9)
      +Use an iterated SHA-512 digest of the password with salt.

    • +
    • argon2 (>= 3.5.3)
      +Use an iterated ARGON2 digest of the password with salt. The +installation of Python's argon2-cffi module is required +for this to work.

    • +
    • autodetect (>= 3.1.9)
      +Automatically detect the encryption method used per user entry.

    • +
    +

    Default: md5 (< 3.3.0) / autodetect (>= 3.3.0)

    @@ -1095,7 +1111,7 @@ autodetection of method per entry.

    delay
    -

    Average delay after failed login attempts in seconds.

    +

    Average delay (in seconds) after failed login attempts.

    Default: 1

    @@ -1152,10 +1168,10 @@ must contain '{0}' as placeholder for the login name.

    LDAP attribute whose value shall be used as the username after successful authentication.

    If set, you can use flexible logins in ldap_filter and -still have consolidated usernames, e.g. to allow login in using mail -addresses as an alternative to cn, simply set

    -
    ldap_filter = (&(objectclass=inetOrgPerson)(|(cn={0})(mail={0})))
    -ldap_user_attribute = cn
    +still have consolidated usernames, e.g. to allow users to login using +mail addresses as an alternative to cn, simply set

    +
    ldap_filter = (&(objectclass=inetOrgPerson)(|(cn={0})(mail={0})))
    +ldap_user_attribute = cn

    Even for simple filter setups, it is recommended to set it in order to get usernames exactly as they are stored in LDAP and to avoid inconsistencies in the upper-/lower-case spelling of the login @@ -1166,21 +1182,31 @@ username)

    ldap_use_ssl

    (>= 3.3.0)

    -

    Use ssl on the LDAP connection. Deprecated, use -ldap_security instead**!**

    +

    Use ssl on the LDAP connection. Deprecated! Use +ldap_security instead.

    ldap_security

    (>= 3.5.2)

    -

    Use encryption on the LDAP connection. One of none, -tls, starttls.

    +

    Use encryption on the LDAP connection.

    +

    One of

    +
      +
    • none
    • +
    • tls
    • +
    • starttls
    • +

    Default: none

    ldap_ssl_verify_mode

    (>= 3.3.0)

    -

    Certificate verification mode for tls and starttls. One of -NONE, OPTIONAL, REQUIRED.

    +

    Certificate verification mode for tls and starttls.

    +

    One of

    +
      +
    • NONE
    • +
    • OPTIONAL
    • +
    • REQUIRED.
    • +

    Default: REQUIRED

    @@ -1256,34 +1282,39 @@ the user's DN is in.

    Quirks for Authentik LDAP server, which violates the LDAP RFCs: add modifyTimestamp and createTimestamp to the exclusion list of internal ldap3 client so that these schema attributes are not checked.

    -

    Default: false

    +

    Default: False

    -
    -
    dovecot_connection_type = AF_UNIX
    +
    +
    dovecot_connection_type

    (>= 3.4.1)

    -

    Connection type for dovecot authentication -(AF_UNIX|AF_INET|AF_INET6)

    +

    Connection type for dovecot authentication.

    +

    One of:

    +
      +
    • AF_UNIX
    • +
    • AF_INET
    • +
    • AF_INET6
    • +

    Note: credentials are transmitted in cleartext

    Default: AF_UNIX

    dovecot_socket

    (>= 3.3.1)

    -

    The path to the Dovecot client authentication socket (eg. -/run/dovecot/auth-client on Fedora). Radicale must have read / write +

    Path to the Dovecot client authentication socket (eg. +/run/dovecot/auth-client on Fedora). Radicale must have read & write access to the socket.

    Default: /var/run/dovecot/auth-client

    dovecot_host

    (>= 3.4.1)

    -

    Host of via network exposed dovecot socket

    +

    Host of dovecot socket exposed via network

    Default: localhost

    dovecot_port

    (>= 3.4.1)

    -

    Port of via network exposed dovecot socket

    +

    Port of dovecot socket exposed via network

    Default: 12345

    @@ -1307,59 +1338,73 @@ passed to dovecot is reliable. For example, for nginx, add

    imap_host

    (>= 3.4.1)

    -

    IMAP server hostname: address | address:port | [address]:port | -imap.server.tld

    +

    IMAP server hostname.

    +

    One of:

    +
      +
    • address
    • +
    • address:port
    • +
    • +
    • imap.server.tld
    • +

    Default: localhost

    imap_security

    (>= 3.4.1)

    -

    Secure the IMAP connection: tls | starttls | none

    +

    Secure the IMAP connection:

    +

    One of:

    +
      +
    • tls
    • +
    • starttls
    • +
    • none
    • +

    Default: tls

    oauth2_token_endpoint

    (>= 3.5.0)

    -

    OAuth2 token endpoint URL

    -

    Default:

    +

    Endpoint URL for the OAuth2 token

    +

    Default: (unset)

    pam_service

    (>= 3.5.0)

    -

    PAM service

    -

    Default: radicale

    +

    PAM service name

    +

    Default: radicale

    pam_group_membership

    (>= 3.5.0)

    PAM group user should be member of

    -

    Default:

    +

    Default: (unset)

    lc_username
    -

    Сonvert username to lowercase, must be true for case-insensitive auth -providers like ldap, kerberos

    +

    Сonvert username to lowercase. Recommended to be True +for case-insensitive auth providers like ldap, kerberos, ...

    Default: False

    Notes:

    • lc_username and uc_username are mutually exclusive
    • for auth type ldap the use of -ldap_user_attribute is preferred
    • +ldap_user_attribute is preferred over +lc_username
    uc_username

    (>= 3.3.2)

    -

    Сonvert username to uppercase, must be true for case-insensitive auth -providers like ldap, kerberos

    +

    Сonvert username to uppercase. Recommended to be True +for case-insensitive auth providers like ldap, kerberos, ...

    Default: False

    Notes:

    • uc_username and lc_username are mutually exclusive
    • for auth type ldap the use of -ldap_user_attribute is preferred
    • +ldap_user_attribute is preferred over +uc_username
    @@ -1371,81 +1416,99 @@ exclusive
  • urldecode_username

    (>= 3.5.3)

    -

    URL Decode the username. When the username is an email, some clients -send the username URL-encoded (notably iOS devices) breaking the +

    URL-decode the username. If the username is an email address, some +clients send the username URL-encoded (notably iOS devices) breaking the authentication process (user@example.com becomes -user%40example.com). This setting will force decoding the username.

    +user%40example.com). This setting forces decoding the username.

    Default: False

    -

    rights

    +

    [rights]

    type
    -

    The backend that is used to check the access rights of +

    Authorization backend that is used to check the access rights to collections.

    -

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

    -

    Available backends:

    -

    authenticated : Authenticated users can read and write -everything.

    -

    owner_only : Authenticated users can read and write -their own collections under the path /USERNAME/.

    -

    owner_write : Authenticated users can read everything -and write their own collections under the path /USERNAME/.

    -

    from_file : Load the rules from a file.

    +

    The default and recommended backend is owner_only. If +access to calendars and address books outside the user's collection +directory (that's /username/) is granted, clients will not +detect these collections automatically and will not show them to the +users. Choosing any other authorization backend is only useful if you +access calendars and address books directly via URL.

    +

    Available backends are:

    +
      +
    • authenticated
      +Authenticated users can read and write everything.

    • +
    • owner_only
      +Authenticated users can read and write their own collections under the +path /USERNAME/.

    • +
    • owner_write
      +Authenticated users can read everything and write their own collections +under the path /USERNAME/.

    • +
    • from_file
      +Load the rules from a file.

    • +

    Default: owner_only

    file
    -

    File for the rights backend from_file. See the Rights section.

    +

    Name of the file containing the authorization rules for the +from_file backend. See the Rights section for details.

    +

    Default: /etc/radicale/rights

    permit_delete_collection

    (>= 3.1.9)

    -

    Global control of permission to delete complete collection (default: -True)

    -

    If False it can be permitted by permissions per section with: D

    -

    If True it can be forbidden by permissions per section with: d

    +

    Global permission to delete complete collections.

    +
      +
    • If False it can be explicitly granted per collection by +permissions: D
    • +
    • If True it can be explicitly forbidden per collection +by permissions: d
    • +
    +

    Default: True

    permit_overwrite_collection

    (>= 3.3.0)

    -

    Global control of permission to overwrite complete collection -(default: True)

    -

    If False it can be permitted by permissions per section with: O

    -

    If True it can be forbidden by permissions per section with: o

    +

    Global permission to overwrite complete collections.

    +
      +
    • If False it can be explicitly granted per collection by +permissions: O
    • +
    • If True it can be explicitly forbidden per collection +by permissions: o
    • +
    +

    Default: True

    -

    storage

    +

    [storage]

    type
    -

    The backend that is used to store data.

    -

    Available backends:

    -

    multifilesystem : Stores the data in the filesystem.

    -

    multifilesystem_nolock : The -multifilesystem backend without file-based locking. Must -only be used with a single process.

    +

    Backend used to store data.

    +

    Available backends are:

    +
      +
    • multifilesystem
      +Stores the data in the filesystem.

    • +
    • multifilesystem_nolock
      +The multifilesystem backend without file-based locking. +Must only be used with a single process.

    • +

    Default: multifilesystem

    filesystem_folder
    -

    Folder for storing local collections, created if not present.

    +

    Folder for storing local collections; will be auto-created if not +present.

    Default: /var/lib/radicale/collections

    filesystem_cache_folder

    (>= 3.3.2)

    -

    Folder for storing cache of local collections, created if not -present

    +

    Folder for storing cache of local collections; will be auto-created +if not present

    Default: (filesystem_folder)

    -

    Note: only used in case of use_cache_subfolder_* options are -active

    +

    Note: only used if use_cache_subfolder_* options are active

    Note: can be used on multi-instance setup to cache files on local node (see below)

    @@ -1466,8 +1529,8 @@ node

    of 'history' instead of inside collection folders, created if not present

    Default: False

    -

    Note: use only on single-instance setup, will break consistency with -client in multi-instance setup

    +

    Note: only use on single-instance setup: it will break consistency +with clients in multi-instance setup

    use_cache_subfolder_for_synctoken
    @@ -1476,35 +1539,40 @@ client in multi-instance setup

    of 'sync-token' instead of inside collection folders, created if not present

    Default: False

    -

    Note: use only on single-instance setup, will break consistency with -client in multi-instance setup

    +

    Note: only use on single-instance setup: it will break consistency +with clients in multi-instance setup

    use_mtime_and_size_for_item_cache

    (>= 3.3.2)

    -

    Use last modifiction time (nanoseconds) and size (bytes) for 'item' -cache instead of SHA256 (improves speed)

    +

    Use last modification time (in nanoseconds) and size (in bytes) for +'item' cache instead of SHA256 (improves speed)

    Default: False

    -

    Note: check used filesystem mtime precision before enabling

    -

    Note: conversion is done on access, bulk conversion can be done -offline using storage verification option -radicale --verify-storage

    +

    Notes:

    +
    folder_umask

    (>= 3.3.2)

    -

    Use configured umask for folder creation (not applicable for OS -Windows)

    -

    Default: (system-default, usual 0022)

    -

    Useful value: 0077 (user:rw group:- other:-) or -0027 (user:rw group:r other:-) or 0007 -(user:rw group:rw other:-) or 0022 (user:rw group:r -other:r)

    +

    umask to use for folder creation (not applicable for OS Windows)

    +

    Default: (system-default, usually 0022)

    +

    Useful values:

    +
    max_sync_token_age
    -

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

    +

    Delete sync-tokens that are older than the specified time (in +seconds).

    Default: 2592000

    @@ -1515,9 +1583,9 @@ other:r)

    hook
    -

    Command that is run after changes to storage. Take a look at the Versioning with Git tutorial for an -example.

    -

    Default:

    +

    Command that is run after changes to storage. Take a look at the Versioning collections with +Git tutorial for an example.

    +

    Default: (unset)

    Supported placeholders:

    -

    Command will be executed with base directory defined in +

    The command will be executed with base directory defined in filesystem_folder (see above)

    predefined_collections
    -

    Create predefined user collections

    +

    Create predefined user collections.

    Example:

    -
     {
    -   "def-addressbook": {
    -      "D:displayname": "Personal Address Book",
    -      "tag": "VADDRESSBOOK"
    -   },
    -   "def-calendar": {
    -      "C:supported-calendar-component-set": "VEVENT,VJOURNAL,VTODO",
    -      "D:displayname": "Personal Calendar",
    -      "tag": "VCALENDAR"
    -   }
    - }
    -

    Default:

    +
    {
    +  "def-addressbook": {
    +     "D:displayname": "Personal Address Book",
    +     "tag": "VADDRESSBOOK"
    +  },
    +  "def-calendar": {
    +     "C:supported-calendar-component-set": "VEVENT,VJOURNAL,VTODO",
    +     "D:displayname": "Personal Calendar",
    +     "tag": "VCALENDAR"
    +  }
    +}
    +

    Default: (unset)

    -

    web

    +

    [web]

    type

    The backend that provides the web interface of Radicale.

    -

    Available backends:

    -

    none : Just shows the message "Radicale works!".

    -

    internal : Allows creation and management of address -books and calendars.

    +

    Available backends are:

    +
      +
    • none
      +Simply shows the message "Radicale works!".

    • +
    • internal
      +Allows creation and management of address books and calendars.

    • +

    Default: internal

    -

    logging

    +

    [logging]

    level

    Set the logging level.

    -

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

    -

    Default: warning (< 3.2.0) info -(>= 3.2.0)

    +

    Available levels are:

    +
      +
    • debug
    • +
    • info
    • +
    • warning
    • +
    • error
    • +
    • critical
    • +
    +

    Default: warning (< 3.2.0) / +info (>= 3.2.0)

    trace_on_debug
    @@ -1582,12 +1658,12 @@ books and calendars.

    trace_filter

    (> 3.5.4)

    Filter debug messages starting with 'TRACE/'

    -

    Precondition: trace_on_debug = True

    +

    Prerequisite: trace_on_debug = True

    Default: (empty)

    mask_passwords
    -

    Don't include passwords in logs.

    +

    Do not include passwords in logs.

    Default: True

    @@ -1599,129 +1675,143 @@ books and calendars.

    backtrace_on_debug

    (>= 3.2.2)

    -

    Log backtrace on level=debug

    +

    Log backtrace on level = debug

    Default: False

    request_header_on_debug

    (>= 3.2.2)

    -

    Log request on level=debug

    +

    Log request on level = debug

    Default: False

    request_content_on_debug

    (>= 3.2.2)

    -

    Log request on level=debug

    +

    Log request on level = debug

    Default: False

    response_content_on_debug

    (>= 3.2.2)

    -

    Log response on level=debug

    +

    Log response on level = debug

    Default: False

    rights_rule_doesnt_match_on_debug

    (>= 3.2.3)

    -

    Log rights rule which doesn't match on level=debug

    +

    Log rights rule which doesn't match on level = debug

    Default: False

    storage_cache_actions_on_debug

    (>= 3.3.2)

    -

    Log storage cache actions on level=debug

    +

    Log storage cache actions on level = debug

    Default: False

    -

    headers

    -

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

    +

    [headers]

    +

    This section can be used to specify additional HTTP headers that will +be sent to clients.

    An example to relax the same-origin policy:

    -
    Access-Control-Allow-Origin = *
    +
    Access-Control-Allow-Origin = *
    -

    hook

    +

    [hook]

    type

    Hook binding for event changes and deletion notifications.

    -

    Available types:

    -

    none : Disabled. Nothing will be notified.

    -

    rabbitmq (>= 3.2.0) : Push the message to -the rabbitmq server.

    -

    email (>= 3.5.5) : Send an email -notification to event attendees.

    +

    Available types are:

    +
      +
    • none
      +Disabled. Nothing will be notified.

    • +
    • rabbitmq (>= 3.2.0)
      +Push the message to the rabbitmq server.

    • +
    • email (>= 3.5.5)
      +Send an email notification to event attendees.

    • +

    Default: none

    dryrun

    (> 3.5.4)

    -

    Dry-Run (do not really trigger hook action)

    +

    Dry-Run / simulate (i.e. do not really trigger) the hook action.

    Default: False

    rabbitmq_endpoint

    (>= 3.2.0)

    -

    End-point address for rabbitmq server. Ex: -amqp://user:password@localhost:5672/

    -

    Default:

    +

    End-point address for rabbitmq server. E.g.: +amqp://user:password@localhost:5672/

    +

    Default: (unset)

    rabbitmq_topic

    (>= 3.2.0)

    -

    RabbitMQ topic to publish message.

    -

    Default:

    +

    RabbitMQ topic to publish message in.

    +

    Default: (unset)

    rabbitmq_queue_type

    (>= 3.2.0)

    RabbitMQ queue type for the topic.

    -

    Default: classic

    +

    Default: classic

    smtp_server

    (>= 3.5.5)

    -

    Address to connect to SMTP server.

    -

    Default:

    +

    Address of SMTP server to connect to.

    +

    Default: (unset)

    smtp_port

    (>= 3.5.5)

    -

    Port to connect to SMTP server.

    +

    Port on SMTP server to connect to.

    Default:

    smtp_security

    (>= 3.5.5)

    -

    Use encryption on the SMTP connection. none, tls, starttls

    -

    Default: none

    +

    Use encryption on the SMTP connection.

    +

    One of:

    +
      +
    • none
    • +
    • tls
    • +
    • starttls
    • +
    +

    Default: none

    smtp_ssl_verify_mode

    (>= 3.5.5)

    -

    The certificate verification mode. Works for tls and starttls. NONE, -OPTIONAL or REQUIRED

    -

    Default: REQUIRED

    +

    The certificate verification mode for tls and starttls.

    +

    One of:

    +
      +
    • NONE
    • +
    • OPTIONAL
    • +
    • REQUIRED
    • +
    +

    Default: REQUIRED

    smtp_username

    (>= 3.5.5)

    Username to authenticate with SMTP server. Leave empty to disable authentication (e.g. using local mail server).

    -

    Default:

    +

    Default: (unset)

    smtp_password

    (>= 3.5.5)

    Password to authenticate with SMTP server. Leave empty to disable authentication (e.g. using local mail server).

    -

    Default:

    +

    Default: (unset)

    from_email

    (>= 3.5.5)

    Email address to use as sender in email notifications.

    -

    Default:

    +

    Default: (unset)

    mass_email
    @@ -1733,9 +1823,9 @@ disabled, send one email per attendee email address.

    new_or_added_to_event_template

    (>= 3.5.5)

    -

    Template to use for added/updated event email body (sent to an +

    Template to use for added/updated event email body sent to an attendee when the event is created or they are added to a pre-existing -event).

    +event.

    The following placeholders will be replaced:

    • $organizer_name: Name of the organizer, or "Unknown @@ -1768,9 +1858,9 @@ This is an automated message. Please do not reply.
      deleted_or_removed_from_event_template

      (>= 3.5.5)

      -

      Template to use for deleted/removed event email body (sent to an +

      Template to use for deleted/removed event email body sent to an attendee when the event is deleted or they are removed from the -event).

      +event.

      The following placeholders will be replaced:

      • $organizer_name: Name of the organizer, or "Unknown @@ -1800,12 +1890,11 @@ The following event has been deleted. This is an automated message. Please do not reply.
      -
    -
    -

    updated_event_template

    +
    +
    updated_event_template

    (>= 3.5.5)

    -

    Template to use for updated event email body (sent to an attendee -when non-attendee-related details of the event are updated).

    +

    Template to use for updated event email body sent to an attendee when +non-attendee-related details of the event are updated.

    Existing attendees will NOT be notified of a modified event if the only changes are adding/removing other attendees.

    The following placeholders will be replaced:

    @@ -1837,8 +1926,9 @@ The following event has been updated. This is an automated message. Please do not reply.
    +
    -

    reporting

    +

    [reporting]

    max_freebusy_occurrence

    (>= 3.2.3)

    @@ -1861,6 +1951,7 @@ instead of returning the results.

  • OneCalendar
  • GNOME Calendar, Contacts and Evolution
  • +
  • KDE PIM Applications, KDE Merkuro
  • Mozilla Thunderbird (Thunderbird/Radicale) with CardBook @@ -1876,10 +1967,10 @@ Calendar
  • 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 username. In others, -you have to enter the URL of the collection directly (e.g. -http://localhost:5232/user/calendar).

    +

    In some clients, it is sufficient to simply enter the URL of the +Radicale server (e.g. http://localhost:5232) and your +username. In others, you have to enter the URL of the collection +directly (e.g. http://localhost:5232/user/calendar).

    Some clients (notably macOS's Calendar.app) may silently refuse to include account credentials over unsecured HTTP, leading to unexpected authentication failures. In these cases, you want to make sure the @@ -1888,7 +1979,8 @@ Radicale server is accessible over HTTPS.

    DAVx⁵

    Enter the URL of the Radicale server (e.g. http://localhost:5232) and your username. DAVx⁵ will show -all existing calendars and address books and you can create new.

    +all existing calendars and address books and you can create new +ones.

    OneCalendar

    @@ -1919,6 +2011,15 @@ search button will list the existing calendars and address books.

    Adding CalDAV and CardDAV accounts in Evolution will automatically make them available in GNOME Contacts and GNOME Calendar.

    +
    +

    KDE PIM Applications

    +

    In Kontact add a DAV Groupware resource to +Akonadi under Settings > Configure Kontact > Calendar > +General > Calendars, select the protocol (CalDAV or CardDAV), +add the URL to the Radicale collections and enter the credentials. After +synchronization of the calendar resp. addressbook items, you can manage +them in Kontact.

    +

    Thunderbird

    Add a new calendar on the network. Enter your username and the URL of @@ -1948,80 +2049,81 @@ InfCloud.

    calendars and address books. Use Radicale's web interface or a client with support for it (e.g. DAVx⁵).

    To create a new calendar run something like:

    -
    $ 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>'
    +
    $ 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: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>'
    +
    $ 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>'

    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'

    Note: requires config/option permit_delete_collection = True

    -
    -

    Authentication and Rights

    +
    +

    Authorization and Rights

    This section 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 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.

    +is granted to calendars and address books outside the home directory of +users (that's /USERNAME/), clients will not detect these +collections automatically, and will not show them to the users. This is +only useful if you access calendars and address books directly via +URL.

    An example rights file:

    -
    # Allow reading root collection for authenticated users
    -[root]
    -user: .+
    -collection:
    -permissions: R
    -
    -# Allow reading and writing principal collection (same as username)
    -[principal]
    -user: .+
    -collection: {user}
    -permissions: RW
    -
    -# Allow reading and writing calendars and address books that are direct
    -# children of the principal collection
    -[calendars]
    -user: .+
    -collection: {user}/[^/]+
    -permissions: rw
    +
    # Allow reading root collection for authenticated users
    +[root]
    +user: .+
    +collection:
    +permissions: R
    +
    +# Allow reading and writing principal collection (same as username)
    +[principal]
    +user: .+
    +collection: {user}
    +permissions: RW
    +
    +# Allow reading and writing calendars and address books that are direct
    +# children of the principal collection
    +[calendars]
    +user: .+
    +collection: {user}/[^/]+
    +permissions: rw

    The titles of the sections are ignored (but must be unique). The keys user and collection contain regular expressions, that are matched against the username and the path of the @@ -2051,51 +2153,53 @@ expensive search requests) calendars)

  • w: write address book and calendar collections
  • D: permit delete of collection in case -permit_delete_collection=False (>= 3.3.0)
  • +permit_delete_collection=False (>= 3.3.0)
  • d: forbid delete of collection in case -permit_delete_collection=True (>= 3.3.0)
  • +permit_delete_collection=True (>= 3.3.0)
  • O: permit overwrite of collection in case -permit_overwrite_collection=False
  • +permit_overwrite_collection=False
  • o: forbid overwrite of collection in case -permit_overwrite_collection=True
  • +permit_overwrite_collection=True

    Storage

    This document describes the layout and format of the file system -storage (multifilesystem backend).

    -

    It's safe to access and manipulate the data by hand or with scripts. -Scripts can be invoked manually, periodically (e.g. with cron) +storage, the multifilesystem backend.

    +

    It is safe to access and manipulate the data by hand or with scripts. +Scripts can be invoked manually, periodically (e.g. using cron) or after each change to the storage with the configuration option -hook in the storage section (e.g. Versioning with Git).

    +hook in the storage section (e.g. Versioning collections with +Git).

    Layout

    -

    The file system contains the following files and folders:

    +

    The file system comprises the following files and folders:

    • .Radicale.lock: The lock file for locking the storage.
    • collection-root: This folder contains all collections and items.
    -

    A collection is represented by a folder. This folder may contain the -file .Radicale.props with all WebDAV properties of the +

    Each collection is represented by a folder. This folder may contain +the file .Radicale.props with all WebDAV properties of the collection encoded as JSON.

    -

    An item is represented by a file containing the iCalendar data.

    -

    All files and folders, whose names start with a dot but not +

    Each item in a calendar or address book collection is represented by +a file containing the item's iCalendar resp. vCard data.

    +

    All files and folders, whose names start with a dot but not with .Radicale. (internal files) are ignored.

    -

    If you introduce syntax errors in any of the files, all requests that -access the faulty data will fail. The logging output should contain the -names of the culprits.

    +

    Syntax errors in any of the files will cause all requests accessing +the faulty data to fail. The logging output should contain the names of +the culprits.

    Caches and sync-tokens are stored in the .Radicale.cache folder inside of collections. This folder may be created or modified, while the storage is locked for shared access. In theory, it should be safe to delete the folder. Caches will be recreated automatically and -clients will be told that their sync-token isn't valid anymore.

    +clients will be told that their sync-token is not valid anymore.

    You may encounter files or folders that start with .Radicale.tmp-. Radicale uses them for atomic creation and deletion of files and folders. They should be deleted after requests are -finished but it's possible that they are left behind when Radicale or -the computer crashes. It's safe to delete them.

    +finished but it is possible that they are left behind when Radicale or +the computer crashes. You can safely delete them.

    Locking

    @@ -2107,11 +2211,12 @@ system. The storage is locked with exclusive access while the
    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
    +utility to acquire exclusive or shared locks for the commands you want +to run on Radicale's data.

    +
    # Exclusive lock for COMMAND
    +$ flock --exclusive /path/to/storage/.Radicale.lock COMMAND
    +# Shared lock for COMMAND
    +$ flock --shared /path/to/storage/.Radicale.lock COMMAND
    Linux and MacOS
    @@ -2130,17 +2235,17 @@ which also supports shared access. Setting

    Manually creating collections

    -

    To create a new collection, you have to create the corresponding +

    To create a new collection, you need to create the corresponding folder in the file system storage (e.g. -collection-root/user/calendar). To tell Radicale and +collection-root/user/calendar). To indicate to 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"}
    -

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

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

    The calendar is now available at the URL path (e.g. +/user/calendar). For address books +.Radicale.props must contain:

    +
    {"tag": "VADDRESSBOOK"}

    Calendar and address book collections must not have any child collections. Clients with automatic discovery of collections will only show calendars and address books that are direct children of the path @@ -2202,13 +2307,13 @@ calendar or an address book through network:

    Radicale is only the server part of this architecture.

    -

    Please note that:

    +

    Please note:

      -
    • CalDAV and CardDAV are superset protocols of WebDAV,
    • -
    • WebDAV is a superset protocol of HTTP.
    • +
    • CalDAV and CardDAV are extension protocols of WebDAV,
    • +
    • WebDAV is an extension of the HTTP protocol.
    -

    Radicale being a CalDAV/CardDAV server, it also can be seen as a -special WebDAV and HTTP server.

    +

    Radicale being a CalDAV/CardDAV server, can also be seen as a special +WebDAV and HTTP server.

    Radicale is not the client part of this architecture. It means that Radicale never draws calendars, address books, events and contacts on the screen. It only stores them and give @@ -2221,48 +2326,52 @@ application.

    Code Architecture

    The radicale package offers the following modules.

    -

    __init__ : Contains the entry point for WSGI.

    -

    __main__ : Provides the entry point for the +

      +
    • __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 +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 representation 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 +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 representation 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.

      +ElementTree XML API.

    • +

    Plugins

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

    -
    -

    Getting started

    +
    +

    Getting started with plugin development

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

    @@ -2270,49 +2379,49 @@ password.

    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_static_password_auth",
    -      packages=["radicale_static_password_auth"])
    +
    #!/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, login, password):
    -        # Get password from configuration option
    -        static_password = self.configuration.get("auth", "password")
    -        # Check authentication
    -        logger.info("Login attempt by %r with password %r",
    -                    login, password)
    -        if password == static_password:
    -            return login
    -        return ""
    +
    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, login, password):
    +        # Get password from configuration option
    +        static_password = self.configuration.get("auth", "password")
    +        # Check authentication
    +        logger.info("Login attempt by %r with password %r",
    +                    login, password)
    +        if password == static_password:
    +            return login
    +        return ""

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

    -
    python3 -m pip install .
    +
    python3 -m pip install .

    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
    +
    [auth]
    +type = radicale_static_password_auth
    +password = secret

    You can uninstall the module with:

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

    Authentication plugins

    @@ -2371,14 +2480,14 @@ you want to add new features, fix bugs or update the documentation.

    PyPI

    Radicale is available on PyPI. To install, just type as superuser:

    -
    python3 -m pip install --upgrade radicale
    +
    python3 -m pip install --upgrade radicale

    Git Repository

    If you want the development version of Radicale, take a look at the git repository on GitHub, or install it directly with:

    -
    python3 -m pip install --upgrade https://github.com/Kozea/Radicale/archive/master.tar.gz
    +
    python3 -m pip install --upgrade https://github.com/Kozea/Radicale/archive/master.tar.gz

    You can also download the content of the repository as an archive.

    @@ -2390,7 +2499,7 @@ GitHub, or install it directly with:

    Radicale is available as a Docker image for platforms linux/amd64 and linux/arm64. To install the latest version, run:

    -
    docker pull ghcr.io/kozea/radicale:latest
    +
    docker pull ghcr.io/kozea/radicale:latest

    An example docker-compose.yml and detailed instructions will soon be updated.