rss logo

Setting Up Roundcube with CalDAV Support on Debian

Update Aug 11, 2024:

Following recent Debian 12 updates the plugin can no longer be installed. It fails with message: "Install of kolab/libkolab failed" In ExtensionInstaller.php line 88: [ErrorException] require_once(/var/lib/roundcube/vendor/roundcube/roundcubemail/program/include/iniset.php): Failed to open stream: No such file or directory

Rouncube Logo Rouncube Calendar

In a previous article, I looked at setting up a CalDAV server (see here). As part of my effort to replace the aging Zimbra solution, the next step is to set up a webmail and calendar solution.

Here we'll look at how to set up a Roundcube server with a SQLite3 database on Debian (easy!) as well as adding a calendar plugin (less easy :/).

For this configuration, I opted for the SQLite3 database, ideal for a small user base, and the use of Roundcube Debian packages for easy updating and maintenance. To add the calendar to Roundcube, I chose the JodliDev/calendar plugin, available free on GitHub. Because it still seems to be supported, and allows you to connect to a CalDAV server. Special thanks to JodliDev and community contributors, Offerel and mtudury, for their valuable contributions.

Prerequisites include a functioning SMTP and IMAP server for webmail, as well as a CalDAV calendar sharing server. In addition, it's important to note that, at the time of writing, the solution only supports a single calendar, as I haven't been able to add any other calendars in parallel. Hopefully, the plugin will be upgraded in the coming months.

  • Configuration:
    • debian: 12 bookworm
    • php: 8.2
    • roundcube: 1.6.5
    • sqlite3: 3.40

Roundcube

Installation

  • Installing packages:
root@host:~# apt update && apt install roundcube sqlite3 roundcube-plugins roundcube-sqlite3
  • Answer yes to configure the database:
Rouncube package installation process on a Debian asking to configure database
  • Edit /etc/apache2/conf-enabled/roundcube.conf and uncomment this line:
Alias /roundcube /var/lib/roundcube/public_html […]

Configuration

Here, the mail server has Let's Encrypt certificates, associated with imaps and smtps services. So I need to use the names and the keyword ssl:// to connect.

  • Edit the configuration file /etc/roundcube/config.inc.php, it says it's a good thing to change the des_key, so do it if you like :):
$config['imap_host'] = ["ssl://mx.std.rocks:993"]; $config['smtp_host'] = 'ssl://mx.std.rocks:465'; // This key is used to encrypt the users imap password which is stored // in the session record. For the default cipher method it must be // exactly 24 characters long. // YOUR KEY MUST BE DIFFERENT THAN THE SAMPLE VALUE FOR SECURITY REASONS $config['des_key'] = 'PaaKtcPFfopJxHHyTe9rahk3';
  • Restart the apache2 service:
