RadicaleでCalDAV/CardDAVサーバーを構築する

以前のポストでNextcloudをインストールし、CalDAV/CardDAVサーバーとして利用していると書きました。ところが先日、Nextcloud 12がリリースされたので更新しようとしましたがうまく行きません。次のマイナーアップデートで改善されるかもしれませんが、なんとなく居心地がよくない気がします。

もともとNextcloudは、他のCalDAV/CardDAVサーバーが不安定であったため導入したもので、その多機能さゆえカレンダーや連絡帳の同期にのみ利用するのは少し大袈裟でした。また、Nextcloudのインストールには多くのPHPパッケージを必要とし、加えてデータベースも別途用意しなければならず煩雑な点があります。

そこでNextcloudがアップデートされなかったことを機に、先の試行ではきちんと動かすことができなかったRadicaleを再び試してみることにしました。すると、しばらく見ない間にバージョン2になっており、ドキュメントも以前より分かりやすく書かれています。実際にインストールしてみると正常に動作したのでその過程を記します。


前提として、Debian 8.8上でウェブサーバーにNginxを使用しています。チュートリアルによるとPython3.4以上とPythonパッケージ導入にpipが必要なのでインストールします。また、今回はVirtualenvを用い、環境を切り離してRadicaleを動かすことにしたので、それも同時にインストールしておきます。

$ sudo apt install python3 python3-pip python3-virtualenv

Radicaleのインストール

radicaleという名前の仮想環境を作り、Radicaleをインストールします。その際python3がデフォルトとなるよう指定しておきます。

$ virtualenv --python=python3 radicale
$ cd radicale
$ source bin/activate
(radicale)$ python --version
Python 3.4.2

Radicaleやパスワード生成に必要なPythonパッケージをインストールします cf. Basic Setupbcryptをインストールする際、依存関係となるライブラリなどがないとエラーが出るので、 bcryptドキュメントにならい、先にインストールしておきます。

$ sudo apt install build-essential libffi-dev python-dev
$ python -m pip install radicale passlib bcrypt

Radicaleの設定

ログインのためのパスワードを生成します cf. Basic SetuphtpasswdコマンドはDebianではapache2-utilsに含まれるため、これもインストールします。-Bオプションはbcryptの暗号方式、-cオプションはパスワードファイルを生成することを意味します cf. htpasswd。以下、usernameはRadicaleにログインする時のユーザーとして任意の名前を付けます。

$ sudo apt install apache2-utils
$ htpasswd -B -c /path/to/file username
New password:
Re-type new password:

設定方法のページを参考にconfigファイルを作成します cf. Configuration。今回はそのままの設定にしました。パスワードファイルまでのパスは適宜変える必要があります。

$ cat ~/.config/radicale/config
[server]
hosts = 0.0.0.0:5232

[auth]
type = htpasswd
htpasswd_filename = /path/to/file
htpasswd_encryption = bcrypt
[storage]
filesystem_folder = ~/.var/lib/radicale/collections

Systemdの設定

サーバーとして稼働されるためのsystemdファイルを作成します cf. Basic Setup。今回はシステムワイドではなく1ユーザー環境下でのsystemd initとしました。

$ cat ~/.config/systemd/user/radicale.service
[Unit]
Description=A simple CalDAV (calendar) and CardDAV (contact) server

[Service]
ExecStart=/path/to/radicale/bin/python -m radicale
Restart=on-failure

[Install]
WantedBy=default.target

ドキュメントではExecStartの項目がExecStart=/usr/bin/env python3 -m radicaleとなっていますが、今回はVirtualenv内にpython実行ファイルが存在するのでその箇所を変更します。

ここでRadicaleを試しに稼働させてみます。http://localhost:5232にアクセスしてRadicale works!と表示されれば、ローカルでRadicaleが動いていることが確認できます。

$ systemctl --user start radicale.service
$ wget http://localhost:5232
$ cat index.html
Radicale works!

Proxyサーバーの設定

外部からもアクセスできるようNginxの設定を行います cf. Reverse Proxy。まずHTTPSで通信を行うため、Let’s Encryptを利用して証明書を発行します。詳細は以前のポストを参考ください。

