Deployment
Testing / development
To run a standalone instance with no authentication (useful for testing),
storing data in $HOME/dav:
xandikos --defaults -d $HOME/dav
This starts a server on localhost:8080. The
--defaults flag creates a default calendar and address book on first run.
Production with uWSGI + Nginx
For production use, the recommended setup is uWSGI behind Nginx. Nginx handles TLS and authentication; uWSGI runs Xandikos as a WSGI application.
uWSGI configuration
Save the following as /etc/uwsgi/apps-enabled/xandikos.ini, adjusting paths
as needed:
[uwsgi]
socket = 127.0.0.1:8001
uid = xandikos
gid = xandikos
master = true
cheaper = 0
processes = 1
plugin = python3
module = xandikos.wsgi:app
umask = 022
env = XANDIKOSPATH=/var/lib/xandikos/collections
env = CURRENT_USER_PRINCIPAL=/user/
# Create default calendar and contacts collections on first run
env = AUTOCREATE=defaults
Nginx configuration
The following configuration proxies requests to uWSGI, enables HTTPS via Let's Encrypt, and handles CalDAV/CardDAV service discovery (RFC 6764):
upstream xandikos {
server 127.0.0.1:8080;
# server unix:/run/xandikos.socket;
}
server {
server_name dav.example.com;
# Service discovery (RFC 6764)
location = /.well-known/caldav {
return 307 $scheme://$host/user/calendars;
}
location = /.well-known/carddav {
return 307 $scheme://$host/user/contacts;
}
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://xandikos;
auth_basic "Login required";
auth_basic_user_file /etc/xandikos/htpasswd;
}
listen 443 ssl http2;
listen [::]:443 ssl ipv6only=on http2;
ssl_certificate /etc/letsencrypt/live/dav.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dav.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = dav.example.com) {
return 301 https://$host$request_uri;
}
listen 80;
listen [::]:80;
server_name dav.example.com;
return 404;
}
Create an htpasswd file for authentication:
sudo htpasswd -c /etc/xandikos/htpasswd myusername
See Authentication for more detail on how Xandikos handles the authenticated user identity.
systemd socket activation
Xandikos supports systemd socket activation. Two unit files are needed.
/etc/systemd/system/xandikos.socket:
[Unit]
Description=Xandikos socket
[Socket]
ListenStream=/run/xandikos.sock
[Install]
WantedBy=sockets.target
/etc/systemd/system/xandikos.service:
[Unit]
Description=Xandikos CalDAV/CardDAV server
After=network.target
[Service]
ExecStart=/usr/local/bin/xandikos \
-d /var/lib/xandikos \
--route-prefix=/dav \
--current-user-principal=/jelmer \
-l /run/xandikos.sock
User=xandikos
Group=www-data
Restart=on-failure
KillSignal=SIGQUIT
Type=simple
NotifyAccess=all
Enable and start:
sudo systemctl enable --now xandikos.socket
uWSGI standalone (with built-in HTTP and auth)
For simpler setups, uWSGI can handle HTTP and basic authentication directly without a separate web server:
[uwsgi]
http-socket = 127.0.0.1:8080
umask = 022
master = true
cheaper = 0
processes = 1
plugin = router_basicauth,python3
route = ^/ basicauth:myrealm,user1:password1
module = xandikos.wsgi:app
env = XANDIKOSPATH=$HOME/dav
env = CURRENT_USER_PRINCIPAL=/dav/user1/
env = AUTOCREATE=defaults
mkdir -p $HOME/dav
uwsgi uwsgi-standalone.ini
Command-line reference
| Option | Default | Description |
|---|---|---|
-d, --directory |
(required) | Directory to store data in |
-l, --listen-address |
localhost |
Address to bind to; pass a path for a Unix socket |
-p, --port |
8080 |
Port to listen on |
--route-prefix |
/ |
Path prefix when behind a reverse proxy |
--current-user-principal |
/user/ |
Path to the current user principal |
--autocreate |
off | Create necessary directories automatically |
--defaults |
off | Create default calendar and address book (implies --autocreate) |
--no-strict |
off | Enable workarounds for buggy client implementations |
--dump-dav-xml |
off | Log DAV XML requests/responses (for debugging) |
--avahi |
off | Announce services via Avahi/mDNS |