User Tools

Radicale

Radicale is a CalDAV/CardDAV server. It can be used to store your contacts and calendars, and i will show you how to install also InfCloud as a WEB GUI to it.

CalDAV is the WebDAV extension to manage Calendars

CardDAV is the WebDAV extension to manage address books and contacts in general.

To add support for both, which will allow your phone to sync contacts and calendars with your home server, i choose to use the great, simple and effective Radicale server.

Please note that Radicale do not provide a user-interface to edit or use calendars or contacts, you need third party apps for that, and the one i am currently using is InfCloud, see installation instructions at the bottom of this page.

To install radicale, of course, you need it's dedicated user, so add user:

useradd -d /data/daemons/radicale -m radicale

Create data folder:

mkdir /data/cardcal
chown radicale:radicale /data/cardcal

Radicale uses pip, so as usual enable it on Gentoo for user Radicale by creating the file /data/daemons/radicale/.config/pip/pip.conf with this content:

pip.conf
[global]
break-system-packages = true
user = true

Install as user radicale:

su - radicale
pip install --upgrade radicale

Create the config file ~/.config/radicale/config:

config
[server]
# Bind all addresses
hosts = 127.0.0.1:5232

[auth]
type = http_x_remote_user
#htpasswd_filename = ~/.config/radicale/users
#htpasswd_encryption = md5

[storage]
filesystem_folder = /data/cardcal

then start it:

su - radicale
radicale

Reverse Proxy

Radicale can be hosted both on subdomain or subpath, but i choose subdomain to make it easier to also host InfCloud on the same subdomain.

As usual you want it protected by the Reverse Proxy, so create the radicale.conf file:

radicale.conf
server {
        server_name radicale.mydomain.com;
        listen 443 ssl;
        listen 8443 ssl;
        http2 on;

        include "com.mydomain/authelia_location-basic.conf";

        access_log /var/log/nginx/radicale.mydomain.com_access_log main;
        error_log /var/log/nginx/radicale.mydomain.com_error_log info;

        location / { # The trailing / is important!
                proxy_pass        http://127.0.0.1:5232/; # The / is important!
                proxy_set_header  X-Script-Name /;
                proxy_set_header  X-Remote-User $remote_user;
                proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header  Host $http_host;
                proxy_pass_header Authorization;
                include "com.mydomain/authelia_proxy.conf";
                include "com.mydomain/authelia_authrequest-basic.conf";
        }

        location /gui/ { # The trailing / is important!
                proxy_pass        http://127.0.0.1:5233/; # The / is important!
                proxy_set_header  X-Script-Name /;
                proxy_set_header  X-Remote-User $remote_user;
                proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header  Host $http_host;
                proxy_pass_header Authorization;
        }
        include com.mydomain/certbot.conf;
}

add this config file to NGINX (see The Reverse Proxy concept for more details) and restart nginx.