root@host:~# systemctl restart apache2
  • The Roundcube web page should be accessible via HTTP (ex: http://IP_ROUNDCUBE/roundcube):
Rouncube authentication web interface

Enable HTTPS

For security reasons, its a good thing to enable HTTPS connections to access Roundcube. Let's see how to do that.

  • Enable apache ssl module:
root@host:~# a2enmod ssl

Let's Encrypt

  • If you have Let's Encrypt certificates, edit /etc/apache2/sites-available/default-ssl.conf:
SSLCertificateFile /etc/letsencrypt/roundcube.std.rocks/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/roundcube.std.rocks/privkey.pem SSLCertificateChainFile /etc/letsencrypt/roundcube.std.rocks/chain.pem

Self-Signed Certificates

  • Alternatively, you can create a self-signed certificate:
root@host:~# mkdir /etc/apache2/ssl/ root@host:~# openssl req -x509 -nodes -days 3650 -newkey rsa:4096 -keyout /etc/apache2/ssl/selfsigned.key -out /etc/apache2/ssl/selsigned.crt root@host:~# cat /etc/apache2/ssl/selfsigned.key /etc/apache2/ssl/selsigned.crt > /etc/apache2/ssl/cert.pem

Finalize Configuration

  • Edit the /etc/apache2/sites-available/default-ssl.conf configuration file:
DocumentRoot /var/lib/roundcube/public_html/ #AUTOGENERATE CERTIFICATES SSLCertificateFile /etc/apache2/ssl/cert.pem SSLCertificateKeyFile /etc/apache2/ssl/selfsigned.key
  • Edit the /etc/apache2/ports.conf configuration file and disable http:
#Listen 80
  • Enable and restart the apache2 service:
root@host:~# a2ensite default-ssl root@host:~# systemctl restart apache2

Prequisites

Note: to avoid the GitHubrate limit we need to open a free account in order to obtain an OAuth token. Once the account has been created, go to https://github.com/settings/tokens page to generate a new token.

  • Considerations to make about the CalDAV server:
    • If using HTTPS, ensure the CalDAV server employs a valid certificate; otherwise, use HTTP or add the root certificate to your Roundcube server.
    • Use basic authentication

Basic Authentication

  • Configure the remote calendar with Basic Auth; for example, if you have a Baïkal shared calendar server:
The Baïkal WebDAV authentication type menu.

CalDAV server with self-signed certificate

If you're using a self-signed certificate on your CalDAV server, you can either enable HTTP or add the root certificate to your Roundcube server so that it's recognized as trusted. Let's take a look at how to do this with Baïkal.

Enable HTTP

  • From the Baïkal server, edit /etc/apache2/sites-available/000-default.conf:
<VirtualHost *:443> DocumentRoot /var/www/baikal/html ServerName baikal.std.rocks RewriteEngine On # Generally already set by global Apache configuration #RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteRule /.well-known/carddav /dav.php [R=308,L] RewriteRule /.well-known/caldav /dav.php [R=308,L] <Directory "/var/www/baikal/html"> Options None # If you install cloning git repository, you may need the following Options +FollowSymlinks AllowOverride None # Configuration for apache-2.4: Require all granted # Configuration for apache-2.2: # Order allow,deny # Allow from all </Directory> <IfModule mod_expires.c> ExpiresActive Off </IfModule> SSLEngine On #AUTOGENERATE CERTIFICATES SSLCertificateFile /etc/apache2/ssl/cert.pem SSLCertificateKeyFile /etc/apache2/ssl/selfsigned.key </VirtualHost> <VirtualHost *:80> DocumentRoot /var/www/baikal/html ServerName dav.example.org RewriteEngine On # Generally already set by global Apache configuration #RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteRule /.well-known/carddav /dav.php [R=308,L] RewriteRule /.well-known/caldav /dav.php [R=308,L] <Directory "/var/www/baikal/html"> Options None # If you install cloning git repository, you may need the following Options +FollowSymlinks AllowOverride None # Configuration for apache-2.4: Require all granted # Configuration for apache-2.2: # Order allow,deny # Allow from all </Directory> <IfModule mod_expires.c> ExpiresActive Off </IfModule> #SSLEngine on #AUTOGENERATE CERTIFICATES #SSLCertificateFile /etc/apache2/ssl/cert.pem #SSLCertificateKeyFile /etc/apache2/ssl/selfsigned.key #LETS ENCRYPT CERTIFICATES #SSLCertificateFile /etc/letsencrypt/baikal.std.rocks/fullchain.pem #SSLCertificateKeyFile /etc/letsencrypt/baikal.std.rocks/privkey.pem #SSLCertificateChainFile /etc/letsencrypt/baikal.std.rocks/chain.pem </VirtualHost>

Install Self-Signed Root Certificate on the Roundcube Server

  • Copy the /etc/apache2/ssl/selsigned.crt of your CalDAV server to /usr/local/share/ca-certificates/ and then run update-ca-certificates:
root@host:~# cp selsigned.crt /usr/local/share/ca-certificates/ root@host:~# update-ca-certificates Updating certificates in /etc/ssl/certs... rehash: warning: skipping ca-certificates.crt,it does not contain exactly one certificate or CRL 1 added, 0 removed; done. Running hooks in /etc/ca-certificates/update.d... done.

Calendar Plugin

Install the Plugin

It's now time to install the calendar plugin on our Roundcube server!

  • Install the necessary packages:
root@host:~# apt update && apt install php-sabre-* php-curl composer wget
  • Change the directory to /var/lib/roundcube/:
root@host:~# cd /var/lib/roundcube/
  • Create a composer.json file:
{ "name": "roundcube/calendar", "type": "roundcube-plugin", "description": "Calendar plugin", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", "version": "3.5.11", "authors": [ { "name": "Thomas Bruederli", "email": "bruederli@kolabsys.com", "role": "Lead" }, { "name": "Aleksander Machniak", "email": "machniak@kolabsys.com", "role": "Developer" } ], "repositories": { "libcalendaring": { "type": "vcs", "url": "https://github.com/JodliDev/libcalendaring" }, "calendar": { "type": "vcs", "url": "https://github.com/JodliDev/calendar" }, "0": { "type": "composer", "url": "https://plugins.roundcube.net" }, "1": { "type": "vcs", "url": "https://github.com/JodliDev/libcalendaring" } }, "require": { "php": ">=5.5", "roundcube/plugin-installer": ">=0.1.3", "jodlidev/libcalendaring": "dev-master", "kolab/libkolab": ">=3.4.0", "sabre/dav": ">=4.1.5" }, "extra": { "roundcube": { "min-version": "1.4.0", "sql-dir": "drivers/database/SQL" } }, "minimum-stability": "dev" }
  • Lauch the composer tool to install the calendar plugin and use the GitHub token of your previously created account:
root@host:~# composer -vv require kolab/calendar Do not run Composer as root/super user! See https://getcomposer.org/root for details Continue as root/super user [yes]? yes […] Reading composer.json of kolab/calendar (3.2.16) GitHub API limit (60 calls/hr) is exhausted, could not fetch https://api.github.com/repos/JodliDev/calendar/contents/composer.json?ref=a0aacd4a737e48189cfb5a82463e8b9fe16d56ea. Create a GitHub OAuth token to go over the API rate limit. You can also wait until 2024-02-09 16:43:21 for the rate limit to reset. When working with _public_ GitHub repositories only, head to https://github.com/settings/tokens/new?scopes=&description=Composer+on+roundcube+2024-02-09+1543 to retrieve a token. This token will have read-only permission for public information only. When you need to access _private_ GitHub repositories as well, go to https://github.com/settings/tokens/new?scopes=repo&description=Composer+on+roundcube+2024-02-09+1543 Note that such tokens have broad read/write permissions on your behalf, even if not needed by Composer. Tokens will be stored in plain text in "/root/.config/composer/auth.json" for future use by Composer. For additional information, check https://getcomposer.org/doc/articles/authentication-for-private-packages.md#github-oauth Token (hidden): GIT_TOKEN […] roundcube/plugin-installer contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins Do you trust "roundcube/plugin-installer" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?] Y […] 12/15 [======================>-----] 80% 1 sec/1 sec Do you want to activate the plugin libkolab? [Y|n] Y Updated local config at /etc/roundcube/config.inc.php Creating package config file Do you want to activate the plugin libcalendaring? [Y|n] Y Updated local config at /etc/roundcube/config.inc.php 14/15 [==========================>-] 93% 1 min/1 min Do you want to activate the plugin calendar? [Y|n] Y

Install Fixes for PHP8 and SQLite

Now, let's add the fixes for Debian 12 since it uses PHP 8, and the plugins seem to have been developed for PHP 7. The patches are available on the official GitHub plugin page: https://github.com/JodliDev/calendar/pulls.

PHP Fixes

  • Download the patched files and copy them into their respective folders:
root@host:~# wget https://raw.githubusercontent.com/JodliDev/calendar/e50160c2e1be4dca42788e7de9436fca1216f9f3/drivers/caldav/caldav_client.php root@host:~# mv ./caldav_client.php /var/lib/roundcube/plugins/calendar/drivers/caldav/caldav_client.php root@host:~# wget https://raw.githubusercontent.com/JodliDev/calendar/fa24c2f1ba0a72d83bd717fc5852a69366e39db2/calendar.php root@host:~# mv ./calendar.php /var/lib/roundcube/plugins/calendar/calendar.php root@host:~# wget https://raw.githubusercontent.com/JodliDev/calendar/2e526d5977da44e35722e332f0c3fc51034746ad/drivers/caldav/caldav_driver.php root@host:~# mv caldav_driver.php /var/lib/roundcube/plugins/calendar/drivers/caldav/caldav_driver.php

SQLite Fixes

We now need to apply fixes for the SQLite database (who said it was a good idea to use it?)!

calendar.php
  • Modify line 439 in /var/lib/roundcube/plugins/calendar/calendar.php:
//$select->add($choices); foreach ($choices as $choice) { $select->add($choice, $choice); }
sqlite.initial.sql
  • Download the sqlite.initial.sql and apply the patch:
root@host:~# wget https://raw.githubusercontent.com/JodliDev/calendar/c221f134063f21047cd9c2aefa120c6903dc84bd/drivers/caldav/SQL/sqlite.initial.sql root@host:~# sqlite3 /var/lib/dbconfig-common/sqlite3/roundcube/roundcube < sqlite.initial.sql
caldav_driver.php
  • Modify line 301 in /var/lib/roundcube/plugins/calendar/drivers/caldav/caldav_driver.php:
//if($this->rc->db->affected_rows($result)) continue; if($this->rc->db->num_rows($result) > 0) continue;
  • Modify line 2066 in /var/lib/roundcube/plugins/calendar/drivers/caldav/caldav_driver.php:
//$base_uri = $tokens['scheme']."://".$tokens['host'].(isset($tokens['port']) ? ":".$tokens['port'] : null); $base_uri = $tokens['scheme']."://".$tokens['host'].($tokens['port'] ? ":".$tokens['port'] : null);
  • Modify line 2266 in /var/lib/roundcube/plugins/calendar/drivers/caldav/caldav_driver.php:
// no local event -> create event // else else if(isset($update["remote_event"]))
  • Modify line 2305 in /var/lib/roundcube/plugins/calendar/drivers/caldav/caldav_driver.php:
private function _is_synced($cal_id) { //ADD THIS LINES : if ($this->rc->db->db_provider == 'sqlite') { // this is a minimal $query = $this->rc->db->query( "UPDATE ".$this->db_calendars." ". "SET caldav_last_change = CURRENT_TIMESTAMP WHERE calendar_id = ?", $cal_id); return false; }
calendar_ui.php
  • Comment line from 52 to 61 in /var/lib/roundcube/plugins/calendar/lib/calendar_ui.php:
//$this->cal->add_button([ // 'command' => 'calendar', // 'class' => 'button-calendar', // 'classsel' => 'button-calendar button-selected', // 'innerclass' => 'button-inner', // 'label' => 'calendar.calendar', // 'type' => 'link' // ], // 'taskbar' //);
Restart apache
  • Restart the apache2 service:
root@host:~# systemctl restart apache2

Connect Roundcube to the shared Calendar

  • Connect to Roundcube, the calendar icon should appear:
Rouncube web interface with the calendar plugin
  • From the calendar menu, select Add CalDAV sources:
Roundcube adding a CalDAV sources menu
  • Note: you can retrieve the full URI from your CalDAV server; here's an example using Baïkal:
URI of the shared calendar from Baikal server
  • Add your CalDAV server, here is an example with an HTTP server:
Roundcube adding a CalDAV sources window
  • Or, if you are using an HTTPS server, note that you need to specify the name to match with the certificate, otherwise, it won't connect:
Roundcube adding a CalDAV sources window
  • Once done, you can enjoy using your CalDAV calendar via Roundcube:
Roundcube accessing a CalDAV calendar window