Privacy Tools Guide

Google Calendar and Apple iCloud see everything you schedule — meetings, medical appointments, travel. The CalDAV and CardDAV protocols are open standards that let you self-host sync with any client. This guide walks through running your own calendar/contacts server and connecting it to Android, Linux, and macOS.


Why Standard Protocols Matter

CalDAV (calendar) and CardDAV (contacts) are RFC-standard protocols that every major client supports. Once you have a CalDAV/CardDAV server, you can connect:

Your data stays on your server. No vendor lock-in.


Nextcloud includes CalDAV/CardDAV support with a web UI, sharing, and multi-user management. Best if you want more than just calendar/contacts.

# Install Nextcloud via Docker (simplest path)
mkdir -p ~/nextcloud/{db,html}
cat > ~/nextcloud/docker-compose.yml << 'EOF'
version: '3'
services:
  db:
    image: mariadb:10.11
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: changeme_root
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
      MYSQL_PASSWORD: changeme_nc
    volumes:
      - ~/nextcloud/db:/var/lib/mysql

  app:
    image: nextcloud:28
    restart: always
    ports:
      - "8080:80"
    environment:
      MYSQL_HOST: db
      MYSQL_DATABASE: nextcloud
      MYSQL_USER: nextcloud
      MYSQL_PASSWORD: changeme_nc
    volumes:
      - ~/nextcloud/html:/var/www/html
    depends_on:
      - db
EOF

cd ~/nextcloud && docker compose up -d

After startup, open http://localhost:8080 and complete the setup wizard. The CalDAV URL will be:

https://yourdomain.com/remote.php/dav/principals/users/USERNAME/

Option 2: Radicale (Lightweight, Single-User)

Radicale is a minimal CalDAV/CardDAV server — one Python process, no database, files stored as-is. Good for personal use on a Raspberry Pi or VPS.

# Install
pip install radicale

# Create config directory
mkdir -p ~/.config/radicale

cat > ~/.config/radicale/config << 'EOF'
[server]
hosts = 127.0.0.1:5232

[auth]
type = htpasswd
htpasswd_filename = /home/user/.config/radicale/users
htpasswd_encryption = bcrypt

[storage]
filesystem_folder = /home/user/.local/share/radicale

[logging]
level = warning
EOF

# Create user account
htpasswd -B -c ~/.config/radicale/users yourname
# Enter password when prompted

# Start Radicale
python -m radicale

Run as a systemd service:

# /etc/systemd/system/radicale.service
[Unit]
Description=Radicale CalDAV/CardDAV server
After=network.target

[Service]
User=youruser
ExecStart=/usr/local/bin/python -m radicale
Restart=on-failure

[Install]
WantedBy=multi-user.target
systemctl enable --now radicale

Expose via nginx reverse proxy with TLS (required for mobile clients):

server {
    listen 443 ssl;
    server_name cal.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/cal.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/cal.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:5232;
        proxy_set_header X-Script-Name /;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass_header Authorization;
    }
}

Connect Android with DAVx5

DAVx5 is the standard open-source CalDAV/CardDAV client for Android, available on F-Droid (no Google tracking) and Play Store.

Install DAVx5 from F-Droid: https://f-droid.org/packages/at.bitfire.davdroid/

Setup:

  1. Open DAVx5 → Add account
  2. Select Login with URL and user name
  3. Base URL:
    • Nextcloud: https://cloud.yourdomain.com/remote.php/dav/
    • Radicale: https://cal.yourdomain.com/
  4. Username and password as configured
  5. DAVx5 auto-discovers calendars and address books
  6. Select which to sync → tap Create account

Sync settings:

Settings → Account → Sync interval: 15 minutes
Contact group method: Groups are per-contact categories (vCard)

Connect Linux Clients

GNOME (Evolution Data Server)

# Install GNOME Online Accounts with CalDAV support
sudo apt install gnome-online-accounts

