mirror of
https://github.com/Kozea/Radicale.git
synced 2025-06-26 16:45:52 +00:00
1624 lines
114 KiB
HTML
1624 lines
114 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html lang="en">
|
|
<meta charset="utf-8">
|
|
<meta content="pandoc" name="generator">
|
|
<meta content="width=device-width, initial-scale=1" name="viewport">
|
|
<style>
|
|
code{white-space: pre-wrap;}
|
|
span.smallcaps{font-variant: small-caps;}
|
|
span.underline{text-decoration: underline;}
|
|
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
|
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
|
ul.task-list{list-style: none;}
|
|
pre > code.sourceCode { white-space: pre; position: relative; }
|
|
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
|
pre > code.sourceCode > span:empty { height: 1.2em; }
|
|
.sourceCode { overflow: visible; }
|
|
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
|
div.sourceCode { margin: 1em 0; }
|
|
pre.sourceCode { margin: 0; }
|
|
@media screen {
|
|
div.sourceCode { overflow: auto; }
|
|
}
|
|
@media print {
|
|
pre > code.sourceCode { white-space: pre-wrap; }
|
|
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
|
}
|
|
pre.numberSource code
|
|
{ counter-reset: source-line 0; }
|
|
pre.numberSource code > span
|
|
{ position: relative; left: -4em; counter-increment: source-line; }
|
|
pre.numberSource code > span > a:first-child::before
|
|
{ content: counter(source-line);
|
|
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
|
border: none; display: inline-block;
|
|
-webkit-touch-callout: none; -webkit-user-select: none;
|
|
-khtml-user-select: none; -moz-user-select: none;
|
|
-ms-user-select: none; user-select: none;
|
|
padding: 0 4px; width: 4em;
|
|
color: #aaaaaa;
|
|
}
|
|
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
|
div.sourceCode
|
|
{ }
|
|
@media screen {
|
|
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
|
}
|
|
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
|
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
|
code span.at { color: #7d9029; } /* Attribute */
|
|
code span.bn { color: #40a070; } /* BaseN */
|
|
code span.bu { } /* BuiltIn */
|
|
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
|
code span.ch { color: #4070a0; } /* Char */
|
|
code span.cn { color: #880000; } /* Constant */
|
|
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
|
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
|
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
|
code span.dt { color: #902000; } /* DataType */
|
|
code span.dv { color: #40a070; } /* DecVal */
|
|
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
|
code span.ex { } /* Extension */
|
|
code span.fl { color: #40a070; } /* Float */
|
|
code span.fu { color: #06287e; } /* Function */
|
|
code span.im { } /* Import */
|
|
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
|
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
|
code span.op { color: #666666; } /* Operator */
|
|
code span.ot { color: #007020; } /* Other */
|
|
code span.pp { color: #bc7a00; } /* Preprocessor */
|
|
code span.sc { color: #4070a0; } /* SpecialChar */
|
|
code span.ss { color: #bb6688; } /* SpecialString */
|
|
code span.st { color: #4070a0; } /* String */
|
|
code span.va { color: #19177c; } /* Variable */
|
|
code span.vs { color: #4070a0; } /* VerbatimString */
|
|
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
|
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
|
|
</style>
|
|
<link href="assets/all.css" media="all" rel="stylesheet">
|
|
<link href="assets/screen.css" media="screen" rel="stylesheet">
|
|
<link href="assets/screen-narrow.css" media="screen and (max-width: 50em)" rel="stylesheet">
|
|
<link href="assets/print.css" media="print" rel="stylesheet">
|
|
<noscript><link href="assets/screen-noscript.css" media="screen" rel="stylesheet"></noscript>
|
|
<link href="https://github.com/Kozea/Radicale/releases.atom" rel="alternate" title="Radicale Releases" type="application/atom+xml">
|
|
<link href="assets/icon.png" rel="icon" type="image/png">
|
|
<title>Radicale master Documentation</title>
|
|
<meta content="Free and Open-Source CalDAV and CardDAV Server" name="description">
|
|
<script src="assets/navigation.js"></script>
|
|
<script src="assets/document-branches.js"></script>
|
|
<script src="assets/narrow-menu.js"></script>
|
|
<script src="assets/navigation-scroll-fix.js"></script>
|
|
<header>
|
|
<div class="logoContainer">
|
|
<h1>
|
|
Radicale
|
|
<span class="documentBranch">
|
|
<span>master</span>
|
|
<select style="display: none;">
|
|
<option value="v3.2-devel.html">v3.2-devel</option>
|
|
<option selected value="master.html">master</option>
|
|
<option value="v3.html">v3</option>
|
|
<option value="v2.html">v2</option>
|
|
<option value="v1.html">v1</option>
|
|
</select>
|
|
</span>
|
|
</h1>
|
|
<p>Free and Open-Source CalDAV and CardDAV Server</p>
|
|
</div>
|
|
<div class="linkContainer">
|
|
<ul>
|
|
<li><a href="https://community.kozea.fr">Made with ❤ by Kozea Community</a></li>
|
|
<li><a href="https://github.com/Kozea/Radicale">Fork me on GitHub</a></li>
|
|
</ul>
|
|
</div>
|
|
</header>
|
|
<main>
|
|
<div class="navButtonContainer" style="display: none;">
|
|
<button data-name="nav-open">Contents</button>
|
|
</div>
|
|
<nav>
|
|
<div class="navContainer">
|
|
<div class="navButtonContainer" style="display: none;">
|
|
<button data-name="nav-close">Close</button>
|
|
</div>
|
|
<h2>Contents</h2>
|
|
<ul>
|
|
<li class="level2"><a href="#getting-started" id="toc-getting-started">Getting
|
|
started</a>
|
|
<ul>
|
|
<li class="level4"><a href="#about-radicale" id="toc-about-radicale">About
|
|
Radicale</a></li>
|
|
<li class="level4"><a href="#installation" id="toc-installation">Installation</a></li>
|
|
<li class="level4"><a href="#whats-new" id="toc-whats-new">What's New?</a></li>
|
|
</ul></li>
|
|
<li class="level2"><a href="#tutorials" id="toc-tutorials">Tutorials</a>
|
|
<ul>
|
|
<li class="level3"><a href="#simple-5-minute-setup" id="toc-simple-5-minute-setup">Simple 5-minute setup</a>
|
|
<ul>
|
|
<li class="level4"><a href="#linux--bsd" id="toc-linux--bsd">Linux / *BSD</a></li>
|
|
<li class="level4"><a href="#windows" id="toc-windows">Windows</a></li>
|
|
</ul></li>
|
|
<li class="level3"><a href="#basic-configuration" id="toc-basic-configuration">Basic
|
|
Configuration</a>
|
|
<ul>
|
|
<li class="level4"><a href="#authentication" id="toc-authentication">Authentication</a></li>
|
|
<li class="level4"><a href="#addresses" id="toc-addresses">Addresses</a></li>
|
|
<li class="level4"><a href="#storage" id="toc-storage">Storage</a></li>
|
|
<li class="level4"><a href="#limits" id="toc-limits">Limits</a></li>
|
|
</ul></li>
|
|
<li class="level3"><a href="#running-as-a-service" id="toc-running-as-a-service">Running as a service</a>
|
|
<ul>
|
|
<li class="level4"><a href="#linux-with-systemd-system-wide" id="toc-linux-with-systemd-system-wide">Linux with systemd
|
|
system-wide</a></li>
|
|
<li class="level4"><a href="#linux-with-systemd-as-a-user" id="toc-linux-with-systemd-as-a-user">Linux with systemd as a
|
|
user</a></li>
|
|
<li class="level4"><a href="#windows-with-nssm---the-non-sucking-service-manager" id="toc-windows-with-nssm---the-non-sucking-service-manager">Windows
|
|
with "NSSM - the Non-Sucking Service Manager"</a></li>
|
|
</ul></li>
|
|
<li class="level3"><a href="#reverse-proxy" id="toc-reverse-proxy">Reverse Proxy</a>
|
|
<ul>
|
|
<li class="level4"><a href="#manage-user-accounts-with-the-reverse-proxy" id="toc-manage-user-accounts-with-the-reverse-proxy">Manage user
|
|
accounts with the reverse proxy</a></li>
|
|
<li class="level4"><a href="#secure-connection-between-radicale-and-the-reverse-proxy" id="toc-secure-connection-between-radicale-and-the-reverse-proxy">Secure
|
|
connection between Radicale and the reverse proxy</a></li>
|
|
</ul></li>
|
|
<li class="level3"><a href="#wsgi-server" id="toc-wsgi-server">WSGI Server</a>
|
|
<ul>
|
|
<li class="level4"><a href="#manage-user-accounts-with-the-wsgi-server" id="toc-manage-user-accounts-with-the-wsgi-server">Manage user accounts
|
|
with the WSGI server</a></li>
|
|
</ul></li>
|
|
<li class="level3"><a href="#versioning-with-git" id="toc-versioning-with-git">Versioning with Git</a></li>
|
|
</ul></li>
|
|
<li class="level2"><a href="#documentation-1" id="toc-documentation-1">Documentation</a>
|
|
<ul>
|
|
<li class="level3"><a href="#configuration" id="toc-configuration">Configuration</a>
|
|
<ul>
|
|
<li class="level4"><a href="#server" id="toc-server">server</a></li>
|
|
<li class="level4"><a href="#encoding" id="toc-encoding">encoding</a></li>
|
|
<li class="level4"><a href="#auth" id="toc-auth">auth</a></li>
|
|
<li class="level4"><a href="#rights" id="toc-rights">rights</a></li>
|
|
<li class="level4"><a href="#storage-1" id="toc-storage-1">storage</a></li>
|
|
<li class="level4"><a href="#web" id="toc-web">web</a></li>
|
|
<li class="level4"><a href="#logging" id="toc-logging">logging</a></li>
|
|
<li class="level4"><a href="#headers" id="toc-headers">headers</a></li>
|
|
</ul></li>
|
|
<li class="level3"><a href="#supported-clients" id="toc-supported-clients">Supported
|
|
Clients</a>
|
|
<ul>
|
|
<li class="level4"><a href="#davx⁵" id="toc-davx⁵">DAVx⁵</a></li>
|
|
<li class="level4"><a href="#gnome-calendar-contacts-and-evolution" id="toc-gnome-calendar-contacts-and-evolution">GNOME Calendar, Contacts
|
|
and Evolution</a></li>
|
|
<li class="level4"><a href="#thunderbird" id="toc-thunderbird">Thunderbird</a></li>
|
|
<li class="level4"><a href="#infcloud-caldavzap-and-carddavmate" id="toc-infcloud-caldavzap-and-carddavmate">InfCloud, CalDavZAP and
|
|
CardDavMATE</a></li>
|
|
<li class="level4"><a href="#command-line" id="toc-command-line">Command line</a></li>
|
|
</ul></li>
|
|
<li class="level3"><a href="#authentication-and-rights" id="toc-authentication-and-rights">Authentication and Rights</a></li>
|
|
<li class="level3"><a href="#storage-2" id="toc-storage-2">Storage</a>
|
|
<ul>
|
|
<li class="level4"><a href="#layout" id="toc-layout">Layout</a></li>
|
|
<li class="level4"><a href="#locking" id="toc-locking">Locking</a></li>
|
|
<li class="level4"><a href="#manually-creating-collections" id="toc-manually-creating-collections">Manually creating
|
|
collections</a></li>
|
|
</ul></li>
|
|
<li class="level3"><a href="#logging-1" id="toc-logging-1">Logging</a></li>
|
|
<li class="level3"><a href="#architecture" id="toc-architecture">Architecture</a>
|
|
<ul>
|
|
<li class="level4"><a href="#protocol-overview" id="toc-protocol-overview">Protocol
|
|
overview</a></li>
|
|
<li class="level4"><a href="#code-architecture" id="toc-code-architecture">Code
|
|
Architecture</a></li>
|
|
</ul></li>
|
|
<li class="level3"><a href="#plugins" id="toc-plugins">Plugins</a>
|
|
<ul>
|
|
<li class="level4"><a href="#getting-started-1" id="toc-getting-started-1">Getting
|
|
started</a></li>
|
|
<li class="level4"><a href="#authentication-plugins" id="toc-authentication-plugins">Authentication plugins</a></li>
|
|
<li class="level4"><a href="#rights-management-plugins" id="toc-rights-management-plugins">Rights management plugins</a></li>
|
|
<li class="level4"><a href="#web-plugins" id="toc-web-plugins">Web plugins</a></li>
|
|
<li class="level4"><a href="#storage-plugins" id="toc-storage-plugins">Storage
|
|
plugins</a></li>
|
|
</ul></li>
|
|
</ul></li>
|
|
<li class="level2"><a href="#contribute" id="toc-contribute">Contribute</a>
|
|
<ul>
|
|
<li class="level4"><a href="#report-bugs" id="toc-report-bugs">Report Bugs</a></li>
|
|
<li class="level4"><a href="#hack" id="toc-hack">Hack</a></li>
|
|
<li class="level4"><a href="#documentation-2" id="toc-documentation-2">Documentation</a></li>
|
|
</ul></li>
|
|
<li class="level2"><a href="#download" id="toc-download">Download</a>
|
|
<ul>
|
|
<li class="level4"><a href="#pypi" id="toc-pypi">PyPI</a></li>
|
|
<li class="level4"><a href="#git-repository" id="toc-git-repository">Git
|
|
Repository</a></li>
|
|
<li class="level4"><a href="#source-packages" id="toc-source-packages">Source
|
|
Packages</a></li>
|
|
<li class="level4"><a href="#linux-distribution-packages" id="toc-linux-distribution-packages">Linux Distribution
|
|
Packages</a></li>
|
|
</ul></li>
|
|
<li class="level2"><a href="#about" id="toc-about">About</a>
|
|
<ul>
|
|
<li class="level4"><a href="#main-goals" id="toc-main-goals">Main Goals</a></li>
|
|
<li class="level4"><a href="#what-radicale-will-never-be" id="toc-what-radicale-will-never-be">What Radicale Will Never
|
|
Be</a></li>
|
|
<li class="level4"><a href="#technical-choices" id="toc-technical-choices">Technical
|
|
Choices</a></li>
|
|
<li class="level4"><a href="#history" id="toc-history">History</a></li>
|
|
</ul></li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
<div class="documentContainer">
|
|
<section class="level2" id="getting-started">
|
|
<h2>Getting started <a class="headerlink" href="#getting-started">¶</a></h2>
|
|
<section class="level4" id="about-radicale">
|
|
<h4>About Radicale <a class="headerlink" href="#about-radicale">¶</a></h4>
|
|
<p>Radicale is a small but powerful CalDAV (calendars, to-do lists) and
|
|
CardDAV (contacts) server, that:</p>
|
|
<ul>
|
|
<li>Shares calendars and contact lists through CalDAV, CardDAV and
|
|
HTTP.</li>
|
|
<li>Supports events, todos, journal entries and business cards.</li>
|
|
<li>Works out-of-the-box, no complicated setup or configuration
|
|
required.</li>
|
|
<li>Can limit access by authentication.</li>
|
|
<li>Can secure connections with TLS.</li>
|
|
<li>Works with many <a href="#supported-clients">CalDAV and CardDAV
|
|
clients</a>.</li>
|
|
<li>Stores all data on the file system in a simple folder
|
|
structure.</li>
|
|
<li>Can be extended with plugins.</li>
|
|
<li>Is GPLv3-licensed free software.</li>
|
|
</ul>
|
|
</section>
|
|
<section class="level4" id="installation">
|
|
<h4>Installation <a class="headerlink" href="#installation">¶</a></h4>
|
|
<p>Radicale is really easy to install and works out-of-the-box.</p>
|
|
<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a aria-hidden="true" href="#cb1-1" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> pip install <span class="at">--upgrade</span> https://github.com/Kozea/Radicale/archive/master.tar.gz</span>
|
|
<span id="cb1-2"><a aria-hidden="true" href="#cb1-2" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> radicale <span class="at">--storage-filesystem-folder</span><span class="op">=</span>~/.var/lib/radicale/collections</span></code></pre></div>
|
|
<p>When the server is launched, open <a href="http://localhost:5232">http://localhost:5232</a> in your browser!
|
|
You can login with any username and password.</p>
|
|
<p>Want more? Check the <a href="#tutorials">tutorials</a> and the <a href="#documentation-1">documentation</a>.</p>
|
|
</section>
|
|
<section class="level4" id="whats-new">
|
|
<h4>What's New? <a class="headerlink" href="#whats-new">¶</a></h4>
|
|
<p>Read the <a href="https://github.com/Kozea/Radicale/blob/master/CHANGELOG.md">changelog
|
|
on GitHub.</a></p>
|
|
</section>
|
|
</section>
|
|
<section class="level2" id="tutorials">
|
|
<h2>Tutorials <a class="headerlink" href="#tutorials">¶</a></h2>
|
|
<section class="level3" id="simple-5-minute-setup">
|
|
<h3>Simple 5-minute setup <a class="headerlink" href="#simple-5-minute-setup">¶</a></h3>
|
|
<p>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!</p>
|
|
<p>When everything works, you can get a <a href="#supported-clients">client</a> and start creating calendars and
|
|
address books. The server <strong>only</strong> binds to localhost (is
|
|
<strong>not</strong> reachable over the network) and you can log in with
|
|
any username and password. If Radicale fits your needs, it may be time
|
|
for <a href="#basic-configuration">some basic configuration</a>.</p>
|
|
<p>Follow one of the chapters below depending on your operating
|
|
system.</p>
|
|
<section class="level4" id="linux--bsd">
|
|
<h4>Linux / *BSD <a class="headerlink" href="#linux--bsd">¶</a></h4>
|
|
<p>First, make sure that <strong>python</strong> 3.5 or later
|
|
(<strong>python</strong> ≥ 3.6 is recommended) and <strong>pip</strong>
|
|
are installed. On most distributions it should be enough to install the
|
|
package <code>python3-pip</code>.</p>
|
|
<p>Then open a console and type:</p>
|
|
<div class="sourceCode" id="cb2"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a aria-hidden="true" href="#cb2-1" tabindex="-1"></a><span class="co"># Run the following command as root or</span></span>
|
|
<span id="cb2-2"><a aria-hidden="true" href="#cb2-2" tabindex="-1"></a><span class="co"># add the --user argument to only install for the current user</span></span>
|
|
<span id="cb2-3"><a aria-hidden="true" href="#cb2-3" tabindex="-1"></a><span class="ex">$</span> python3 <span class="at">-m</span> pip install <span class="at">--upgrade</span> https://github.com/Kozea/Radicale/archive/master.tar.gz</span>
|
|
<span id="cb2-4"><a aria-hidden="true" href="#cb2-4" tabindex="-1"></a><span class="ex">$</span> python3 <span class="at">-m</span> radicale <span class="at">--storage-filesystem-folder</span><span class="op">=</span>~/.var/lib/radicale/collections</span></code></pre></div>
|
|
<p>Victory! Open <a href="http://localhost:5232">http://localhost:5232</a> in your browser!
|
|
You can log in with any username and password.</p>
|
|
</section>
|
|
<section class="level4" id="windows">
|
|
<h4>Windows <a class="headerlink" href="#windows">¶</a></h4>
|
|
<p>The first step is to install Python. Go to <a href="https://python.org">python.org</a> and download the latest version
|
|
of Python 3. Then run the installer. On the first window of the
|
|
installer, check the "Add Python to PATH" box and click on "Install
|
|
now". Wait a couple of minutes, it's done!</p>
|
|
<p>Launch a command prompt and type:</p>
|
|
<div class="sourceCode" id="cb3"><pre class="sourceCode powershell"><code class="sourceCode powershell"><span id="cb3-1"><a aria-hidden="true" href="#cb3-1" tabindex="-1"></a>python <span class="op">-</span>m pip install <span class="op">--</span>upgrade https<span class="op">://</span>github<span class="op">.</span><span class="fu">com</span><span class="op">/</span>Kozea<span class="op">/</span>Radicale<span class="op">/</span>archive<span class="op">/</span>master<span class="op">.</span><span class="fu">tar</span><span class="op">.</span><span class="fu">gz</span></span>
|
|
<span id="cb3-2"><a aria-hidden="true" href="#cb3-2" tabindex="-1"></a>python <span class="op">-</span>m radicale <span class="op">--</span>storage<span class="op">-</span>filesystem<span class="op">-</span>folder<span class="op">=~/</span>radicale<span class="op">/</span>collections</span></code></pre></div>
|
|
<p>Victory! Open <a href="http://localhost:5232">http://localhost:5232</a> in your browser!
|
|
You can log in with any username and password.</p>
|
|
</section>
|
|
</section>
|
|
<section class="level3" id="basic-configuration">
|
|
<h3>Basic Configuration <a class="headerlink" href="#basic-configuration">¶</a></h3>
|
|
<p>Installation instructions can be found in the <a href="#simple-5-minute-setup">simple 5-minute setup</a> tutorial.</p>
|
|
<p>Radicale tries to load configuration files from
|
|
<code>/etc/radicale/config</code> and
|
|
<code>~/.config/radicale/config</code>. Custom paths can be specified
|
|
with the <code>--config /path/to/config</code> command line argument or
|
|
the <code>RADICALE_CONFIG</code> environment variable. Multiple
|
|
configuration files can be separated by <code>:</code> (resp.
|
|
<code>;</code> on Windows). Paths that start with <code>?</code> are
|
|
optional.</p>
|
|
<p>You should create a new configuration file at the desired location.
|
|
(If the use of a configuration file is inconvenient, all options can be
|
|
passed via command line arguments.)</p>
|
|
<p>All configuration options are described in detail in the <a href="#configuration">Configuration</a> section.</p>
|
|
<section class="level4" id="authentication">
|
|
<h4>Authentication <a class="headerlink" href="#authentication">¶</a></h4>
|
|
<p>In its default configuration Radicale doesn't check usernames or
|
|
passwords. If the server is reachable over a network, you should change
|
|
this.</p>
|
|
<p>First a <code>users</code> file with all usernames and passwords must
|
|
be created. It can be stored in the same directory as the configuration
|
|
file.</p>
|
|
<section class="level5" id="the-secure-way">
|
|
<h5>The secure way <a class="headerlink" href="#the-secure-way">¶</a></h5>
|
|
<p>The <code>users</code> file can be created and managed with <a href="https://httpd.apache.org/docs/current/programs/htpasswd.html">htpasswd</a>:</p>
|
|
<div class="sourceCode" id="cb4"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a aria-hidden="true" href="#cb4-1" tabindex="-1"></a><span class="co"># Create a new htpasswd file with the user "user1"</span></span>
|
|
<span id="cb4-2"><a aria-hidden="true" href="#cb4-2" tabindex="-1"></a><span class="ex">$</span> htpasswd <span class="at">-c</span> /path/to/users user1</span>
|
|
<span id="cb4-3"><a aria-hidden="true" href="#cb4-3" tabindex="-1"></a><span class="ex">New</span> password:</span>
|
|
<span id="cb4-4"><a aria-hidden="true" href="#cb4-4" tabindex="-1"></a><span class="ex">Re-type</span> new password:</span>
|
|
<span id="cb4-5"><a aria-hidden="true" href="#cb4-5" tabindex="-1"></a><span class="co"># Add another user</span></span>
|
|
<span id="cb4-6"><a aria-hidden="true" href="#cb4-6" tabindex="-1"></a><span class="ex">$</span> htpasswd /path/to/users user2</span>
|
|
<span id="cb4-7"><a aria-hidden="true" href="#cb4-7" tabindex="-1"></a><span class="ex">New</span> password:</span>
|
|
<span id="cb4-8"><a aria-hidden="true" href="#cb4-8" tabindex="-1"></a><span class="ex">Re-type</span> new password:</span></code></pre></div>
|
|
<p>Authentication can be enabled with the following configuration:</p>
|
|
<div class="sourceCode" id="cb5"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb5-1"><a aria-hidden="true" href="#cb5-1" tabindex="-1"></a><span class="kw">[auth]</span></span>
|
|
<span id="cb5-2"><a aria-hidden="true" href="#cb5-2" tabindex="-1"></a><span class="dt">type </span><span class="ot">=</span><span class="st"> htpasswd</span></span>
|
|
<span id="cb5-3"><a aria-hidden="true" href="#cb5-3" tabindex="-1"></a><span class="dt">htpasswd_filename </span><span class="ot">=</span><span class="st"> /path/to/users</span></span>
|
|
<span id="cb5-4"><a aria-hidden="true" href="#cb5-4" tabindex="-1"></a><span class="co"># encryption method used in the htpasswd file</span></span>
|
|
<span id="cb5-5"><a aria-hidden="true" href="#cb5-5" tabindex="-1"></a><span class="dt">htpasswd_encryption </span><span class="ot">=</span><span class="st"> md5</span></span></code></pre></div>
|
|
</section>
|
|
<section class="level5" id="the-simple-but-insecure-way">
|
|
<h5>The simple but insecure way <a class="headerlink" href="#the-simple-but-insecure-way">¶</a></h5>
|
|
<p>Create the <code>users</code> file by hand with lines containing the
|
|
username and password separated by <code>:</code>. Example:</p>
|
|
<pre class="htpasswd"><code>user1:password1
|
|
user2:password2</code></pre>
|
|
<p>Authentication can be enabled with the following configuration:</p>
|
|
<div class="sourceCode" id="cb7"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb7-1"><a aria-hidden="true" href="#cb7-1" tabindex="-1"></a><span class="kw">[auth]</span></span>
|
|
<span id="cb7-2"><a aria-hidden="true" href="#cb7-2" tabindex="-1"></a><span class="dt">type </span><span class="ot">=</span><span class="st"> htpasswd</span></span>
|
|
<span id="cb7-3"><a aria-hidden="true" href="#cb7-3" tabindex="-1"></a><span class="dt">htpasswd_filename </span><span class="ot">=</span><span class="st"> /path/to/users</span></span>
|
|
<span id="cb7-4"><a aria-hidden="true" href="#cb7-4" tabindex="-1"></a><span class="co"># encryption method used in the htpasswd file</span></span>
|
|
<span id="cb7-5"><a aria-hidden="true" href="#cb7-5" tabindex="-1"></a><span class="dt">htpasswd_encryption </span><span class="ot">=</span><span class="st"> plain</span></span></code></pre></div>
|
|
</section>
|
|
</section>
|
|
<section class="level4" id="addresses">
|
|
<h4>Addresses <a class="headerlink" href="#addresses">¶</a></h4>
|
|
<p>The default configuration binds the server to localhost. It can't be
|
|
reached from other computers. This can be changed with the following
|
|
configuration options (IPv4 and IPv6):</p>
|
|
<div class="sourceCode" id="cb8"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb8-1"><a aria-hidden="true" href="#cb8-1" tabindex="-1"></a><span class="kw">[server]</span></span>
|
|
<span id="cb8-2"><a aria-hidden="true" href="#cb8-2" tabindex="-1"></a><span class="dt">hosts </span><span class="ot">=</span><span class="st"> 0.0.0.0:5232, [::]:5232</span></span></code></pre></div>
|
|
</section>
|
|
<section class="level4" id="storage">
|
|
<h4>Storage <a class="headerlink" href="#storage">¶</a></h4>
|
|
<p>Data is stored in the folder
|
|
<code>/var/lib/radicale/collections</code>. The path can be changed with
|
|
the following configuration:</p>
|
|
<div class="sourceCode" id="cb9"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb9-1"><a aria-hidden="true" href="#cb9-1" tabindex="-1"></a><span class="kw">[storage]</span></span>
|
|
<span id="cb9-2"><a aria-hidden="true" href="#cb9-2" tabindex="-1"></a><span class="dt">filesystem_folder </span><span class="ot">=</span><span class="st"> /path/to/storage</span></span></code></pre></div>
|
|
<blockquote>
|
|
<p><strong>Security:</strong> The storage folder should not be readable
|
|
by unauthorized users. Otherwise, they can read the calendar data and
|
|
lock the storage. You can find OS dependent instructions in the <a href="#running-as-a-service">Running as a service</a> section.</p>
|
|
</blockquote>
|
|
</section>
|
|
<section class="level4" id="limits">
|
|
<h4>Limits <a class="headerlink" href="#limits">¶</a></h4>
|
|
<p>Radicale enforces limits on the maximum number of parallel
|
|
connections, the maximum file size (important for contacts with big
|
|
photos) and the rate of incorrect authentication attempts. Connections
|
|
are terminated after a timeout. The default values should be fine for
|
|
most scenarios.</p>
|
|
<div class="sourceCode" id="cb10"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb10-1"><a aria-hidden="true" href="#cb10-1" tabindex="-1"></a><span class="kw">[server]</span></span>
|
|
<span id="cb10-2"><a aria-hidden="true" href="#cb10-2" tabindex="-1"></a><span class="dt">max_connections </span><span class="ot">=</span><span class="st"> </span><span class="dv">20</span></span>
|
|
<span id="cb10-3"><a aria-hidden="true" href="#cb10-3" tabindex="-1"></a><span class="co"># 100 Megabyte</span></span>
|
|
<span id="cb10-4"><a aria-hidden="true" href="#cb10-4" tabindex="-1"></a><span class="dt">max_content_length </span><span class="ot">=</span><span class="st"> </span><span class="dv">100000000</span></span>
|
|
<span id="cb10-5"><a aria-hidden="true" href="#cb10-5" tabindex="-1"></a><span class="co"># 30 seconds</span></span>
|
|
<span id="cb10-6"><a aria-hidden="true" href="#cb10-6" tabindex="-1"></a><span class="dt">timeout </span><span class="ot">=</span><span class="st"> </span><span class="dv">30</span></span>
|
|
<span id="cb10-7"><a aria-hidden="true" href="#cb10-7" tabindex="-1"></a></span>
|
|
<span id="cb10-8"><a aria-hidden="true" href="#cb10-8" tabindex="-1"></a><span class="kw">[auth]</span></span>
|
|
<span id="cb10-9"><a aria-hidden="true" href="#cb10-9" tabindex="-1"></a><span class="co"># Average delay after failed login attempts in seconds</span></span>
|
|
<span id="cb10-10"><a aria-hidden="true" href="#cb10-10" tabindex="-1"></a><span class="dt">delay </span><span class="ot">=</span><span class="st"> </span><span class="dv">1</span></span></code></pre></div>
|
|
</section>
|
|
</section>
|
|
<section class="level3" id="running-as-a-service">
|
|
<h3>Running as a service <a class="headerlink" href="#running-as-a-service">¶</a></h3>
|
|
<p>The method to run Radicale as a service depends on your host
|
|
operating system. Follow one of the chapters below depending on your
|
|
operating system and requirements.</p>
|
|
<section class="level4" id="linux-with-systemd-system-wide">
|
|
<h4>Linux with systemd system-wide <a class="headerlink" href="#linux-with-systemd-system-wide">¶</a></h4>
|
|
<p>Create the <strong>radicale</strong> user and group for the Radicale
|
|
service. (Run
|
|
<code>useradd --system --user-group --home-dir / --shell /sbin/nologin radicale</code>
|
|
as root.) The storage folder must be writable by
|
|
<strong>radicale</strong>. (Run
|
|
<code>mkdir -p /var/lib/radicale/collections && chown -R radicale:radicale /var/lib/radicale/collections</code>
|
|
as root.)</p>
|
|
<blockquote>
|
|
<p><strong>Security:</strong> The storage should not be readable by
|
|
others. (Run <code>chmod -R o= /var/lib/radicale/collections</code> as
|
|
root.)</p>
|
|
</blockquote>
|
|
<p>Create the file
|
|
<code>/etc/systemd/system/radicale.service</code>:</p>
|
|
<div class="sourceCode" id="cb11"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb11-1"><a aria-hidden="true" href="#cb11-1" tabindex="-1"></a><span class="kw">[Unit]</span></span>
|
|
<span id="cb11-2"><a aria-hidden="true" href="#cb11-2" tabindex="-1"></a><span class="dt">Description</span><span class="ot">=</span><span class="st">A simple CalDAV (calendar) and CardDAV (contact) server</span></span>
|
|
<span id="cb11-3"><a aria-hidden="true" href="#cb11-3" tabindex="-1"></a><span class="dt">After</span><span class="ot">=</span><span class="st">network.target</span></span>
|
|
<span id="cb11-4"><a aria-hidden="true" href="#cb11-4" tabindex="-1"></a><span class="dt">Requires</span><span class="ot">=</span><span class="st">network.target</span></span>
|
|
<span id="cb11-5"><a aria-hidden="true" href="#cb11-5" tabindex="-1"></a></span>
|
|
<span id="cb11-6"><a aria-hidden="true" href="#cb11-6" tabindex="-1"></a><span class="kw">[Service]</span></span>
|
|
<span id="cb11-7"><a aria-hidden="true" href="#cb11-7" tabindex="-1"></a><span class="dt">ExecStart</span><span class="ot">=</span><span class="st">/usr/bin/env python3 -m radicale</span></span>
|
|
<span id="cb11-8"><a aria-hidden="true" href="#cb11-8" tabindex="-1"></a><span class="dt">Restart</span><span class="ot">=</span><span class="st">on-failure</span></span>
|
|
<span id="cb11-9"><a aria-hidden="true" href="#cb11-9" tabindex="-1"></a><span class="dt">User</span><span class="ot">=</span><span class="st">radicale</span></span>
|
|
<span id="cb11-10"><a aria-hidden="true" href="#cb11-10" tabindex="-1"></a><span class="co"># Deny other users access to the calendar data</span></span>
|
|
<span id="cb11-11"><a aria-hidden="true" href="#cb11-11" tabindex="-1"></a><span class="dt">UMask</span><span class="ot">=</span><span class="dv">0027</span></span>
|
|
<span id="cb11-12"><a aria-hidden="true" href="#cb11-12" tabindex="-1"></a><span class="co"># Optional security settings</span></span>
|
|
<span id="cb11-13"><a aria-hidden="true" href="#cb11-13" tabindex="-1"></a><span class="dt">PrivateTmp</span><span class="ot">=</span><span class="kw">true</span></span>
|
|
<span id="cb11-14"><a aria-hidden="true" href="#cb11-14" tabindex="-1"></a><span class="dt">ProtectSystem</span><span class="ot">=</span><span class="st">strict</span></span>
|
|
<span id="cb11-15"><a aria-hidden="true" href="#cb11-15" tabindex="-1"></a><span class="dt">ProtectHome</span><span class="ot">=</span><span class="kw">true</span></span>
|
|
<span id="cb11-16"><a aria-hidden="true" href="#cb11-16" tabindex="-1"></a><span class="dt">PrivateDevices</span><span class="ot">=</span><span class="kw">true</span></span>
|
|
<span id="cb11-17"><a aria-hidden="true" href="#cb11-17" tabindex="-1"></a><span class="dt">ProtectKernelTunables</span><span class="ot">=</span><span class="kw">true</span></span>
|
|
<span id="cb11-18"><a aria-hidden="true" href="#cb11-18" tabindex="-1"></a><span class="dt">ProtectKernelModules</span><span class="ot">=</span><span class="kw">true</span></span>
|
|
<span id="cb11-19"><a aria-hidden="true" href="#cb11-19" tabindex="-1"></a><span class="dt">ProtectControlGroups</span><span class="ot">=</span><span class="kw">true</span></span>
|
|
<span id="cb11-20"><a aria-hidden="true" href="#cb11-20" tabindex="-1"></a><span class="dt">NoNewPrivileges</span><span class="ot">=</span><span class="kw">true</span></span>
|
|
<span id="cb11-21"><a aria-hidden="true" href="#cb11-21" tabindex="-1"></a><span class="dt">ReadWritePaths</span><span class="ot">=</span><span class="st">/var/lib/radicale/collections</span></span>
|
|
<span id="cb11-22"><a aria-hidden="true" href="#cb11-22" tabindex="-1"></a></span>
|
|
<span id="cb11-23"><a aria-hidden="true" href="#cb11-23" tabindex="-1"></a><span class="kw">[Install]</span></span>
|
|
<span id="cb11-24"><a aria-hidden="true" href="#cb11-24" tabindex="-1"></a><span class="dt">WantedBy</span><span class="ot">=</span><span class="st">multi-user.target</span></span></code></pre></div>
|
|
<p>Radicale will load the configuration file from
|
|
<code>/etc/radicale/config</code>.</p>
|
|
<p>To enable and manage the service run:</p>
|
|
<div class="sourceCode" id="cb12"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb12-1"><a aria-hidden="true" href="#cb12-1" tabindex="-1"></a><span class="co"># Enable the service</span></span>
|
|
<span id="cb12-2"><a aria-hidden="true" href="#cb12-2" tabindex="-1"></a><span class="ex">$</span> systemctl enable radicale</span>
|
|
<span id="cb12-3"><a aria-hidden="true" href="#cb12-3" tabindex="-1"></a><span class="co"># Start the service</span></span>
|
|
<span id="cb12-4"><a aria-hidden="true" href="#cb12-4" tabindex="-1"></a><span class="ex">$</span> systemctl start radicale</span>
|
|
<span id="cb12-5"><a aria-hidden="true" href="#cb12-5" tabindex="-1"></a><span class="co"># Check the status of the service</span></span>
|
|
<span id="cb12-6"><a aria-hidden="true" href="#cb12-6" tabindex="-1"></a><span class="ex">$</span> systemctl status radicale</span>
|
|
<span id="cb12-7"><a aria-hidden="true" href="#cb12-7" tabindex="-1"></a><span class="co"># View all log messages</span></span>
|
|
<span id="cb12-8"><a aria-hidden="true" href="#cb12-8" tabindex="-1"></a><span class="ex">$</span> journalctl <span class="at">--unit</span> radicale.service</span></code></pre></div>
|
|
</section>
|
|
<section class="level4" id="linux-with-systemd-as-a-user">
|
|
<h4>Linux with systemd as a user <a class="headerlink" href="#linux-with-systemd-as-a-user">¶</a></h4>
|
|
<p>Create the file
|
|
<code>~/.config/systemd/user/radicale.service</code>:</p>
|
|
<div class="sourceCode" id="cb13"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb13-1"><a aria-hidden="true" href="#cb13-1" tabindex="-1"></a><span class="kw">[Unit]</span></span>
|
|
<span id="cb13-2"><a aria-hidden="true" href="#cb13-2" tabindex="-1"></a><span class="dt">Description</span><span class="ot">=</span><span class="st">A simple CalDAV (calendar) and CardDAV (contact) server</span></span>
|
|
<span id="cb13-3"><a aria-hidden="true" href="#cb13-3" tabindex="-1"></a></span>
|
|
<span id="cb13-4"><a aria-hidden="true" href="#cb13-4" tabindex="-1"></a><span class="kw">[Service]</span></span>
|
|
<span id="cb13-5"><a aria-hidden="true" href="#cb13-5" tabindex="-1"></a><span class="dt">ExecStart</span><span class="ot">=</span><span class="st">/usr/bin/env python3 -m radicale</span></span>
|
|
<span id="cb13-6"><a aria-hidden="true" href="#cb13-6" tabindex="-1"></a><span class="dt">Restart</span><span class="ot">=</span><span class="st">on-failure</span></span>
|
|
<span id="cb13-7"><a aria-hidden="true" href="#cb13-7" tabindex="-1"></a></span>
|
|
<span id="cb13-8"><a aria-hidden="true" href="#cb13-8" tabindex="-1"></a><span class="kw">[Install]</span></span>
|
|
<span id="cb13-9"><a aria-hidden="true" href="#cb13-9" tabindex="-1"></a><span class="dt">WantedBy</span><span class="ot">=</span><span class="st">default.target</span></span></code></pre></div>
|
|
<p>Radicale will load the configuration file from
|
|
<code>~/.config/radicale/config</code>. You should set the configuration
|
|
option <code>filesystem_folder</code> in the <code>storage</code>
|
|
section to something like
|
|
<code>~/.var/lib/radicale/collections</code>.</p>
|
|
<p>To enable and manage the service run:</p>
|
|
<div class="sourceCode" id="cb14"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb14-1"><a aria-hidden="true" href="#cb14-1" tabindex="-1"></a><span class="co"># Enable the service</span></span>
|
|
<span id="cb14-2"><a aria-hidden="true" href="#cb14-2" tabindex="-1"></a><span class="ex">$</span> systemctl <span class="at">--user</span> enable radicale</span>
|
|
<span id="cb14-3"><a aria-hidden="true" href="#cb14-3" tabindex="-1"></a><span class="co"># Start the service</span></span>
|
|
<span id="cb14-4"><a aria-hidden="true" href="#cb14-4" tabindex="-1"></a><span class="ex">$</span> systemctl <span class="at">--user</span> start radicale</span>
|
|
<span id="cb14-5"><a aria-hidden="true" href="#cb14-5" tabindex="-1"></a><span class="co"># Check the status of the service</span></span>
|
|
<span id="cb14-6"><a aria-hidden="true" href="#cb14-6" tabindex="-1"></a><span class="ex">$</span> systemctl <span class="at">--user</span> status radicale</span>
|
|
<span id="cb14-7"><a aria-hidden="true" href="#cb14-7" tabindex="-1"></a><span class="co"># View all log messages</span></span>
|
|
<span id="cb14-8"><a aria-hidden="true" href="#cb14-8" tabindex="-1"></a><span class="ex">$</span> journalctl <span class="at">--user</span> <span class="at">--unit</span> radicale.service</span></code></pre></div>
|
|
</section>
|
|
<section class="level4" id="windows-with-nssm---the-non-sucking-service-manager">
|
|
<h4>Windows with "NSSM - the Non-Sucking Service Manager" <a class="headerlink" href="#windows-with-nssm---the-non-sucking-service-manager">¶</a></h4>
|
|
<p>First install <a href="https://nssm.cc/">NSSM</a> and start
|
|
<code>nssm install</code> in a command prompt. Apply the following
|
|
configuration:</p>
|
|
<ul>
|
|
<li>Service name: <code>Radicale</code></li>
|
|
<li>Application
|
|
<ul>
|
|
<li>Path: <code>C:\Path\To\Python\python.exe</code></li>
|
|
<li>Arguments: <code>-m radicale --config C:\Path\To\Config</code></li>
|
|
</ul></li>
|
|
<li>I/O redirection
|
|
<ul>
|
|
<li>Error: <code>C:\Path\To\Radicale.log</code></li>
|
|
</ul></li>
|
|
</ul>
|
|
<blockquote>
|
|
<p><strong>Security:</strong> Be aware that the service runs in the
|
|
local system account, you might want to change this. Managing user
|
|
accounts is beyond the scope of this manual. Also, make sure that the
|
|
storage folder and log file is not readable by unauthorized users.</p>
|
|
</blockquote>
|
|
<p>The log file might grow very big over time, you can configure file
|
|
rotation in <strong>NSSM</strong> to prevent this.</p>
|
|
<p>The service is configured to start automatically when the computer
|
|
starts. To start the service manually open <strong>Services</strong> in
|
|
<strong>Computer Management</strong> and start the
|
|
<strong>Radicale</strong> service.</p>
|
|
</section>
|
|
</section>
|
|
<section class="level3" id="reverse-proxy">
|
|
<h3>Reverse Proxy <a class="headerlink" href="#reverse-proxy">¶</a></h3>
|
|
<p>When a reverse proxy is used, and Radicale should be made available
|
|
at a path below the root (such as <code>/radicale/</code>), then this
|
|
path must be provided via the <code>X-Script-Name</code> header (without
|
|
a trailing <code>/</code>). The proxy must remove the location from the
|
|
URL path that is forwarded to Radicale. If Radicale should be made
|
|
available at the root of the web server (in the nginx case using
|
|
<code>location /</code>), then the setting of the
|
|
<code>X-Script-Name</code> header should be removed from the example
|
|
below.</p>
|
|
<p>Example <strong>nginx</strong> configuration:</p>
|
|
<pre class="nginx"><code>location /radicale/ { # The trailing / is important!
|
|
proxy_pass http://localhost:5232/; # The / is important!
|
|
proxy_set_header X-Script-Name /radicale;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header Host $http_host;
|
|
proxy_pass_header Authorization;
|
|
}</code></pre>
|
|
<p>Example <strong>Caddy</strong> configuration with basicauth from
|
|
Caddy:</p>
|
|
<pre class="Caddy"><code>handle_path /radicale* {
|
|
basicauth {
|
|
user hash
|
|
}
|
|
reverse_proxy localhost:5232 {
|
|
header_up +X-Script-Name "/radicale"
|
|
header_up +X-remote-user "{http.auth.user.id}"
|
|
}
|
|
}</code></pre>
|
|
<p>Example <strong>Apache</strong> configuration:</p>
|
|
<div class="sourceCode" id="cb17"><pre class="sourceCode apache"><code class="sourceCode apache"><span id="cb17-1"><a aria-hidden="true" href="#cb17-1" tabindex="-1"></a><span class="ex">RewriteEngine</span><span class="ch"> </span><span class="kw">On</span></span>
|
|
<span id="cb17-2"><a aria-hidden="true" href="#cb17-2" tabindex="-1"></a>RewriteRule<span class="st"> ^/radicale$ /radicale/ [R,L]</span></span>
|
|
<span id="cb17-3"><a aria-hidden="true" href="#cb17-3" tabindex="-1"></a></span>
|
|
<span id="cb17-4"><a aria-hidden="true" href="#cb17-4" tabindex="-1"></a><span class="fu"><Location</span><span class="at"> "/radicale/"</span><span class="fu">></span></span>
|
|
<span id="cb17-5"><a aria-hidden="true" href="#cb17-5" tabindex="-1"></a> ProxyPass<span class="st"> http://localhost:5232/ retry=0</span></span>
|
|
<span id="cb17-6"><a aria-hidden="true" href="#cb17-6" tabindex="-1"></a> ProxyPassReverse<span class="st"> http://localhost:5232/</span></span>
|
|
<span id="cb17-7"><a aria-hidden="true" href="#cb17-7" tabindex="-1"></a> RequestHeader<span class="st"> set X-Script-Name /radicale</span></span>
|
|
<span id="cb17-8"><a aria-hidden="true" href="#cb17-8" tabindex="-1"></a> RequestHeader<span class="st"> set X-Forwarded-Port "%{SERVER_PORT}s"</span></span>
|
|
<span id="cb17-9"><a aria-hidden="true" href="#cb17-9" tabindex="-1"></a> RequestHeader<span class="st"> unset X-Forwarded-Proto</span></span>
|
|
<span id="cb17-10"><a aria-hidden="true" href="#cb17-10" tabindex="-1"></a> <span class="fu"><If</span><span class="at"> "%{HTTPS} =~ /on/"</span><span class="fu">></span></span>
|
|
<span id="cb17-11"><a aria-hidden="true" href="#cb17-11" tabindex="-1"></a> RequestHeader<span class="st"> set X-Forwarded-Proto "https"</span></span>
|
|
<span id="cb17-12"><a aria-hidden="true" href="#cb17-12" tabindex="-1"></a> <span class="fu"></If></span></span>
|
|
<span id="cb17-13"><a aria-hidden="true" href="#cb17-13" tabindex="-1"></a><span class="fu"></Location></span></span></code></pre></div>
|
|
<p>Example <strong>Apache .htaccess</strong> configuration:</p>
|
|
<div class="sourceCode" id="cb18"><pre class="sourceCode apache"><code class="sourceCode apache"><span id="cb18-1"><a aria-hidden="true" href="#cb18-1" tabindex="-1"></a>DirectoryIndex<span class="st"> disabled</span></span>
|
|
<span id="cb18-2"><a aria-hidden="true" href="#cb18-2" tabindex="-1"></a><span class="ex">RewriteEngine</span><span class="ch"> </span><span class="kw">On</span></span>
|
|
<span id="cb18-3"><a aria-hidden="true" href="#cb18-3" tabindex="-1"></a>RewriteRule<span class="st"> ^(.*)$ http://localhost:5232/$1 [P,L]</span></span>
|
|
<span id="cb18-4"><a aria-hidden="true" href="#cb18-4" tabindex="-1"></a></span>
|
|
<span id="cb18-5"><a aria-hidden="true" href="#cb18-5" tabindex="-1"></a><span class="co"># Set to directory of .htaccess file:</span></span>
|
|
<span id="cb18-6"><a aria-hidden="true" href="#cb18-6" tabindex="-1"></a>RequestHeader<span class="st"> set X-Script-Name /radicale</span></span>
|
|
<span id="cb18-7"><a aria-hidden="true" href="#cb18-7" tabindex="-1"></a>RequestHeader<span class="st"> set X-Forwarded-Port "%{SERVER_PORT}s"</span></span>
|
|
<span id="cb18-8"><a aria-hidden="true" href="#cb18-8" tabindex="-1"></a>RequestHeader<span class="st"> unset X-Forwarded-Proto</span></span>
|
|
<span id="cb18-9"><a aria-hidden="true" href="#cb18-9" tabindex="-1"></a><span class="fu"><If</span><span class="at"> "%{HTTPS} =~ /on/"</span><span class="fu">></span></span>
|
|
<span id="cb18-10"><a aria-hidden="true" href="#cb18-10" tabindex="-1"></a>RequestHeader<span class="st"> set X-Forwarded-Proto "https"</span></span>
|
|
<span id="cb18-11"><a aria-hidden="true" href="#cb18-11" tabindex="-1"></a><span class="fu"></If></span></span></code></pre></div>
|
|
<p>Example <strong>lighttpd</strong> configuration:</p>
|
|
<pre class="lighttpd"><code>server.modules += ( "mod_proxy" , "mod_setenv", "mod_rewrite" )
|
|
|
|
$HTTP["url"] =~ "^/radicale/" {
|
|
proxy.server = ( "" => (( "host" => "127.0.0.1", "port" => "5232" )) )
|
|
proxy.header = ( "map-urlpath" => ( "/radicale/" => "/" ))
|
|
|
|
setenv.add-request-header = (
|
|
"X-Script-Name" => "/radicale",
|
|
"Script-Name" => "/radicale",
|
|
)
|
|
url.rewrite-once = ( "^/radicale/radicale/(.*)" => "/radicale/$1" )
|
|
}</code></pre>
|
|
<p>Be reminded that Radicale's default configuration enforces limits on
|
|
the maximum number of parallel connections, the maximum file size and
|
|
the rate of incorrect authentication attempts. Connections are
|
|
terminated after a timeout.</p>
|
|
<section class="level4" id="manage-user-accounts-with-the-reverse-proxy">
|
|
<h4>Manage user accounts with the reverse proxy <a class="headerlink" href="#manage-user-accounts-with-the-reverse-proxy">¶</a></h4>
|
|
<p>Set the configuration option <code>type</code> in the
|
|
<code>auth</code> section to <code>http_x_remote_user</code>. Radicale
|
|
uses the username provided in the <code>X-Remote-User</code> HTTP header
|
|
and disables HTTP authentication.</p>
|
|
<p>Example <strong>nginx</strong> configuration:</p>
|
|
<pre class="nginx"><code>location /radicale/ {
|
|
proxy_pass http://localhost:5232/;
|
|
proxy_set_header X-Script-Name /radicale;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Remote-User $remote_user;
|
|
proxy_set_header Host $http_host;
|
|
auth_basic "Radicale - Password Required";
|
|
auth_basic_user_file /etc/nginx/htpasswd;
|
|
}</code></pre>
|
|
<p>Example <strong>Apache</strong> configuration:</p>
|
|
<div class="sourceCode" id="cb21"><pre class="sourceCode apache"><code class="sourceCode apache"><span id="cb21-1"><a aria-hidden="true" href="#cb21-1" tabindex="-1"></a><span class="ex">RewriteEngine</span><span class="ch"> </span><span class="kw">On</span></span>
|
|
<span id="cb21-2"><a aria-hidden="true" href="#cb21-2" tabindex="-1"></a>RewriteRule<span class="st"> ^/radicale$ /radicale/ [R,L]</span></span>
|
|
<span id="cb21-3"><a aria-hidden="true" href="#cb21-3" tabindex="-1"></a></span>
|
|
<span id="cb21-4"><a aria-hidden="true" href="#cb21-4" tabindex="-1"></a><span class="fu"><Location</span><span class="at"> "/radicale/"</span><span class="fu">></span></span>
|
|
<span id="cb21-5"><a aria-hidden="true" href="#cb21-5" tabindex="-1"></a> <span class="ex">AuthType</span><span class="ch"> </span><span class="kw">Basic</span></span>
|
|
<span id="cb21-6"><a aria-hidden="true" href="#cb21-6" tabindex="-1"></a> AuthName<span class="st"> "Radicale - Password Required"</span></span>
|
|
<span id="cb21-7"><a aria-hidden="true" href="#cb21-7" tabindex="-1"></a> AuthUserFile<span class="st"> "/etc/radicale/htpasswd"</span></span>
|
|
<span id="cb21-8"><a aria-hidden="true" href="#cb21-8" tabindex="-1"></a> Require<span class="st"> valid-user</span></span>
|
|
<span id="cb21-9"><a aria-hidden="true" href="#cb21-9" tabindex="-1"></a></span>
|
|
<span id="cb21-10"><a aria-hidden="true" href="#cb21-10" tabindex="-1"></a> ProxyPass<span class="st"> http://localhost:5232/ retry=0</span></span>
|
|
<span id="cb21-11"><a aria-hidden="true" href="#cb21-11" tabindex="-1"></a> ProxyPassReverse<span class="st"> http://localhost:5232/</span></span>
|
|
<span id="cb21-12"><a aria-hidden="true" href="#cb21-12" tabindex="-1"></a> RequestHeader<span class="st"> set X-Script-Name /radicale</span></span>
|
|
<span id="cb21-13"><a aria-hidden="true" href="#cb21-13" tabindex="-1"></a> RequestHeader<span class="st"> set X-Remote-User expr=%{REMOTE_USER}</span></span>
|
|
<span id="cb21-14"><a aria-hidden="true" href="#cb21-14" tabindex="-1"></a><span class="fu"></Location></span></span></code></pre></div>
|
|
<p>Example <strong>Apache .htaccess</strong> configuration:</p>
|
|
<div class="sourceCode" id="cb22"><pre class="sourceCode apache"><code class="sourceCode apache"><span id="cb22-1"><a aria-hidden="true" href="#cb22-1" tabindex="-1"></a>DirectoryIndex<span class="st"> disabled</span></span>
|
|
<span id="cb22-2"><a aria-hidden="true" href="#cb22-2" tabindex="-1"></a><span class="ex">RewriteEngine</span><span class="ch"> </span><span class="kw">On</span></span>
|
|
<span id="cb22-3"><a aria-hidden="true" href="#cb22-3" tabindex="-1"></a>RewriteRule<span class="st"> ^(.*)$ http://localhost:5232/$1 [P,L]</span></span>
|
|
<span id="cb22-4"><a aria-hidden="true" href="#cb22-4" tabindex="-1"></a></span>
|
|
<span id="cb22-5"><a aria-hidden="true" href="#cb22-5" tabindex="-1"></a><span class="ex">AuthType</span><span class="ch"> </span><span class="kw">Basic</span></span>
|
|
<span id="cb22-6"><a aria-hidden="true" href="#cb22-6" tabindex="-1"></a>AuthName<span class="st"> "Radicale - Password Required"</span></span>
|
|
<span id="cb22-7"><a aria-hidden="true" href="#cb22-7" tabindex="-1"></a>AuthUserFile<span class="st"> "/etc/radicale/htpasswd"</span></span>
|
|
<span id="cb22-8"><a aria-hidden="true" href="#cb22-8" tabindex="-1"></a>Require<span class="st"> valid-user</span></span>
|
|
<span id="cb22-9"><a aria-hidden="true" href="#cb22-9" tabindex="-1"></a></span>
|
|
<span id="cb22-10"><a aria-hidden="true" href="#cb22-10" tabindex="-1"></a><span class="co"># Set to directory of .htaccess file:</span></span>
|
|
<span id="cb22-11"><a aria-hidden="true" href="#cb22-11" tabindex="-1"></a>RequestHeader<span class="st"> set X-Script-Name /radicale</span></span>
|
|
<span id="cb22-12"><a aria-hidden="true" href="#cb22-12" tabindex="-1"></a>RequestHeader<span class="st"> set X-Remote-User expr=%{REMOTE_USER}</span></span></code></pre></div>
|
|
<blockquote>
|
|
<p><strong>Security:</strong> Untrusted clients should not be able to
|
|
access the Radicale server directly. Otherwise, they can authenticate as
|
|
any user.</p>
|
|
</blockquote>
|
|
</section>
|
|
<section class="level4" id="secure-connection-between-radicale-and-the-reverse-proxy">
|
|
<h4>Secure connection between Radicale and the reverse proxy <a class="headerlink" href="#secure-connection-between-radicale-and-the-reverse-proxy">¶</a></h4>
|
|
<p>SSL certificates can be used to encrypt and authenticate the
|
|
connection between Radicale and the reverse proxy. First you have to
|
|
generate a certificate for Radicale and a certificate for the reverse
|
|
proxy. The following commands generate self-signed certificates. You
|
|
will be asked to enter additional information about the certificate, the
|
|
values don't matter and you can keep the defaults.</p>
|
|
<div class="sourceCode" id="cb23"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb23-1"><a aria-hidden="true" href="#cb23-1" tabindex="-1"></a><span class="ex">openssl</span> req <span class="at">-x509</span> <span class="at">-newkey</span> rsa:4096 <span class="at">-keyout</span> server_key.pem <span class="at">-out</span> server_cert.pem <span class="dt">\</span></span>
|
|
<span id="cb23-2"><a aria-hidden="true" href="#cb23-2" tabindex="-1"></a> <span class="at">-nodes</span> <span class="at">-days</span> 9999</span>
|
|
<span id="cb23-3"><a aria-hidden="true" href="#cb23-3" tabindex="-1"></a><span class="ex">openssl</span> req <span class="at">-x509</span> <span class="at">-newkey</span> rsa:4096 <span class="at">-keyout</span> client_key.pem <span class="at">-out</span> client_cert.pem <span class="dt">\</span></span>
|
|
<span id="cb23-4"><a aria-hidden="true" href="#cb23-4" tabindex="-1"></a> <span class="at">-nodes</span> <span class="at">-days</span> 9999</span></code></pre></div>
|
|
<p>Use the following configuration for Radicale:</p>
|
|
<div class="sourceCode" id="cb24"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb24-1"><a aria-hidden="true" href="#cb24-1" tabindex="-1"></a><span class="kw">[server]</span></span>
|
|
<span id="cb24-2"><a aria-hidden="true" href="#cb24-2" tabindex="-1"></a><span class="dt">ssl </span><span class="ot">=</span><span class="st"> </span><span class="kw">True</span></span>
|
|
<span id="cb24-3"><a aria-hidden="true" href="#cb24-3" tabindex="-1"></a><span class="dt">certificate </span><span class="ot">=</span><span class="st"> /path/to/server_cert.pem</span></span>
|
|
<span id="cb24-4"><a aria-hidden="true" href="#cb24-4" tabindex="-1"></a><span class="dt">key </span><span class="ot">=</span><span class="st"> /path/to/server_key.pem</span></span>
|
|
<span id="cb24-5"><a aria-hidden="true" href="#cb24-5" tabindex="-1"></a><span class="dt">certificate_authority </span><span class="ot">=</span><span class="st"> /path/to/client_cert.pem</span></span></code></pre></div>
|
|
<p>If you're using the Let's Encrypt's Certbot, the configuration should
|
|
look similar to this:</p>
|
|
<div class="sourceCode" id="cb25"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb25-1"><a aria-hidden="true" href="#cb25-1" tabindex="-1"></a><span class="kw">[server]</span></span>
|
|
<span id="cb25-2"><a aria-hidden="true" href="#cb25-2" tabindex="-1"></a><span class="dt">ssl </span><span class="ot">=</span><span class="st"> </span><span class="kw">True</span></span>
|
|
<span id="cb25-3"><a aria-hidden="true" href="#cb25-3" tabindex="-1"></a><span class="dt">certificate </span><span class="ot">=</span><span class="st"> /etc/letsencrypt/live/{Your Domain}/fullchain.pem</span></span>
|
|
<span id="cb25-4"><a aria-hidden="true" href="#cb25-4" tabindex="-1"></a><span class="dt">key </span><span class="ot">=</span><span class="st"> /etc/letsencrypt/live/{Your Domain}/privkey.pem</span></span></code></pre></div>
|
|
<p>Example <strong>nginx</strong> configuration:</p>
|
|
<pre class="nginx"><code>location /radicale/ {
|
|
proxy_pass https://localhost:5232/;
|
|
...
|
|
# Place the files somewhere nginx is allowed to access (e.g. /etc/nginx/...).
|
|
proxy_ssl_certificate /path/to/client_cert.pem;
|
|
proxy_ssl_certificate_key /path/to/client_key.pem;
|
|
proxy_ssl_trusted_certificate /path/to/server_cert.pem;
|
|
}</code></pre>
|
|
</section>
|
|
</section>
|
|
<section class="level3" id="wsgi-server">
|
|
<h3>WSGI Server <a class="headerlink" href="#wsgi-server">¶</a></h3>
|
|
<p>Radicale is compatible with the WSGI specification.</p>
|
|
<p>A configuration file can be set with the <code>RADICALE_CONFIG</code>
|
|
environment variable, otherwise no configuration file is loaded and the
|
|
default configuration is used.</p>
|
|
<p>Example <strong>uWSGI</strong> configuration:</p>
|
|
<div class="sourceCode" id="cb27"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb27-1"><a aria-hidden="true" href="#cb27-1" tabindex="-1"></a><span class="kw">[uwsgi]</span></span>
|
|
<span id="cb27-2"><a aria-hidden="true" href="#cb27-2" tabindex="-1"></a><span class="dt">http-socket </span><span class="ot">=</span><span class="st"> 127.0.0.1:5232</span></span>
|
|
<span id="cb27-3"><a aria-hidden="true" href="#cb27-3" tabindex="-1"></a><span class="dt">processes </span><span class="ot">=</span><span class="st"> </span><span class="dv">8</span></span>
|
|
<span id="cb27-4"><a aria-hidden="true" href="#cb27-4" tabindex="-1"></a><span class="dt">plugin </span><span class="ot">=</span><span class="st"> python3</span></span>
|
|
<span id="cb27-5"><a aria-hidden="true" href="#cb27-5" tabindex="-1"></a><span class="dt">module </span><span class="ot">=</span><span class="st"> radicale</span></span>
|
|
<span id="cb27-6"><a aria-hidden="true" href="#cb27-6" tabindex="-1"></a><span class="dt">env </span><span class="ot">=</span><span class="st"> RADICALE_CONFIG=/etc/radicale/config</span></span></code></pre></div>
|
|
<p>Example <strong>Gunicorn</strong> configuration:</p>
|
|
<div class="sourceCode" id="cb28"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb28-1"><a aria-hidden="true" href="#cb28-1" tabindex="-1"></a><span class="ex">gunicorn</span> <span class="at">--bind</span> <span class="st">'127.0.0.1:5232'</span> <span class="at">--env</span> <span class="st">'RADICALE_CONFIG=/etc/radicale/config'</span> <span class="dt">\</span></span>
|
|
<span id="cb28-2"><a aria-hidden="true" href="#cb28-2" tabindex="-1"></a> <span class="at">--workers</span> 8 radicale</span></code></pre></div>
|
|
<section class="level4" id="manage-user-accounts-with-the-wsgi-server">
|
|
<h4>Manage user accounts with the WSGI server <a class="headerlink" href="#manage-user-accounts-with-the-wsgi-server">¶</a></h4>
|
|
<p>Set the configuration option <code>type</code> in the
|
|
<code>auth</code> section to <code>remote_user</code>. Radicale uses the
|
|
username provided by the WSGI server and disables authentication over
|
|
HTTP.</p>
|
|
</section>
|
|
</section>
|
|
<section class="level3" id="versioning-with-git">
|
|
<h3>Versioning with Git <a class="headerlink" href="#versioning-with-git">¶</a></h3>
|
|
<p>This tutorial describes how to keep track of all changes to calendars
|
|
and address books with <strong>git</strong> (or any other version
|
|
control system).</p>
|
|
<p>The repository must be initialized by running <code>git init</code>
|
|
in the file system folder. Internal files of Radicale can be excluded by
|
|
creating the file <code>.gitignore</code> with the following
|
|
content:</p>
|
|
<pre class="gitignore"><code>.Radicale.cache
|
|
.Radicale.lock
|
|
.Radicale.tmp-*</code></pre>
|
|
<p>The configuration option <code>hook</code> in the
|
|
<code>storage</code> section must be set to the following command:</p>
|
|
<div class="sourceCode" id="cb30"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb30-1"><a aria-hidden="true" href="#cb30-1" tabindex="-1"></a><span class="fu">git</span> add <span class="at">-A</span> <span class="kw">&&</span> <span class="kw">(</span><span class="fu">git</span> diff <span class="at">--cached</span> <span class="at">--quiet</span> <span class="kw">||</span> <span class="fu">git</span> commit <span class="at">-m</span> <span class="st">"Changes by "</span>%<span class="er">(</span><span class="ex">user</span><span class="kw">)</span><span class="ex">s</span><span class="kw">)</span></span></code></pre></div>
|
|
<p>The command gets executed after every change to the storage and
|
|
commits the changes into the <strong>git</strong> repository.</p>
|
|
<p>For the hook to not cause errors either <strong>git</strong> user
|
|
details need to be set and match the owner of the collections directory
|
|
or the repository needs to be marked as safe.</p>
|
|
<p>When using the systemd unit file from the <a href="#running-as-a-service">Running as a service</a> section this
|
|
<strong>cannot</strong> be done via a <code>.gitconfig</code> file in
|
|
the users home directory, as Radicale won't have read permissions!</p>
|
|
<p>In <code>/var/lib/radicale/collections/.git</code> run:</p>
|
|
<div class="sourceCode" id="cb31"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb31-1"><a aria-hidden="true" href="#cb31-1" tabindex="-1"></a><span class="fu">git</span> config user.name <span class="st">"radicale"</span></span>
|
|
<span id="cb31-2"><a aria-hidden="true" href="#cb31-2" tabindex="-1"></a><span class="fu">git</span> config user.email <span class="st">"radicale@example.com"</span></span></code></pre></div>
|
|
</section>
|
|
</section>
|
|
<section class="level2" id="documentation-1">
|
|
<h2>Documentation <a class="headerlink" href="#documentation-1">¶</a></h2>
|
|
<section class="level3" id="configuration">
|
|
<h3>Configuration <a class="headerlink" href="#configuration">¶</a></h3>
|
|
<p>Radicale can be configured with a configuration file or with command
|
|
line arguments.</p>
|
|
<p>An example configuration file looks like:</p>
|
|
<div class="sourceCode" id="cb32"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb32-1"><a aria-hidden="true" href="#cb32-1" tabindex="-1"></a><span class="kw">[server]</span></span>
|
|
<span id="cb32-2"><a aria-hidden="true" href="#cb32-2" tabindex="-1"></a><span class="co"># Bind all addresses</span></span>
|
|
<span id="cb32-3"><a aria-hidden="true" href="#cb32-3" tabindex="-1"></a><span class="dt">hosts </span><span class="ot">=</span><span class="st"> 0.0.0.0:5232, [::]:5232</span></span>
|
|
<span id="cb32-4"><a aria-hidden="true" href="#cb32-4" tabindex="-1"></a></span>
|
|
<span id="cb32-5"><a aria-hidden="true" href="#cb32-5" tabindex="-1"></a><span class="kw">[auth]</span></span>
|
|
<span id="cb32-6"><a aria-hidden="true" href="#cb32-6" tabindex="-1"></a><span class="dt">type </span><span class="ot">=</span><span class="st"> htpasswd</span></span>
|
|
<span id="cb32-7"><a aria-hidden="true" href="#cb32-7" tabindex="-1"></a><span class="dt">htpasswd_filename </span><span class="ot">=</span><span class="st"> ~/.config/radicale/users</span></span>
|
|
<span id="cb32-8"><a aria-hidden="true" href="#cb32-8" tabindex="-1"></a><span class="dt">htpasswd_encryption </span><span class="ot">=</span><span class="st"> md5</span></span>
|
|
<span id="cb32-9"><a aria-hidden="true" href="#cb32-9" tabindex="-1"></a></span>
|
|
<span id="cb32-10"><a aria-hidden="true" href="#cb32-10" tabindex="-1"></a><span class="kw">[storage]</span></span>
|
|
<span id="cb32-11"><a aria-hidden="true" href="#cb32-11" tabindex="-1"></a><span class="dt">filesystem_folder </span><span class="ot">=</span><span class="st"> ~/.var/lib/radicale/collections</span></span></code></pre></div>
|
|
<p>Radicale tries to load configuration files from
|
|
<code>/etc/radicale/config</code> and
|
|
<code>~/.config/radicale/config</code>. Custom paths can be specified
|
|
with the <code>--config /path/to/config</code> command line argument or
|
|
the <code>RADICALE_CONFIG</code> environment variable. Multiple
|
|
configuration files can be separated by <code>:</code> (resp.
|
|
<code>;</code> on Windows). Paths that start with <code>?</code> are
|
|
optional.</p>
|
|
<p>The same example configuration via command line arguments looks
|
|
like:</p>
|
|
<div class="sourceCode" id="cb33"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb33-1"><a aria-hidden="true" href="#cb33-1" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> radicale <span class="at">--server-hosts</span> 0.0.0.0:5232,[::]:5232 <span class="dt">\</span></span>
|
|
<span id="cb33-2"><a aria-hidden="true" href="#cb33-2" tabindex="-1"></a> <span class="at">--auth-type</span> htpasswd <span class="at">--auth-htpasswd-filename</span> ~/.config/radicale/users <span class="dt">\</span></span>
|
|
<span id="cb33-3"><a aria-hidden="true" href="#cb33-3" tabindex="-1"></a> <span class="at">--auth-htpasswd-encryption</span> md5</span></code></pre></div>
|
|
<p>Add the argument <code>--config ""</code> to stop Radicale from
|
|
loading the default configuration files. Run
|
|
<code>python3 -m radicale --help</code> for more information.</p>
|
|
<p>In the following, all configuration categories and options are
|
|
described.</p>
|
|
<section class="level4" id="server">
|
|
<h4>server <a class="headerlink" href="#server">¶</a></h4>
|
|
<p>The configuration options in this category are only relevant in
|
|
standalone mode. All options are ignored, when Radicale runs via
|
|
WSGI.</p>
|
|
<section class="level5" id="hosts">
|
|
<h5>hosts <a class="headerlink" href="#hosts">¶</a></h5>
|
|
<p>A comma separated list of addresses that the server will bind to.</p>
|
|
<p>Default: <code>localhost:5232</code></p>
|
|
</section>
|
|
<section class="level5" id="max_connections">
|
|
<h5>max_connections <a class="headerlink" href="#max_connections">¶</a></h5>
|
|
<p>The maximum number of parallel connections. Set to <code>0</code> to
|
|
disable the limit.</p>
|
|
<p>Default: <code>8</code></p>
|
|
</section>
|
|
<section class="level5" id="max_content_length">
|
|
<h5>max_content_length <a class="headerlink" href="#max_content_length">¶</a></h5>
|
|
<p>The maximum size of the request body. (bytes)</p>
|
|
<p>Default: <code>100000000</code></p>
|
|
</section>
|
|
<section class="level5" id="timeout">
|
|
<h5>timeout <a class="headerlink" href="#timeout">¶</a></h5>
|
|
<p>Socket timeout. (seconds)</p>
|
|
<p>Default: <code>30</code></p>
|
|
</section>
|
|
<section class="level5" id="ssl">
|
|
<h5>ssl <a class="headerlink" href="#ssl">¶</a></h5>
|
|
<p>Enable transport layer encryption.</p>
|
|
<p>Default: <code>False</code></p>
|
|
</section>
|
|
<section class="level5" id="certificate">
|
|
<h5>certificate <a class="headerlink" href="#certificate">¶</a></h5>
|
|
<p>Path of the SSL certifcate.</p>
|
|
<p>Default: <code>/etc/ssl/radicale.cert.pem</code></p>
|
|
</section>
|
|
<section class="level5" id="key">
|
|
<h5>key <a class="headerlink" href="#key">¶</a></h5>
|
|
<p>Path to the private key for SSL. Only effective if <code>ssl</code>
|
|
is enabled.</p>
|
|
<p>Default: <code>/etc/ssl/radicale.key.pem</code></p>
|
|
</section>
|
|
<section class="level5" id="certificate_authority">
|
|
<h5>certificate_authority <a class="headerlink" href="#certificate_authority">¶</a></h5>
|
|
<p>Path to the CA certificate for validating client certificates. This
|
|
can be used to secure TCP traffic between Radicale and a reverse proxy.
|
|
If you want to authenticate users with client-side certificates, you
|
|
also have to write an authentication plugin that extracts the username
|
|
from the certificate.</p>
|
|
<p>Default:</p>
|
|
</section>
|
|
</section>
|
|
<section class="level4" id="encoding">
|
|
<h4>encoding <a class="headerlink" href="#encoding">¶</a></h4>
|
|
<section class="level5" id="request">
|
|
<h5>request <a class="headerlink" href="#request">¶</a></h5>
|
|
<p>Encoding for responding requests.</p>
|
|
<p>Default: <code>utf-8</code></p>
|
|
</section>
|
|
<section class="level5" id="stock">
|
|
<h5>stock <a class="headerlink" href="#stock">¶</a></h5>
|
|
<p>Encoding for storing local collections</p>
|
|
<p>Default: <code>utf-8</code></p>
|
|
</section>
|
|
</section>
|
|
<section class="level4" id="auth">
|
|
<h4>auth <a class="headerlink" href="#auth">¶</a></h4>
|
|
<section class="level5" id="type">
|
|
<h5>type <a class="headerlink" href="#type">¶</a></h5>
|
|
<p>The method to verify usernames and passwords.</p>
|
|
<p>Available backends:</p>
|
|
<p><code>none</code> : Just allows all usernames and passwords.</p>
|
|
<p><code>htpasswd</code> : Use an <a href="https://httpd.apache.org/docs/current/programs/htpasswd.html">Apache
|
|
htpasswd file</a> to store usernames and passwords.</p>
|
|
<p><code>remote_user</code> : Takes the username from the
|
|
<code>REMOTE_USER</code> environment variable and disables HTTP
|
|
authentication. This can be used to provide the username from a WSGI
|
|
server.</p>
|
|
<p><code>http_x_remote_user</code> : Takes the username from the
|
|
<code>X-Remote-User</code> HTTP header and disables HTTP authentication.
|
|
This can be used to provide the username from a reverse proxy.</p>
|
|
<p>Default: <code>none</code></p>
|
|
</section>
|
|
<section class="level5" id="htpasswd_filename">
|
|
<h5>htpasswd_filename <a class="headerlink" href="#htpasswd_filename">¶</a></h5>
|
|
<p>Path to the htpasswd file.</p>
|
|
<p>Default: <code>/etc/radicale/users</code></p>
|
|
</section>
|
|
<section class="level5" id="htpasswd_encryption">
|
|
<h5>htpasswd_encryption <a class="headerlink" href="#htpasswd_encryption">¶</a></h5>
|
|
<p>The encryption method that is used in the htpasswd file. Use the <a href="https://httpd.apache.org/docs/current/programs/htpasswd.html">htpasswd</a>
|
|
or similar to generate this files.</p>
|
|
<p>Available methods:</p>
|
|
<p><code>plain</code> : Passwords are stored in plaintext. This is
|
|
obviously not secure! The htpasswd file for this can be created by hand
|
|
and looks like:</p>
|
|
<pre class="htpasswd"><code>user1:password1
|
|
user2:password2</code></pre>
|
|
<p><code>bcrypt</code> : This uses a modified version of the Blowfish
|
|
stream cipher. It's very secure. The installation of
|
|
<strong>bcrypt</strong> is required for this.</p>
|
|
<p><code>md5</code> : This uses an iterated md5 digest of the password
|
|
with a salt.</p>
|
|
<p>Default: <code>md5</code></p>
|
|
</section>
|
|
<section class="level5" id="delay">
|
|
<h5>delay <a class="headerlink" href="#delay">¶</a></h5>
|
|
<p>Average delay after failed login attempts in seconds.</p>
|
|
<p>Default: <code>1</code></p>
|
|
</section>
|
|
<section class="level5" id="realm">
|
|
<h5>realm <a class="headerlink" href="#realm">¶</a></h5>
|
|
<p>Message displayed in the client when a password is needed.</p>
|
|
<p>Default: <code>Radicale - Password Required</code></p>
|
|
</section>
|
|
</section>
|
|
<section class="level4" id="rights">
|
|
<h4>rights <a class="headerlink" href="#rights">¶</a></h4>
|
|
<section class="level5" id="type-1">
|
|
<h5>type <a class="headerlink" href="#type-1">¶</a></h5>
|
|
<p>The backend that is used to check the access rights of
|
|
collections.</p>
|
|
<p>The recommended backend is <code>owner_only</code>. If access to
|
|
calendars and address books outside the home directory of users (that's
|
|
<code>/USERNAME/</code>) 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.</p>
|
|
<p>Available backends:</p>
|
|
<p><code>authenticated</code> : Authenticated users can read and write
|
|
everything.</p>
|
|
<p><code>owner_only</code> : Authenticated users can read and write
|
|
their own collections under the path <em>/USERNAME/</em>.</p>
|
|
<p><code>owner_write</code> : Authenticated users can read everything
|
|
and write their own collections under the path <em>/USERNAME/</em>.</p>
|
|
<p><code>from_file</code> : Load the rules from a file.</p>
|
|
<p>Default: <code>owner_only</code></p>
|
|
</section>
|
|
<section class="level5" id="file">
|
|
<h5>file <a class="headerlink" href="#file">¶</a></h5>
|
|
<p>File for the rights backend <code>from_file</code>. See the <a href="#authentication-and-rights">Rights</a> section.</p>
|
|
</section>
|
|
<section class="level5" id="permit_delete_collection">
|
|
<h5>permit_delete_collection <a class="headerlink" href="#permit_delete_collection">¶</a></h5>
|
|
<p>(New since 3.1.9)</p>
|
|
<p>Global control of permission to delete complete collection (default:
|
|
True)</p>
|
|
</section>
|
|
</section>
|
|
<section class="level4" id="storage-1">
|
|
<h4>storage <a class="headerlink" href="#storage-1">¶</a></h4>
|
|
<section class="level5" id="type-2">
|
|
<h5>type <a class="headerlink" href="#type-2">¶</a></h5>
|
|
<p>The backend that is used to store data.</p>
|
|
<p>Available backends:</p>
|
|
<p><code>multifilesystem</code> : Stores the data in the filesystem.</p>
|
|
<p><code>multifilesystem_nolock</code> : The
|
|
<code>multifilesystem</code> backend without file-based locking. Must
|
|
only be used with a single process.</p>
|
|
<p>Default: <code>multifilesystem</code></p>
|
|
</section>
|
|
<section class="level5" id="filesystem_folder">
|
|
<h5>filesystem_folder <a class="headerlink" href="#filesystem_folder">¶</a></h5>
|
|
<p>Folder for storing local collections, created if not present.</p>
|
|
<p>Default: <code>/var/lib/radicale/collections</code></p>
|
|
</section>
|
|
<section class="level5" id="max_sync_token_age">
|
|
<h5>max_sync_token_age <a class="headerlink" href="#max_sync_token_age">¶</a></h5>
|
|
<p>Delete sync-token that are older than the specified time.
|
|
(seconds)</p>
|
|
<p>Default: <code>2592000</code></p>
|
|
</section>
|
|
<section class="level5" id="hook">
|
|
<h5>hook <a class="headerlink" href="#hook">¶</a></h5>
|
|
<p>Command that is run after changes to storage. Take a look at the <a href="#versioning-with-git">Versioning with Git</a> tutorial for an
|
|
example.</p>
|
|
<p>Default:</p>
|
|
</section>
|
|
</section>
|
|
<section class="level4" id="web">
|
|
<h4>web <a class="headerlink" href="#web">¶</a></h4>
|
|
<section class="level5" id="type-3">
|
|
<h5>type <a class="headerlink" href="#type-3">¶</a></h5>
|
|
<p>The backend that provides the web interface of Radicale.</p>
|
|
<p>Available backends:</p>
|
|
<p><code>none</code> : Just shows the message "Radicale works!".</p>
|
|
<p><code>internal</code> : Allows creation and management of address
|
|
books and calendars.</p>
|
|
<p>Default: <code>internal</code></p>
|
|
</section>
|
|
</section>
|
|
<section class="level4" id="logging">
|
|
<h4>logging <a class="headerlink" href="#logging">¶</a></h4>
|
|
<section class="level5" id="level">
|
|
<h5>level <a class="headerlink" href="#level">¶</a></h5>
|
|
<p>Set the logging level.</p>
|
|
<p>Available levels: <strong>debug</strong>, <strong>info</strong>,
|
|
<strong>warning</strong>, <strong>error</strong>,
|
|
<strong>critical</strong></p>
|
|
<p>Default: <code>warning</code></p>
|
|
</section>
|
|
<section class="level5" id="mask_passwords">
|
|
<h5>mask_passwords <a class="headerlink" href="#mask_passwords">¶</a></h5>
|
|
<p>Don't include passwords in logs.</p>
|
|
<p>Default: <code>True</code></p>
|
|
</section>
|
|
</section>
|
|
<section class="level4" id="headers">
|
|
<h4>headers <a class="headerlink" href="#headers">¶</a></h4>
|
|
<p>In this section additional HTTP headers that are sent to clients can
|
|
be specified.</p>
|
|
<p>An example to relax the same-origin policy:</p>
|
|
<div class="sourceCode" id="cb35"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb35-1"><a aria-hidden="true" href="#cb35-1" tabindex="-1"></a><span class="dt">Access-Control-Allow-Origin </span><span class="ot">=</span><span class="st"> *</span></span></code></pre></div>
|
|
</section>
|
|
</section>
|
|
<section class="level3" id="supported-clients">
|
|
<h3>Supported Clients <a class="headerlink" href="#supported-clients">¶</a></h3>
|
|
<p>Radicale has been tested with:</p>
|
|
<ul>
|
|
<li><a href="https://android.com/">Android</a> with <a href="https://www.davx5.com/">DAVx⁵</a> (formerly DAVdroid)</li>
|
|
<li><a href="https://wiki.gnome.org/Apps/Calendar">GNOME Calendar</a>,
|
|
<a href="https://wiki.gnome.org/Apps/Contacts">Contacts</a> and <a href="https://wiki.gnome.org/Apps/Evolution">Evolution</a></li>
|
|
<li><a href="https://www.mozilla.org/thunderbird/">Mozilla
|
|
Thunderbird</a> with <a href="https://addons.mozilla.org/thunderbird/addon/cardbook/">CardBook</a>
|
|
and <a href="https://www.mozilla.org/projects/calendar/">Lightning</a></li>
|
|
<li><a href="https://www.inf-it.com/open-source/clients/infcloud/">InfCloud</a>,
|
|
<a href="https://www.inf-it.com/open-source/clients/caldavzap/">CalDavZAP</a>
|
|
and <a href="https://www.inf-it.com/open-source/clients/carddavmate/">CardDavMATE</a></li>
|
|
</ul>
|
|
<p>Many clients do not support the creation of new calendars and address
|
|
books. You can use Radicale's web interface (e.g. <a href="http://localhost:5232">http://localhost:5232</a>) to create and
|
|
manage address books and calendars.</p>
|
|
<p>In some clients you can just enter the URL of the Radicale server
|
|
(e.g. <code>http://localhost:5232</code>) and your username. In others,
|
|
you have to enter the URL of the collection directly (e.g.
|
|
<code>http://localhost:5232/user/calendar</code>).</p>
|
|
<section class="level4" id="davx⁵">
|
|
<h4>DAVx⁵ <a class="headerlink" href="#davx⁵">¶</a></h4>
|
|
<p>Enter the URL of the Radicale server (e.g.
|
|
<code>http://localhost:5232</code>) and your username. DAVx⁵ will show
|
|
all existing calendars and address books and you can create new.</p>
|
|
</section>
|
|
<section class="level4" id="gnome-calendar-contacts-and-evolution">
|
|
<h4>GNOME Calendar, Contacts and Evolution <a class="headerlink" href="#gnome-calendar-contacts-and-evolution">¶</a></h4>
|
|
<p><strong>GNOME Calendar</strong> and <strong>Contacts</strong> do not
|
|
support adding WebDAV calendars and address books directly, but you can
|
|
add them in <strong>Evolution</strong>.</p>
|
|
<p>In <strong>Evolution</strong> add a new calendar and address book
|
|
respectively with WebDAV. Enter the URL of the Radicale server (e.g.
|
|
<code>http://localhost:5232</code>) and your username. Clicking on the
|
|
search button will list the existing calendars and address books.</p>
|
|
</section>
|
|
<section class="level4" id="thunderbird">
|
|
<h4>Thunderbird <a class="headerlink" href="#thunderbird">¶</a></h4>
|
|
<p>Add a new calendar on the network. Enter your username and the URL of
|
|
the Radicale server (e.g. <code>http://localhost:5232</code>). After
|
|
asking for your password, it will list the existing calendars.</p>
|
|
<section class="level5" id="adress-books-with-cardbook-add-on">
|
|
<h5>Adress books with CardBook add-on <a class="headerlink" href="#adress-books-with-cardbook-add-on">¶</a></h5>
|
|
<p>Add a new address book on the network with CardDAV. Enter the URL of
|
|
the Radicale server (e.g. <code>http://localhost:5232</code>) and your
|
|
username and password. It will list your existing address books.</p>
|
|
</section>
|
|
</section>
|
|
<section class="level4" id="infcloud-caldavzap-and-carddavmate">
|
|
<h4>InfCloud, CalDavZAP and CardDavMATE <a class="headerlink" href="#infcloud-caldavzap-and-carddavmate">¶</a></h4>
|
|
<p>You can integrate InfCloud into Radicale's web interface with <a href="https://github.com/Unrud/RadicaleInfCloud">RadicaleInfCloud</a>.
|
|
No additional configuration is required.</p>
|
|
<p>Set the URL of the Radicale server in <code>config.js</code>. If
|
|
<strong>InfCloud</strong> is not hosted on the same server and port as
|
|
Radicale, the browser will deny access to the Radicale server, because
|
|
of the <a href="https://en.wikipedia.org/wiki/Same-origin_policy">same-origin
|
|
policy</a>. You have to add additional HTTP header in the
|
|
<code>headers</code> section of Radicale's configuration. The
|
|
documentation of <strong>InfCloud</strong> has more details on this.</p>
|
|
</section>
|
|
<section class="level4" id="command-line">
|
|
<h4>Command line <a class="headerlink" href="#command-line">¶</a></h4>
|
|
<p>This is not the recommended way of creating and managing your
|
|
calendars and address books. Use Radicale's web interface or a client
|
|
with support for it (e.g. <strong>DAVx⁵</strong>).</p>
|
|
<p>To create a new calendar run something like:</p>
|
|
<div class="sourceCode" id="cb36"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb36-1"><a aria-hidden="true" href="#cb36-1" tabindex="-1"></a><span class="ex">$</span> curl <span class="at">-u</span> user <span class="at">-X</span> MKCOL <span class="st">'http://localhost:5232/user/calendar'</span> <span class="at">--data</span> <span class="dt">\</span></span>
|
|
<span id="cb36-2"><a aria-hidden="true" href="#cb36-2" tabindex="-1"></a><span class="st">'<?xml version="1.0" encoding="UTF-8" ?></span></span>
|
|
<span id="cb36-3"><a aria-hidden="true" href="#cb36-3" tabindex="-1"></a><span class="st"><create xmlns="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:I="http://apple.com/ns/ical/"></span></span>
|
|
<span id="cb36-4"><a aria-hidden="true" href="#cb36-4" tabindex="-1"></a><span class="st"> <set></span></span>
|
|
<span id="cb36-5"><a aria-hidden="true" href="#cb36-5" tabindex="-1"></a><span class="st"> <prop></span></span>
|
|
<span id="cb36-6"><a aria-hidden="true" href="#cb36-6" tabindex="-1"></a><span class="st"> <resourcetype></span></span>
|
|
<span id="cb36-7"><a aria-hidden="true" href="#cb36-7" tabindex="-1"></a><span class="st"> <collection /></span></span>
|
|
<span id="cb36-8"><a aria-hidden="true" href="#cb36-8" tabindex="-1"></a><span class="st"> <C:calendar /></span></span>
|
|
<span id="cb36-9"><a aria-hidden="true" href="#cb36-9" tabindex="-1"></a><span class="st"> </resourcetype></span></span>
|
|
<span id="cb36-10"><a aria-hidden="true" href="#cb36-10" tabindex="-1"></a><span class="st"> <C:supported-calendar-component-set></span></span>
|
|
<span id="cb36-11"><a aria-hidden="true" href="#cb36-11" tabindex="-1"></a><span class="st"> <C:comp name="VEVENT" /></span></span>
|
|
<span id="cb36-12"><a aria-hidden="true" href="#cb36-12" tabindex="-1"></a><span class="st"> <C:comp name="VJOURNAL" /></span></span>
|
|
<span id="cb36-13"><a aria-hidden="true" href="#cb36-13" tabindex="-1"></a><span class="st"> <C:comp name="VTODO" /></span></span>
|
|
<span id="cb36-14"><a aria-hidden="true" href="#cb36-14" tabindex="-1"></a><span class="st"> </C:supported-calendar-component-set></span></span>
|
|
<span id="cb36-15"><a aria-hidden="true" href="#cb36-15" tabindex="-1"></a><span class="st"> <displayname>Calendar</displayname></span></span>
|
|
<span id="cb36-16"><a aria-hidden="true" href="#cb36-16" tabindex="-1"></a><span class="st"> <C:calendar-description>Example calendar</C:calendar-description></span></span>
|
|
<span id="cb36-17"><a aria-hidden="true" href="#cb36-17" tabindex="-1"></a><span class="st"> <I:calendar-color>#ff0000ff</I:calendar-color></span></span>
|
|
<span id="cb36-18"><a aria-hidden="true" href="#cb36-18" tabindex="-1"></a><span class="st"> </prop></span></span>
|
|
<span id="cb36-19"><a aria-hidden="true" href="#cb36-19" tabindex="-1"></a><span class="st"> </set></span></span>
|
|
<span id="cb36-20"><a aria-hidden="true" href="#cb36-20" tabindex="-1"></a><span class="st"></create>'</span></span></code></pre></div>
|
|
<p>To create a new address book run something like:</p>
|
|
<div class="sourceCode" id="cb37"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb37-1"><a aria-hidden="true" href="#cb37-1" tabindex="-1"></a><span class="ex">$</span> curl <span class="at">-u</span> user <span class="at">-X</span> MKCOL <span class="st">'http://localhost:5232/user/addressbook'</span> <span class="at">--data</span> <span class="dt">\</span></span>
|
|
<span id="cb37-2"><a aria-hidden="true" href="#cb37-2" tabindex="-1"></a><span class="st">'<?xml version="1.0" encoding="UTF-8" ?></span></span>
|
|
<span id="cb37-3"><a aria-hidden="true" href="#cb37-3" tabindex="-1"></a><span class="st"><create xmlns="DAV:" xmlns:CR="urn:ietf:params:xml:ns:carddav"></span></span>
|
|
<span id="cb37-4"><a aria-hidden="true" href="#cb37-4" tabindex="-1"></a><span class="st"> <set></span></span>
|
|
<span id="cb37-5"><a aria-hidden="true" href="#cb37-5" tabindex="-1"></a><span class="st"> <prop></span></span>
|
|
<span id="cb37-6"><a aria-hidden="true" href="#cb37-6" tabindex="-1"></a><span class="st"> <resourcetype></span></span>
|
|
<span id="cb37-7"><a aria-hidden="true" href="#cb37-7" tabindex="-1"></a><span class="st"> <collection /></span></span>
|
|
<span id="cb37-8"><a aria-hidden="true" href="#cb37-8" tabindex="-1"></a><span class="st"> <CR:addressbook /></span></span>
|
|
<span id="cb37-9"><a aria-hidden="true" href="#cb37-9" tabindex="-1"></a><span class="st"> </resourcetype></span></span>
|
|
<span id="cb37-10"><a aria-hidden="true" href="#cb37-10" tabindex="-1"></a><span class="st"> <displayname>Address book</displayname></span></span>
|
|
<span id="cb37-11"><a aria-hidden="true" href="#cb37-11" tabindex="-1"></a><span class="st"> <CR:addressbook-description>Example address book</CR:addressbook-description></span></span>
|
|
<span id="cb37-12"><a aria-hidden="true" href="#cb37-12" tabindex="-1"></a><span class="st"> </prop></span></span>
|
|
<span id="cb37-13"><a aria-hidden="true" href="#cb37-13" tabindex="-1"></a><span class="st"> </set></span></span>
|
|
<span id="cb37-14"><a aria-hidden="true" href="#cb37-14" tabindex="-1"></a><span class="st"></create>'</span></span></code></pre></div>
|
|
<p>The collection <code>/USERNAME</code> 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 <code>/USERNAME/</code>.</p>
|
|
<p>Delete the collections by running something like:</p>
|
|
<div class="sourceCode" id="cb38"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb38-1"><a aria-hidden="true" href="#cb38-1" tabindex="-1"></a><span class="ex">curl</span> <span class="at">-u</span> user <span class="at">-X</span> DELETE <span class="st">'http://localhost:5232/user/calendar'</span></span></code></pre></div>
|
|
</section>
|
|
</section>
|
|
<section class="level3" id="authentication-and-rights">
|
|
<h3>Authentication and Rights <a class="headerlink" href="#authentication-and-rights">¶</a></h3>
|
|
<p>This section describes the format of the rights file for the
|
|
<code>from_file</code> authentication backend. The configuration option
|
|
<code>file</code> in the <code>rights</code> section must point to the
|
|
rights file.</p>
|
|
<p>The recommended rights method is <code>owner_only</code>. If access
|
|
to calendars and address books outside the home directory of users
|
|
(that's <code>/USERNAME/</code>) 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.</p>
|
|
<p>An example rights file:</p>
|
|
<div class="sourceCode" id="cb39"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb39-1"><a aria-hidden="true" href="#cb39-1" tabindex="-1"></a><span class="co"># Allow reading root collection for authenticated users</span></span>
|
|
<span id="cb39-2"><a aria-hidden="true" href="#cb39-2" tabindex="-1"></a><span class="kw">[root]</span></span>
|
|
<span id="cb39-3"><a aria-hidden="true" href="#cb39-3" tabindex="-1"></a><span class="dt">user: .+</span></span>
|
|
<span id="cb39-4"><a aria-hidden="true" href="#cb39-4" tabindex="-1"></a><span class="dt">collection:</span></span>
|
|
<span id="cb39-5"><a aria-hidden="true" href="#cb39-5" tabindex="-1"></a><span class="dt">permissions: r</span></span>
|
|
<span id="cb39-6"><a aria-hidden="true" href="#cb39-6" tabindex="-1"></a></span>
|
|
<span id="cb39-7"><a aria-hidden="true" href="#cb39-7" tabindex="-1"></a><span class="co"># Allow reading and writing principal collection (same as username)</span></span>
|
|
<span id="cb39-8"><a aria-hidden="true" href="#cb39-8" tabindex="-1"></a><span class="kw">[principal]</span></span>
|
|
<span id="cb39-9"><a aria-hidden="true" href="#cb39-9" tabindex="-1"></a><span class="dt">user: .+</span></span>
|
|
<span id="cb39-10"><a aria-hidden="true" href="#cb39-10" tabindex="-1"></a><span class="dt">collection: {user}</span></span>
|
|
<span id="cb39-11"><a aria-hidden="true" href="#cb39-11" tabindex="-1"></a><span class="dt">permissions: RW</span></span>
|
|
<span id="cb39-12"><a aria-hidden="true" href="#cb39-12" tabindex="-1"></a></span>
|
|
<span id="cb39-13"><a aria-hidden="true" href="#cb39-13" tabindex="-1"></a><span class="co"># Allow reading and writing calendars and address books that are direct</span></span>
|
|
<span id="cb39-14"><a aria-hidden="true" href="#cb39-14" tabindex="-1"></a><span class="co"># children of the principal collection</span></span>
|
|
<span id="cb39-15"><a aria-hidden="true" href="#cb39-15" tabindex="-1"></a><span class="kw">[calendars]</span></span>
|
|
<span id="cb39-16"><a aria-hidden="true" href="#cb39-16" tabindex="-1"></a><span class="dt">user: .+</span></span>
|
|
<span id="cb39-17"><a aria-hidden="true" href="#cb39-17" tabindex="-1"></a><span class="dt">collection: {user}/</span><span class="kw">[^/]</span><span class="dt">+</span></span>
|
|
<span id="cb39-18"><a aria-hidden="true" href="#cb39-18" tabindex="-1"></a><span class="dt">permissions: rw</span></span></code></pre></div>
|
|
<p>The titles of the sections are ignored (but must be unique). The keys
|
|
<code>user</code> and <code>collection</code> contain regular
|
|
expressions, that are matched against the username and the path of the
|
|
collection. Permissions from the first matching section are used. If no
|
|
section matches, access gets denied.</p>
|
|
<p>The username is empty for anonymous users. Therefore, the regex
|
|
<code>.+</code> only matches authenticated users and <code>.*</code>
|
|
matches everyone (including anonymous users).</p>
|
|
<p>The path of the collection is separated by <code>/</code> and has no
|
|
leading or trailing <code>/</code>. Therefore, the path of the root
|
|
collection is empty.</p>
|
|
<p>In the <code>collection</code> regex you can use <code>{user}</code>
|
|
and get groups from the <code>user</code> regex with <code>{0}</code>,
|
|
<code>{1}</code>, etc.</p>
|
|
<p>In consequence of the parameter substitution you have to write
|
|
<code>{{</code> and <code>}}</code> if you want to use regular curly
|
|
braces in the <code>user</code> and <code>collection</code> regexes.</p>
|
|
<p>The following <code>permissions</code> are recognized:</p>
|
|
<ul>
|
|
<li><strong>R:</strong> read collections (excluding address books and
|
|
calendars)</li>
|
|
<li><strong>r:</strong> read address book and calendar collections</li>
|
|
<li><strong>i:</strong> subset of <strong>r</strong> that only allows
|
|
direct access via HTTP method GET (CalDAV/CardDAV is susceptible to
|
|
expensive search requests)</li>
|
|
<li><strong>W:</strong> write collections (excluding address books and
|
|
calendars)</li>
|
|
<li><strong>w:</strong> write address book and calendar collections</li>
|
|
</ul>
|
|
</section>
|
|
<section class="level3" id="storage-2">
|
|
<h3>Storage <a class="headerlink" href="#storage-2">¶</a></h3>
|
|
<p>This document describes the layout and format of the file system
|
|
storage (<code>multifilesystem</code> backend).</p>
|
|
<p>It's safe to access and manipulate the data by hand or with scripts.
|
|
Scripts can be invoked manually, periodically (e.g. with <a href="https://manpages.debian.org/unstable/cron/cron.8.en.html">cron</a>)
|
|
or after each change to the storage with the configuration option
|
|
<code>hook</code> in the <code>storage</code> section (e.g. <a href="#versioning-with-git">Versioning with Git</a>).</p>
|
|
<section class="level4" id="layout">
|
|
<h4>Layout <a class="headerlink" href="#layout">¶</a></h4>
|
|
<p>The file system contains the following files and folders:</p>
|
|
<ul>
|
|
<li><code>.Radicale.lock</code>: The lock file for locking the
|
|
storage.</li>
|
|
<li><code>collection-root</code>: This folder contains all collections
|
|
and items.</li>
|
|
</ul>
|
|
<p>A collection is represented by a folder. This folder may contain the
|
|
file <code>.Radicale.props</code> with all WebDAV properties of the
|
|
collection encoded as <a href="https://en.wikipedia.org/wiki/JSON">JSON</a>.</p>
|
|
<p>An item is represented by a file containing the iCalendar data.</p>
|
|
<p>All files and folders, whose names start with a dot but not
|
|
<code>.Radicale.</code> (internal files) are ignored.</p>
|
|
<p>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.</p>
|
|
<p>Caches and sync-tokens are stored in the <code>.Radicale.cache</code>
|
|
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.</p>
|
|
<p>You may encounter files or folders that start with
|
|
<code>.Radicale.tmp-</code>. 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.</p>
|
|
</section>
|
|
<section class="level4" id="locking">
|
|
<h4>Locking <a class="headerlink" href="#locking">¶</a></h4>
|
|
<p>When the data is accessed by hand or by an externally invoked script,
|
|
the storage must be locked. The storage can be locked for exclusive or
|
|
shared access. It prevents Radicale from reading or writing the file
|
|
system. The storage is locked with exclusive access while the
|
|
<code>hook</code> runs.</p>
|
|
<section class="level5" id="linux-shell-scripts">
|
|
<h5>Linux shell scripts <a class="headerlink" href="#linux-shell-scripts">¶</a></h5>
|
|
<p>Use the <a href="https://manpages.debian.org/unstable/util-linux/flock.1.en.html">flock</a>
|
|
utility.</p>
|
|
<div class="sourceCode" id="cb40"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb40-1"><a aria-hidden="true" href="#cb40-1" tabindex="-1"></a><span class="co"># Exclusive</span></span>
|
|
<span id="cb40-2"><a aria-hidden="true" href="#cb40-2" tabindex="-1"></a><span class="ex">$</span> flock <span class="at">--exclusive</span> /path/to/storage/.Radicale.lock COMMAND</span>
|
|
<span id="cb40-3"><a aria-hidden="true" href="#cb40-3" tabindex="-1"></a><span class="co"># Shared</span></span>
|
|
<span id="cb40-4"><a aria-hidden="true" href="#cb40-4" tabindex="-1"></a><span class="ex">$</span> flock <span class="at">--shared</span> /path/to/storage/.Radicale.lock COMMAND</span></code></pre></div>
|
|
</section>
|
|
<section class="level5" id="linux-and-macos">
|
|
<h5>Linux and MacOS <a class="headerlink" href="#linux-and-macos">¶</a></h5>
|
|
<p>Use the <a href="https://manpages.debian.org/unstable/manpages-dev/flock.2.en.html">flock</a>
|
|
syscall. Python provides it in the <a href="https://docs.python.org/3/library/fcntl.html#fcntl.flock">fcntl</a>
|
|
module.</p>
|
|
</section>
|
|
<section class="level5" id="windows-1">
|
|
<h5>Windows <a class="headerlink" href="#windows-1">¶</a></h5>
|
|
<p>Use <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa365202%28v=vs.85%29.aspx">LockFile</a>
|
|
for exclusive access or <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203%28v=vs.85%29.aspx">LockFileEx</a>
|
|
which also supports shared access. Setting
|
|
<code>nNumberOfBytesToLockLow</code> to <code>1</code> and
|
|
<code>nNumberOfBytesToLockHigh</code> to <code>0</code> works.</p>
|
|
</section>
|
|
</section>
|
|
<section class="level4" id="manually-creating-collections">
|
|
<h4>Manually creating collections <a class="headerlink" href="#manually-creating-collections">¶</a></h4>
|
|
<p>To create a new collection, you have to create the corresponding
|
|
folder in the file system storage (e.g.
|
|
<code>collection-root/user/calendar</code>). To tell Radicale and
|
|
clients that the collection is a calendar, you have to create the file
|
|
<code>.Radicale.props</code> with the following content in the
|
|
folder:</p>
|
|
<div class="sourceCode" id="cb41"><pre class="sourceCode json"><code class="sourceCode json"><span id="cb41-1"><a aria-hidden="true" href="#cb41-1" tabindex="-1"></a><span class="fu">{</span><span class="dt">"tag"</span><span class="fu">:</span> <span class="st">"VCALENDAR"</span><span class="fu">}</span></span></code></pre></div>
|
|
<p>The calendar is now available at the URL path
|
|
<code>/user/calendar</code>. For address books the file must
|
|
contain:</p>
|
|
<div class="sourceCode" id="cb42"><pre class="sourceCode json"><code class="sourceCode json"><span id="cb42-1"><a aria-hidden="true" href="#cb42-1" tabindex="-1"></a><span class="fu">{</span><span class="dt">"tag"</span><span class="fu">:</span> <span class="st">"VADDRESSBOOK"</span><span class="fu">}</span></span></code></pre></div>
|
|
<p>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
|
|
<code>/USERNAME/</code>.</p>
|
|
<p>Delete collections by deleting the corresponding folders.</p>
|
|
</section>
|
|
</section>
|
|
<section class="level3" id="logging-1">
|
|
<h3>Logging <a class="headerlink" href="#logging-1">¶</a></h3>
|
|
<p>Radicale logs to <code>stderr</code>. The verbosity of the log output
|
|
can be controlled with <code>--debug</code> command line argument or the
|
|
<code>level</code> configuration option in the <code>logging</code>
|
|
section.</p>
|
|
</section>
|
|
<section class="level3" id="architecture">
|
|
<h3>Architecture <a class="headerlink" href="#architecture">¶</a></h3>
|
|
<p>Radicale is a small piece of software, but understanding it is not as
|
|
easy as it seems. But don't worry, reading this short section is enough
|
|
to understand what a CalDAV/CardDAV server is, and how Radicale's code
|
|
is organized.</p>
|
|
<section class="level4" id="protocol-overview">
|
|
<h4>Protocol overview <a class="headerlink" href="#protocol-overview">¶</a></h4>
|
|
<p>Here is a simple overview of the global architecture for reaching a
|
|
calendar or an address book through network:</p>
|
|
<div class="tableContainer"><table>
|
|
<thead>
|
|
<tr class="header">
|
|
<th>Part</th>
|
|
<th>Layer</th>
|
|
<th>Protocol or Format</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="odd">
|
|
<td>Server</td>
|
|
<td>Calendar/Contact Storage</td>
|
|
<td>iCal/vCard</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>''</td>
|
|
<td>Calendar/Contact Server</td>
|
|
<td>CalDAV/CardDAV Server</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>Transfer</td>
|
|
<td>Network</td>
|
|
<td>CalDAV/CardDAV (HTTP + TLS)</td>
|
|
</tr>
|
|
<tr class="even">
|
|
<td>Client</td>
|
|
<td>Calendar/Contact Client</td>
|
|
<td>CalDAV/CardDAV Client</td>
|
|
</tr>
|
|
<tr class="odd">
|
|
<td>''</td>
|
|
<td>GUI</td>
|
|
<td>Terminal, GTK, Web interface, etc.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table></div>
|
|
<p>Radicale is <strong>only the server part</strong> of this
|
|
architecture.</p>
|
|
<p>Please note that:</p>
|
|
<ul>
|
|
<li>CalDAV and CardDAV are superset protocols of WebDAV,</li>
|
|
<li>WebDAV is a superset protocol of HTTP.</li>
|
|
</ul>
|
|
<p>Radicale being a CalDAV/CardDAV server, it also can be seen as a
|
|
special WebDAV and HTTP server.</p>
|
|
<p>Radicale is <strong>not the client part</strong> of this
|
|
architecture. It means that Radicale never draws calendars, address
|
|
books, events and contacts on the screen. It only stores them and give
|
|
the possibility to share them online with other people.</p>
|
|
<p>If you want to see or edit your events and your contacts, you have to
|
|
use another software called a client, that can be a "normal"
|
|
applications with icons and buttons, a terminal or another web
|
|
application.</p>
|
|
</section>
|
|
<section class="level4" id="code-architecture">
|
|
<h4>Code Architecture <a class="headerlink" href="#code-architecture">¶</a></h4>
|
|
<p>The <code>radicale</code> package offers the following modules.</p>
|
|
<p><code>__init__</code> : Contains the entry point for WSGI.</p>
|
|
<p><code>__main__</code> : Provides the entry point for the
|
|
<code>radicale</code> executable and includes the command line parser.
|
|
It loads configuration files from the default (or specified) paths and
|
|
starts the internal server.</p>
|
|
<p><code>app</code> : 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.</p>
|
|
<p><code>auth</code> : Used for authenticating users based on username
|
|
and password, mapping usernames to internal users and optionally
|
|
retrieving credentials from the environment.</p>
|
|
<p><code>config</code> : Contains the code for managing configuration
|
|
and loading settings from files.</p>
|
|
<p><code>ìtem</code> : Internal representation of address book and
|
|
calendar entries. Based on <a href="https://eventable.github.io/vobject/">VObject</a>.</p>
|
|
<p><code>log</code> : The logger for Radicale based on the default
|
|
Python logging module.</p>
|
|
<p><code>rights</code> : This module is used by Radicale to manage
|
|
access rights to collections, address books and calendars.</p>
|
|
<p><code>server</code> : The integrated HTTP server for standalone
|
|
use.</p>
|
|
<p><code>storage</code> : This module contains the classes representing
|
|
collections in Radicale and the code for storing and loading them in the
|
|
filesystem.</p>
|
|
<p><code>web</code> : This module contains the web interface.</p>
|
|
<p><code>utils</code> : Contains general helper functions.</p>
|
|
<p><code>httputils</code> : Contains helper functions for working with
|
|
HTTP.</p>
|
|
<p><code>pathutils</code> : Helper functions for working with paths and
|
|
the filesystem.</p>
|
|
<p><code>xmlutils</code> : Helper functions for working with the XML
|
|
part of CalDAV/CardDAV requests and responses. It's based on the
|
|
ElementTree XML API.</p>
|
|
</section>
|
|
</section>
|
|
<section class="level3" id="plugins">
|
|
<h3>Plugins <a class="headerlink" href="#plugins">¶</a></h3>
|
|
<p>Radicale can be extended by plugins for authentication, rights
|
|
management and storage. Plugins are <strong>python</strong> modules.</p>
|
|
<section class="level4" id="getting-started-1">
|
|
<h4>Getting started <a class="headerlink" href="#getting-started-1">¶</a></h4>
|
|
<p>To get started we walk through the creation of a simple
|
|
authentication plugin, that accepts login attempts with a static
|
|
password.</p>
|
|
<p>The easiest way to develop and install <strong>python</strong>
|
|
modules is <a href="https://docs.python.org/3/distutils/setupscript.html">Distutils</a>.
|
|
For a minimal setup create the file <code>setup.py</code> with the
|
|
following content in an empty folder:</p>
|
|
<div class="sourceCode" id="cb43"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb43-1"><a aria-hidden="true" href="#cb43-1" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
|
<span id="cb43-2"><a aria-hidden="true" href="#cb43-2" tabindex="-1"></a></span>
|
|
<span id="cb43-3"><a aria-hidden="true" href="#cb43-3" tabindex="-1"></a><span class="im">from</span> distutils.core <span class="im">import</span> setup</span>
|
|
<span id="cb43-4"><a aria-hidden="true" href="#cb43-4" tabindex="-1"></a></span>
|
|
<span id="cb43-5"><a aria-hidden="true" href="#cb43-5" tabindex="-1"></a>setup(name<span class="op">=</span><span class="st">"radicale_static_password_auth"</span>,</span>
|
|
<span id="cb43-6"><a aria-hidden="true" href="#cb43-6" tabindex="-1"></a> packages<span class="op">=</span>[<span class="st">"radicale_static_password_auth"</span>])</span></code></pre></div>
|
|
<p>In the same folder create the sub-folder
|
|
<code>radicale_static_password_auth</code>. The folder must have the
|
|
same name as specified in <code>packages</code> above.</p>
|
|
<p>Create the file <code>__init__.py</code> in the
|
|
<code>radicale_static_password_auth</code> folder with the following
|
|
content:</p>
|
|
<div class="sourceCode" id="cb44"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb44-1"><a aria-hidden="true" href="#cb44-1" tabindex="-1"></a><span class="im">from</span> radicale.auth <span class="im">import</span> BaseAuth</span>
|
|
<span id="cb44-2"><a aria-hidden="true" href="#cb44-2" tabindex="-1"></a><span class="im">from</span> radicale.log <span class="im">import</span> logger</span>
|
|
<span id="cb44-3"><a aria-hidden="true" href="#cb44-3" tabindex="-1"></a></span>
|
|
<span id="cb44-4"><a aria-hidden="true" href="#cb44-4" tabindex="-1"></a>PLUGIN_CONFIG_SCHEMA <span class="op">=</span> {<span class="st">"auth"</span>: {</span>
|
|
<span id="cb44-5"><a aria-hidden="true" href="#cb44-5" tabindex="-1"></a> <span class="st">"password"</span>: {<span class="st">"value"</span>: <span class="st">""</span>, <span class="st">"type"</span>: <span class="bu">str</span>}}}</span>
|
|
<span id="cb44-6"><a aria-hidden="true" href="#cb44-6" tabindex="-1"></a></span>
|
|
<span id="cb44-7"><a aria-hidden="true" href="#cb44-7" tabindex="-1"></a></span>
|
|
<span id="cb44-8"><a aria-hidden="true" href="#cb44-8" tabindex="-1"></a><span class="kw">class</span> Auth(BaseAuth):</span>
|
|
<span id="cb44-9"><a aria-hidden="true" href="#cb44-9" tabindex="-1"></a> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, configuration):</span>
|
|
<span id="cb44-10"><a aria-hidden="true" href="#cb44-10" tabindex="-1"></a> <span class="bu">super</span>().<span class="fu">__init__</span>(configuration.copy(PLUGIN_CONFIG_SCHEMA))</span>
|
|
<span id="cb44-11"><a aria-hidden="true" href="#cb44-11" tabindex="-1"></a></span>
|
|
<span id="cb44-12"><a aria-hidden="true" href="#cb44-12" tabindex="-1"></a> <span class="kw">def</span> login(<span class="va">self</span>, login, password):</span>
|
|
<span id="cb44-13"><a aria-hidden="true" href="#cb44-13" tabindex="-1"></a> <span class="co"># Get password from configuration option</span></span>
|
|
<span id="cb44-14"><a aria-hidden="true" href="#cb44-14" tabindex="-1"></a> static_password <span class="op">=</span> <span class="va">self</span>.configuration.get(<span class="st">"auth"</span>, <span class="st">"password"</span>)</span>
|
|
<span id="cb44-15"><a aria-hidden="true" href="#cb44-15" tabindex="-1"></a> <span class="co"># Check authentication</span></span>
|
|
<span id="cb44-16"><a aria-hidden="true" href="#cb44-16" tabindex="-1"></a> logger.info(<span class="st">"Login attempt by </span><span class="sc">%r</span><span class="st"> with password </span><span class="sc">%r</span><span class="st">"</span>,</span>
|
|
<span id="cb44-17"><a aria-hidden="true" href="#cb44-17" tabindex="-1"></a> login, password)</span>
|
|
<span id="cb44-18"><a aria-hidden="true" href="#cb44-18" tabindex="-1"></a> <span class="cf">if</span> password <span class="op">==</span> static_password:</span>
|
|
<span id="cb44-19"><a aria-hidden="true" href="#cb44-19" tabindex="-1"></a> <span class="cf">return</span> login</span>
|
|
<span id="cb44-20"><a aria-hidden="true" href="#cb44-20" tabindex="-1"></a> <span class="cf">return</span> <span class="st">""</span></span></code></pre></div>
|
|
<p>Install the python module by running the following command in the
|
|
same folder as <code>setup.py</code>:</p>
|
|
<div class="sourceCode" id="cb45"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb45-1"><a aria-hidden="true" href="#cb45-1" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> pip install .</span></code></pre></div>
|
|
<p>To make use this great creation in Radicale, set the configuration
|
|
option <code>type</code> in the <code>auth</code> section to
|
|
<code>radicale_static_password_auth</code>:</p>
|
|
<div class="sourceCode" id="cb46"><pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb46-1"><a aria-hidden="true" href="#cb46-1" tabindex="-1"></a><span class="kw">[auth]</span></span>
|
|
<span id="cb46-2"><a aria-hidden="true" href="#cb46-2" tabindex="-1"></a><span class="dt">type </span><span class="ot">=</span><span class="st"> radicale_static_password_auth</span></span>
|
|
<span id="cb46-3"><a aria-hidden="true" href="#cb46-3" tabindex="-1"></a><span class="dt">password </span><span class="ot">=</span><span class="st"> secret</span></span></code></pre></div>
|
|
<p>You can uninstall the module with:</p>
|
|
<div class="sourceCode" id="cb47"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb47-1"><a aria-hidden="true" href="#cb47-1" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> pip uninstall radicale_static_password_auth</span></code></pre></div>
|
|
</section>
|
|
<section class="level4" id="authentication-plugins">
|
|
<h4>Authentication plugins <a class="headerlink" href="#authentication-plugins">¶</a></h4>
|
|
<p>This plugin type is used to check login credentials. The module must
|
|
contain a class <code>Auth</code> that extends
|
|
<code>radicale.auth.BaseAuth</code>. Take a look at the file
|
|
<code>radicale/auth/__init__.py</code> in Radicale's source code for
|
|
more information.</p>
|
|
</section>
|
|
<section class="level4" id="rights-management-plugins">
|
|
<h4>Rights management plugins <a class="headerlink" href="#rights-management-plugins">¶</a></h4>
|
|
<p>This plugin type is used to check if a user has access to a path. The
|
|
module must contain a class <code>Rights</code> that extends
|
|
<code>radicale.rights.BaseRights</code>. Take a look at the file
|
|
<code>radicale/rights/__init__.py</code> in Radicale's source code for
|
|
more information.</p>
|
|
</section>
|
|
<section class="level4" id="web-plugins">
|
|
<h4>Web plugins <a class="headerlink" href="#web-plugins">¶</a></h4>
|
|
<p>This plugin type is used to provide the web interface for Radicale.
|
|
The module must contain a class <code>Web</code> that extends
|
|
<code>radicale.web.BaseWeb</code>. Take a look at the file
|
|
<code>radicale/web/__init__.py</code> in Radicale's source code for more
|
|
information.</p>
|
|
</section>
|
|
<section class="level4" id="storage-plugins">
|
|
<h4>Storage plugins <a class="headerlink" href="#storage-plugins">¶</a></h4>
|
|
<p>This plugin is used to store collections and items. The module must
|
|
contain a class <code>Storage</code> that extends
|
|
<code>radicale.storage.BaseStorage</code>. Take a look at the file
|
|
<code>radicale/storage/__init__.py</code> in Radicale's source code for
|
|
more information.</p>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
<section class="level2" id="contribute">
|
|
<h2>Contribute <a class="headerlink" href="#contribute">¶</a></h2>
|
|
<section class="level4" id="report-bugs">
|
|
<h4>Report Bugs <a class="headerlink" href="#report-bugs">¶</a></h4>
|
|
<p>Found a bug? Want a new feature? Report a new issue on the <a href="https://github.com/Kozea/Radicale/issues">Radicale
|
|
bug-tracker</a>.</p>
|
|
</section>
|
|
<section class="level4" id="hack">
|
|
<h4>Hack <a class="headerlink" href="#hack">¶</a></h4>
|
|
<p>Interested in hacking? Feel free to clone the <a href="https://github.com/Kozea/Radicale">git repository on GitHub</a> if
|
|
you want to add new features, fix bugs or update the documentation.</p>
|
|
</section>
|
|
<section class="level4" id="documentation-2">
|
|
<h4>Documentation <a class="headerlink" href="#documentation-2">¶</a></h4>
|
|
<p>To change or complement the documentation create a pull request to <a href="https://github.com/Kozea/Radicale/blob/master/DOCUMENTATION.md">DOCUMENTATION.md</a>.</p>
|
|
</section>
|
|
</section>
|
|
<section class="level2" id="download">
|
|
<h2>Download <a class="headerlink" href="#download">¶</a></h2>
|
|
<section class="level4" id="pypi">
|
|
<h4>PyPI <a class="headerlink" href="#pypi">¶</a></h4>
|
|
<p>Radicale is <a href="https://pypi.python.org/pypi/Radicale/">available on PyPI</a>. To
|
|
install, just type as superuser:</p>
|
|
<div class="sourceCode" id="cb48"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb48-1"><a aria-hidden="true" href="#cb48-1" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> pip install <span class="at">--upgrade</span> radicale</span></code></pre></div>
|
|
</section>
|
|
<section class="level4" id="git-repository">
|
|
<h4>Git Repository <a class="headerlink" href="#git-repository">¶</a></h4>
|
|
<p>If you want the development version of Radicale, take a look at the
|
|
<a href="https://github.com/Kozea/Radicale/">git repository on
|
|
GitHub</a>, or install it directly with:</p>
|
|
<div class="sourceCode" id="cb49"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb49-1"><a aria-hidden="true" href="#cb49-1" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> pip install <span class="at">--upgrade</span> https://github.com/Kozea/Radicale/archive/master.tar.gz</span></code></pre></div>
|
|
<p>You can also download the content of the repository as an <a href="https://github.com/Kozea/Radicale/tarball/master">archive</a>.</p>
|
|
</section>
|
|
<section class="level4" id="source-packages">
|
|
<h4>Source Packages <a class="headerlink" href="#source-packages">¶</a></h4>
|
|
<p>You can find the source packages of all releases on <a href="https://github.com/Kozea/Radicale/releases">GitHub</a>.</p>
|
|
</section>
|
|
<section class="level4" id="linux-distribution-packages">
|
|
<h4>Linux Distribution Packages <a class="headerlink" href="#linux-distribution-packages">¶</a></h4>
|
|
<p>Radicale has been packaged for:</p>
|
|
<ul>
|
|
<li><a href="https://www.archlinux.org/packages/community/any/radicale/">ArchLinux</a>
|
|
by David Runge</li>
|
|
<li><a href="http://packages.debian.org/radicale">Debian</a> by Jonas
|
|
Smedegaard</li>
|
|
<li><a href="https://packages.gentoo.org/packages/www-apps/radicale">Gentoo</a>
|
|
by René Neumann, Maxim Koltsov and Manuel Rüger</li>
|
|
<li><a href="https://src.fedoraproject.org/rpms/radicale">Fedora/RHEL/CentOS</a>
|
|
by Jorti and Peter Bieringer</li>
|
|
<li><a href="http://madb.mageia.org/package/show/application/0/name/radicale">Mageia</a>
|
|
by Jani Välimaa</li>
|
|
<li><a href="http://openports.se/productivity/radicale">OpenBSD</a> by
|
|
Sergey Bronnikov, Stuart Henderson and Ian Darwin</li>
|
|
<li><a href="http://software.opensuse.org/package/Radicale?search_term=radicale">openSUSE</a>
|
|
by Ákos Szőts and Rueckert</li>
|
|
<li><a href="http://code.activestate.com/pypm/radicale/">PyPM</a></li>
|
|
<li><a href="http://schoepfer.info/slackware.xhtml#packages-network">Slackware</a>
|
|
by Johannes Schöpfer</li>
|
|
<li><a href="http://packages.trisquel.info/search?searchon=names&keywords=radicale">Trisquel</a></li>
|
|
<li><a href="http://packages.ubuntu.com/radicale">Ubuntu</a> by the MOTU
|
|
and Jonas Smedegaard</li>
|
|
</ul>
|
|
<p>Radicale is also <a href="https://cloudron.io/button.html?app=org.radicale.cloudronapp2">available
|
|
on Cloudron</a> and has a Dockerfile.</p>
|
|
<p>If you are interested in creating packages for other Linux
|
|
distributions, read the <a href="#contribute">"Contribute"
|
|
section</a>.</p>
|
|
</section>
|
|
</section>
|
|
<section class="level2" id="about">
|
|
<h2>About <a class="headerlink" href="#about">¶</a></h2>
|
|
<section class="level4" id="main-goals">
|
|
<h4>Main Goals <a class="headerlink" href="#main-goals">¶</a></h4>
|
|
<p>Radicale is a complete calendar and contact storing and manipulating
|
|
solution. It can store multiple calendars and multiple address
|
|
books.</p>
|
|
<p>Calendar and contact manipulation is available from both local and
|
|
distant accesses, possibly limited through authentication policies.</p>
|
|
<p>It aims to be a lightweight solution, easy to use, easy to install,
|
|
easy to configure. As a consequence, it requires few software
|
|
dependencies and is preconfigured to work out-of-the-box.</p>
|
|
<p>Radicale is written in Python. It runs on most of the UNIX-like
|
|
platforms (Linux, *BSD, macOS) and Windows. It is free and open-source
|
|
software.</p>
|
|
</section>
|
|
<section class="level4" id="what-radicale-will-never-be">
|
|
<h4>What Radicale Will Never Be <a class="headerlink" href="#what-radicale-will-never-be">¶</a></h4>
|
|
<p>Radicale is a server, not a client. No interfaces will be created to
|
|
work with the server.</p>
|
|
<p>CalDAV and CardDAV are not perfect protocols. We think that their
|
|
main problem is their complexity, that is why we decided not to
|
|
implement the whole standard but just enough to understand some of its
|
|
client-side implementations.</p>
|
|
<p>CalDAV and CardDAV are the best open standards available, and they
|
|
are quite widely used by both clients and servers. We decided to use it,
|
|
and we will not use another one.</p>
|
|
</section>
|
|
<section class="level4" id="technical-choices">
|
|
<h4>Technical Choices <a class="headerlink" href="#technical-choices">¶</a></h4>
|
|
<p>Important global development choices have been decided before writing
|
|
code. They are very useful to understand why the Radicale Project is
|
|
different from other CalDAV and CardDAV servers, and why features are
|
|
included or not in the code.</p>
|
|
<section class="level5" id="oriented-to-calendar-and-contact-user-agents">
|
|
<h5>Oriented to Calendar and Contact User Agents <a class="headerlink" href="#oriented-to-calendar-and-contact-user-agents">¶</a></h5>
|
|
<p>Calendar and contact servers work with calendar and contact clients,
|
|
using a defined protocol. CalDAV and CardDAV are good protocols,
|
|
covering lots of features and use cases, but it is quite hard to
|
|
implement fully.</p>
|
|
<p>Some calendar servers have been created to follow the CalDAV and
|
|
CardDAV RFCs as much as possible: <a href="http://www.davical.org/">Davical</a>, <a href="http://sabre.io/baikal/">Baïkal</a> and <a href="http://trac.calendarserver.org/">Darwin Calendar Server</a>, for
|
|
example, are much more respectful of CalDAV and CardDAV and can be used
|
|
with many clients. They are very good choices if you want to develop and
|
|
test new CalDAV clients, or if you have a possibly heterogeneous list of
|
|
user agents.</p>
|
|
<p>Even if it tries it best to follow the RFCs, Radicale does not and
|
|
<strong>will not</strong> blindly implement the CalDAV and CardDAV
|
|
standards. It is mainly designed to support the CalDAV and CardDAV
|
|
implementations of different clients.</p>
|
|
</section>
|
|
<section class="level5" id="simple">
|
|
<h5>Simple <a class="headerlink" href="#simple">¶</a></h5>
|
|
<p>Radicale is designed to be simple to install, simple to configure,
|
|
simple to use.</p>
|
|
<p>The installation is very easy, particularly with Linux: one
|
|
dependency, no superuser rights needed, no configuration required, no
|
|
database. Installing and launching the main script out-of-the-box, as a
|
|
normal user, are often the only steps to have a simple remote calendar
|
|
and contact access.</p>
|
|
<p>Contrary to other servers that are often complicated, require high
|
|
privileges or need a strong configuration, the Radicale Server can
|
|
(sometimes, if not often) be launched in a couple of minutes, if you
|
|
follow the <a href="#simple-5-minute-setup">tutorial</a>.</p>
|
|
</section>
|
|
<section class="level5" id="lazy">
|
|
<h5>Lazy <a class="headerlink" href="#lazy">¶</a></h5>
|
|
<p>The CalDAV RFC defines what must be done, what can be done and what
|
|
cannot be done. Many violations of the protocol are totally defined and
|
|
behaviors are given in such cases.</p>
|
|
<p>Radicale often assumes that the clients are perfect and that protocol
|
|
violations do not exist. That is why most of the errors in client
|
|
requests have undetermined consequences for the lazy server that can
|
|
reply good answers, bad answers, or even no answer.</p>
|
|
</section>
|
|
</section>
|
|
<section class="level4 last" id="history">
|
|
<h4>History <a class="headerlink" href="#history">¶</a></h4>
|
|
<p>Radicale has been started as a (free topic) stupid school project
|
|
replacing another (assigned topic) even more stupid school project.</p>
|
|
<p>At the beginning, it was just a proof-of-concept. The main goal was
|
|
to write a small, dirty and simple CalDAV server working with Lightning,
|
|
using no external libraries. That's how we created a piece of code
|
|
that's (quite) easy to understand, to use and to hack.</p>
|
|
<p>The <a href="https://github.com/Kozea/Radicale/commit/b1591aea">first
|
|
lines</a> have been added to the SVN (!) repository as I was drinking
|
|
(many) beers at the very end of 2008 (Python 2.6 and 3.0 were just
|
|
released). It's now packaged for a growing number of Linux
|
|
distributions.</p>
|
|
<p>And that was fun going from here to there thanks to you!</p>
|
|
</section>
|
|
</section>
|
|
</div>
|
|
</main>
|
|
</html>
|