This set-up links also Radicale to your SSO (see this page, which is a good approach, but please note that this will make access to the radicale web ui (not the WEB GUI InfCloud) a bit more awkward as the Radicale login window cannot be disabled, and the user will need double authentication.

Now go with browser to https://radicale.mydomain.com to finish setup.

URLs summary

The following URL's are exposed between Radicale and InfCloud:

And, last, when setting up your *DAV clients (like on Android or similar), use https://radicale.mydomain.com as server URL.

Startup

Since i use OpenRC, to start radicale simply create the following script under /etc/init.d:

/etc/init.d/radicale
#!/sbin/openrc-run
# Copyright 1999-2021 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

description="Radicale WebDAV / WebCAL server"
pidfile="/run/radicale.pid"
command_background=true
command="/data/daemons/radicale/.local/bin/radicale"
command_args=""
command_user="radicale:users"

depend() {
        need net
}

Make it executable and add the service to the default runlevel:

chmod +x /etc/init.d/radicale
rc-update add radicale default

Sharing calendars

Radicale doesn't directly support sharing calendars (see here) but it's pretty easy to share calendars between users anyway by creating simple symlinks.

So, first of all login on Radicale web GUI with all the users you want to share the calendar with, then create in one of them the actual calendar.

At this point, you only need to link the calendar folder inside all he users:

ln -s /data/cardcal/collection-root/user1/72757af3-557c-e8e4-bdd7-c9bc5689b862   /data/cardcal/collection-root/user2/

and that's it.

WEB GUI for Radicale

InfCloud is a nice javascript WEB GUI for Radicale. It's a bit old-style, but solid and pretty usable. I strongly suggest to go the container way and use this InfCloud docker solution here, which is pretty nice and easy to setup.

First of all, to avoid cross-domain issues (CORS) which are hard to solve due to using SSO on Radicale itself, i will host InfCloud on the same radicale domain, using the /gui/ subpath.

First of all, setup the docker-compose file /data/daemons/radicale/docker-compose.yml:

docker-compose.yml
version: "3"

services:
  infcloud:
    image: ckulka/infcloud
    restart: always
    depends_on:
      - php
    ports:
      - "5233:80"
    volumes:
      - infcloud:/usr/share/nginx/infcloud
      - ./config.js:/usr/share/nginx/infcloud/config.js:ro

  php:
    image: php:7.3-fpm-alpine
    restart: always
    volumes:
      - infcloud:/usr/share/nginx/infcloud:ro

volumes:
  infcloud:

Now, create the /data/daemons/radicale/config.js:

config.js
var globalNetworkCheckSettings={
        href: "https://radicale.mydomain.com/",
        timeOut: 90000,
        lockTimeOut: 10000,
        checkContentType: true,
        settingsAccount: true,
        delegation: true,
        additionalResources: [],
        hrefLabel: null,
        forceReadOnly: null,
        ignoreAlarms: false,
        backgroundCalendars: []
};
var globalInterfaceLanguage='it_IT';
var globalSearchTransformAlphabet={
        '[ÀàÁáÂâÄ䯿ÃãÅåĀā]': 'a', '[ÇçĆćČč]': 'c', '[Ďď]': 'd',
        '[ÈèÉéÊêËëĒēĖėĘęĚě]': 'e', '[Ğğ]': 'g', '[ÌìÍíÎîİıÏïĪīĮį]': 'i',
        '[ŁłĹ弾]': 'l', '[ŃńÑñŇň]': 'n', '[ÒòÓóÔôÖöŐőŒœØøÕõŌō]': 'o',
        '[ŔŕŘř]': 'r', '[ŚśŠšȘșŞşẞß]': 's', '[ŤťȚțŢţ]': 't',
        '[ÙùÚúÛûÜüŰűŮůŪū]': 'u', '[ÝýŸÿ]': 'y', '[ŹźŻżŽž]': 'z'
};
var globalSortAlphabet=' 0123456789'+
        'AÀÁÂÄÆÃÅĀBCÇĆČDĎEÈÉÊËĒĖĘĚFGĞHIÌÍÎİÏĪĮJKLŁĹĽMNŃÑŇOÒÓÔÖŐŒØÕŌ'+
        'PQRŔŘSŚŠȘșŞşẞTŤȚțŢţUÙÚÛÜŰŮŪVWXYÝŸZŹŻŽ'+
        'aàáâäæãåābcçćčdďeèéêëēėęěfgğhiìíîïīįıjklłĺľmnńñňoòóôöőœøõō'+
        'pqrŕřsśšßtťuùúûüűůūvwxyýÿzźżžАБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЮЯ'+
        'Ьабвгґдеєжзиіїйклмнопрстуфхцчшщюяь';
var globalBackgroundSync=true;
var globalSyncResourcesInterval=120000;
var globalEnableRefresh=false;
var globalEnableKbNavigation=true;
var globalInterfaceCustomLanguages=[];
var globalResourceAlphabetSorting=true;
var globalNewVersionNotifyUsers=[];
var globalDatepickerFirstDayOfWeek=1;
var globalHideInfoMessageAfter=1800;
var globalEditorFadeAnimation=666;
var globalEventStartPastLimit=3;
var globalEventStartFutureLimit=3;
var globalTodoPastLimit=1;
var globalLoadedCalendarCollections=[];
var globalLoadedTodoCollections=[];
var globalActiveCalendarCollections=[];
var globalActiveTodoCollections=[];
var globalActiveView='multiWeek';
var globalOpenFormMode='double';
var globalTodoListFilterSelected=['filterAction', 'filterProgress'];
var globalCalendarStartOfBusiness=8;
var globalCalendarEndOfBusiness=17;
var globalDefaultEventDuration=120;
var globalDisplayHiddenEvents=false;
var globalTimeZoneSupport=true;
var globalTimeZone='Europe/Berlin';
var globalTimeZonesEnabled=[];
var globalRewriteTimezoneComponent=true;
var globalRemoveUnknownTimezone=false;
var globalShowHiddenAlarms=false;
var globalIgnoreCompletedOrCancelledAlarms=true;
var globalMozillaSupport=false;
var globalWeekendDays=[0, 6];
var globalAppleRemindersMode=true;
var globalLoadedAddressbookCollections=[];
var globalActiveAddressbookCollections=[];
var globalCompatibility={anniversaryOutputFormat: ['apple']};
var globalUriHandlerTel='tel:';
var globalUriHandlerEmail='mailto:';
var globalUriHandlerUrl='http://';
var globalUriHandlerProfile={
        'twitter': 'http://twitter.com/%u',
        'facebook': 'http://www.facebook.com/%u',
        'flickr': 'http://www.flickr.com/photos/%u',
        'linkedin': 'http://www.linkedin.com/in/%u',
        'myspace': 'http://www.myspace.com/%u',
        'sinaweibo': 'http://weibo.com/n/%u'
};
var globalDefaultAddressCountry='us';
var globalAddressCountryEquivalence=[
        {country: 'de', regex: '^\\W*Deutschland\\W*$'},
        {country: 'sk', regex: '^\\W*Slovensko\\W*$'}
];
var globalAddressCountryFavorites=[];
var globalContactStoreFN=['prefix',' last',' middle',' first',' suffix'];
var globalGroupContactsByCompanies=false;
var globalContactDataMinVisiblePercentage=0.95;

Edit to your likings, more detail can be found here.

Now create the startup config script /etc/conf.d/user-containers.infCloud:

user-containers.infCloud
USER=radicale
DESCRIPTION="WEB GUI for Radicale"

Create the link and start it:

cd /etc/init.d/
ln -s user-containers user-containers.infCloud
rc-update add user-containers.infCloud default
./user-containers.infCloud start

Now point your browser to https://radicale.mydomain.com/gui/ to access infCloud.