# Settings → Online Accounts → Add Account → Nextcloud
# Or: Settings → Online Accounts → Other (for CardDAV URL)
# Enter your server URL and credentials

GNOME Calendar, Contacts, and GNOME To Do all pick up accounts from Evolution Data Server automatically.

Thunderbird + Lightning

Thunderbird → Calendar tab → New Calendar → On the Network
Format: CalDAV
Location: https://cal.yourdomain.com/USERNAME/calendar/

For contacts in Thunderbird:

Address Book → New Address Book → Remote Address Book
URL: https://cal.yourdomain.com/USERNAME/contacts/

Connect macOS/iOS (Built-In)

macOS:

System Settings → Internet Accounts → Add Account → Other Account
CalDAV Account:
  Account Type: Advanced
  User Name: yourname
  Password: yourpassword
  Server Address: cal.yourdomain.com
  Server Path: /
  Port: 443
  Use SSL: checked

iOS:

Settings → Mail → Accounts → Add Account → Other
Add CalDAV Account → enter server, username, password

iOS will auto-discover calendar and contacts endpoints if your server sends the correct well-known redirects.


Migrating from Google Calendar and Google Contacts

Before you can use your own server, you need to export your existing data. Google provides clean export tools for both services.

Export Google Calendar:

Google Calendar → Settings (gear icon) → Settings
→ Import & export → Export
Downloads a .zip containing .ics files for each calendar
# Extract and inspect the export
unzip calendar_export.zip -d ~/calendar_export
ls ~/calendar_export/
# You'll see files like: personal@gmail.com.ics, birthdays.ics

# Import into Radicale by copying to the collection folder
cp ~/calendar_export/personal.ics \
  ~/.local/share/radicale/collection-root/yourname/calendar.ics

Export Google Contacts:

Google Contacts → Export → Google CSV or vCard format
# Convert Google CSV to vCard if needed
pip install vobject

python3 << 'EOF'
import csv, vobject

with open('contacts.csv', 'r') as f:
    reader = csv.DictReader(f)
    for row in reader:
        card = vobject.vCard()
        card.add('fn').value = row['Name']
        if row['E-mail 1 - Value']:
            email = card.add('email')
            email.value = row['E-mail 1 - Value']
        print(card.serialize())
EOF

For most users, exporting as vCard (.vcf) directly from Google Contacts is simpler — the file imports directly into Radicale or Nextcloud Contacts without conversion.

Troubleshooting Common Sync Problems

DAVx5 shows “Sync error” on Android:

The most common cause is a self-signed TLS certificate. DAVx5 requires a valid certificate chain. Use Let’s Encrypt:

# Install certbot and get a certificate
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d cal.yourdomain.com
# Certbot auto-configures nginx and sets up renewal

If you must use a self-signed certificate (internal network only), add it to Android’s trusted certificates via Settings → Security → Install certificates.

Contacts not appearing after sync:

DAVx5 stores contacts in a separate account. The Android Contacts app must be configured to display all accounts:

Android Contacts → Menu → Manage contacts → Contacts to display
→ Select "All contacts" or check the DAVx5 account

Calendar events disappear after editing on another client:

This usually indicates a timezone handling mismatch. Set a consistent timezone on your server:

# For Radicale, ensure events are stored with explicit TZID
# Check a problematic event:
cat ~/.local/share/radicale/collection-root/yourname/calendar/*.ics | grep TZID

# Nextcloud: set server timezone
docker exec -u www-data nextcloud-app php occ config:system:set logtimezone --value="America/New_York"

High battery drain from DAVx5:

Reduce sync frequency for less time-sensitive data:

DAVx5 → Account → Calendar sync interval: 1 hour
DAVx5 → Account → Contact sync interval: 4 hours

Contacts change rarely — daily or even manual sync is sufficient for most users.

Privacy Considerations Beyond the Server

Running your own CalDAV/CardDAV server eliminates Google and Apple from seeing your schedule, but other data flows still deserve attention.

DNS leaks your calendar server address. When DAVx5 syncs, it queries your DNS provider for cal.yourdomain.com. If you use your ISP’s DNS or a logging resolver, your sync activity is visible. Use a privacy-respecting resolver:

# On Android: Settings → Network → Private DNS
# Enter: dns.quad9.net or 1dot1dot1dot1.cloudflare-dns.com

Your VPN provider sees sync traffic timing. Even over TLS, the timing and size patterns of CalDAV sync can reveal meeting frequency. For high-sensitivity use cases, route sync traffic over a VPN or Tor.

Email invitations bypass your private server entirely. Meeting invites sent via .ics email attachments come through your email provider. If privacy-of-meetings is critical, use a private email provider alongside your CalDAV server — Tutanota and Proton Mail both support calendar invitations independently of Google.

# Export from Radicale storage (plain vCard/iCal files)
ls ~/.local/share/radicale/collection-root/

# Nextcloud export via CLI
docker exec -u www-data nextcloud-app php occ dav:export-calendar \
  --user=yourname \
  --calendar=personal \
  --output=/tmp/personal.ics

# Backup script for Radicale
rsync -av ~/.local/share/radicale/ /backup/radicale-$(date +%Y%m%d)/

Multi-User Setup on Radicale

Radicale supports multiple users from a single instance. Each user gets their own collection namespace, and access is controlled through htpasswd authentication.

# Add a second user to Radicale
htpasswd -B ~/.config/radicale/users seconduser
# Enter password when prompted

# Radicale automatically creates a separate namespace:
# /seconduser/calendar/
# /seconduser/contacts/

For per-user calendar sharing (allowing one user to read another’s calendar), Radicale’s rights system handles this through a rights config file:

# ~/.config/radicale/rights
[owner-write]
user: .+
collection: ^{user}/.*$
permissions: rw

[shared-read]
user: alice
collection: ^bob/shared-calendar/.*$
permissions: r

This gives alice read access to bob’s shared-calendar collection. Nextcloud has a web UI for this — useful for households or small teams who want shared family calendars without giving everyone full access.

Encryption at Rest

Radicale stores files as plain text. If the server disk is encrypted (LUKS), that covers it. For an extra layer:

# Store Radicale data inside an encrypted directory using fscrypt
fscrypt setup
fscrypt encrypt ~/.local/share/radicale/

# Or use encfs
encfs /backup/radicale-encrypted ~/.local/share/radicale/

Nextcloud supports server-side encryption per-file using AES-256, though it adds CPU overhead and makes backup restoration more complex — only use it if you have a specific threat model requiring it beyond full-disk encryption.



Built by theluckystrike — More at zovo.one

Frequently Asked Questions

Who is this article written for?

This article is written for developers, technical professionals, and power users who want practical guidance. Whether you are evaluating options or implementing a solution, the information here focuses on real-world applicability rather than theoretical overviews.

How current is the information in this article?

We update articles regularly to reflect the latest changes. However, tools and platforms evolve quickly. Always verify specific feature availability and pricing directly on the official website before making purchasing decisions.

Are there free alternatives available?

Free alternatives exist for most tool categories, though they typically come with limitations on features, usage volume, or support. Open-source options can fill some gaps if you are willing to handle setup and maintenance yourself. Evaluate whether the time savings from a paid tool justify the cost for your situation.

Can I trust these tools with sensitive data?

Review each tool’s privacy policy, data handling practices, and security certifications before using it with sensitive data. Look for SOC 2 compliance, encryption in transit and at rest, and clear data retention policies. Enterprise tiers often include stronger privacy guarantees.

What is the learning curve like?

Most tools discussed here can be used productively within a few hours. Mastering advanced features takes 1-2 weeks of regular use. Focus on the 20% of features that cover 80% of your needs first, then explore advanced capabilities as specific needs arise.