$ sudo systemctl stop nginx
$ su
# certbot certonly -d radicale.example.com
How would you like to authenticate with the ACME CA?
-------------------------------------------------------------------------------
1: Place files in webroot directory (webroot)
2: Spin up a temporary webserver (standalone)
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
...
- Congratulations! Your certificate and chain have been saved at ...

次にNginxの設定ファイルを作成します。

# exit
$ cat /etc/nginx/sites-available/radicale.example.com
server {
    listen  80;
    server_name radicale.example.com;
    return 301 https://radicale.example.com;
}

server {
  listen 443 ssl;
  server_name radicale.example.com;

  ssl_certificate /etc/letsencrypt/live/radicale.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/radicale.example.com/privkey.pem;

  location / {
    proxy_pass http://127.0.0.1:5232/;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass_header Authorization;
  }
}
$ sudo ln -s /etc/nginx/sites-available/radicale.example.com /etc/nginx/sites-enabled
$ sudo systemctl restart nginx

これが最小の設定だと思います。Mozilla SSL Configuration Generatorなどを参考にセキュリティやその他の設定を追加しても良いでしょう。

radicale.example.comがサーバーのIPアドレスに向いていれば、ブラウザからアクセスするとRadicale works!と表示されるはずです。

最後にサーバーの再起動後もRadicaleが自動で立ち上がるようにしておきます。

$ systemctl --user enable radicale.service

CalDAV/CardDAVクライアントの設定

サーバーが動作していることを確認できたので、各デバイスからの接続を行います cf. Clients。基本的にドキュメント通りですが躓いた箇所を補足します。

クライアントから接続した後、連絡先を追加すれば自動的にサーバー上にコレクションが作成されます。しかし、自動に任せると、コレクションの名前がハッシュ値のようなランダムな数字の配列になってしまいます。すると、Thunderbirdなどからサーバーに繋げる際、接続先のURLがhttps://radicale.example.com/username/*************と煩雑になり入力が面倒です。

そこでドキュメント終盤に書かれているように、まず手動でサーバー側にコレクションを作っておくとURLが簡潔になり覚えやすいです。

Radicaleの設定ファイル~/.config/radicale/configが上記のように設定されているなら、コレクションのルートディレクトリは~/.var/lib/radicale/collections/collection-root/username/となります。この下にカレンダーならcalendar.ics、連絡帳ならaddressbook.vcfといった任意の名前をつけたディレクトリを作成します。

$ mkdir -p ~/.var/lib/radicale/collections/collection-root/username/
$ cd ~/.var/lib/radicale/collections/collection-root/username/
$ mkdir calendar.ics
$ mkdir addressbook.vcf

そして、それぞれのディレクトリ配下に.Raidicale.propsファイルを作成します。

$ cat calendar.ics/.Radicale.props
{"tag": "VCALENDAR"}
$ cat addressbook.vcf/.Radicale.props
{"tag": "VADDRESSBOOK"}

これでクライアントからコレクションを直接指定して接続しなければならない場合、カレンダーと連絡帳の接続先はそれぞれhttps://radicale.example.com/username/calendar.icshttps://radicale.example.com/username/addressbook.vcfと記述できます。

自分の試した範囲では、macOS・iOSのカレンダー・連絡帳、Thunderbirdに登録する際にはこれらのURLが必要でしたが、DAVdroidhttps://radicale.example.comだけでCalDAV・CardDAVどちらも自動で認識してくれました。

また、macOS・iOSの設定方法はドキュメントに示されていませんが、macOSはSystem Preferences - Internet Accounts - Add Other Account... - CalDAV accountもしくはCardDav account - Account Type: Manual、iOSはSettings - Mail, Contacts, Calendars - Add Account - Other - Add CalDAV accountもしくはAdd CardDAV accountと進み、必要事項: User namePasswardServer addressを記入すると繋がりました。


今のところどのクライアントでも正常に動作しています。ドキュメントには、

A future release of Radicale 2.x.x will come with a built-in web interface that lets you create and manage collections conveniently.

Clients

との記述もあり、将来的にブラウザ経由でのコレクションの管理が予定されているようなので、より簡単に設定が可能になると思われます。