Standalone calendar + contacts via Radicale on a NAS, syncing to iOS Calendar / Contacts over CalDAV and CardDAV (without iCloud)

You’ve spent enough years watching iCloud quietly rewrite your contact data, randomly de-syncing one device, “merging” the same family member into three different cards. The fix is leaving iCloud and running your own CalDAV/CardDAV server. Apple’s Calendar and Contacts apps speak both protocols natively — you don’t need a third-party app on the iPhone, you don’t need a sync wrapper, you just point iOS at your own server and it treats it as a peer to iCloud.

The simplest server I’ve found in years of trying is Radicale. It’s Python, ~3 MB of code, no database (it stores each calendar entry as a flat .ics file on disk), and it runs perfectly on a Synology / QNAP / homemade NAS. Set up takes about 30 minutes. Here’s the version that doesn’t break two months later.

Why Radicale, not Baikal or Nextcloud

  • Baikal is also fine, but it’s PHP+SQLite and the upstream is less actively developed in 2026. If you already run PHP on your NAS you can pick it. I prefer Radicale because it’s simpler.
  • Nextcloud includes calendar+contacts but you have to install all of Nextcloud — a 200 MB app with a database, web UI, plugins, federation, the works. Overkill if you only want CalDAV/CardDAV. Worth it if you also want files, deck, mail, etc.
  • Radicale is just CalDAV+CardDAV. No web UI to speak of (a small read-only one). No database. The data is plain text on disk — you back it up with rsync, you grep through it when something’s weird.

Step 1 — install Radicale on the NAS

Easiest path is Docker, which most modern NAS UIs support. On a Synology with Container Manager, or any Linux box:

# /volume1/docker/radicale/docker-compose.yml
services:
  radicale:
    image: tomsquest/docker-radicale:latest
    container_name: radicale
    ports:
      - "127.0.0.1:5232:5232"
    volumes:
      - ./data:/data
      - ./config:/config:ro
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5232/"]
      interval: 60s

# /volume1/docker/radicale/config/config
# (this is the radicale config file, NOT yaml)
[server]
hosts = 0.0.0.0:5232

[auth]
type = htpasswd
htpasswd_filename = /config/users
htpasswd_encryption = bcrypt

[storage]
filesystem_folder = /data/collections

Generate the users file with htpasswd. Use a real password — this server holds your address book:

htpasswd -B -c /volume1/docker/radicale/config/users you
# you'll be prompted for password twice

Bring it up: docker compose up -d. The server is now listening on 127.0.0.1:5232 — only on localhost, intentionally. You’ll expose it through a reverse proxy with TLS next, never raw on the LAN.

Step 2 — front it with TLS via your reverse proxy

iOS will refuse to talk to a CalDAV server over plain HTTP, and won’t accept self-signed certificates without you manually trusting them. Easiest path: a real DNS name, a real Let’s Encrypt cert, Caddy in front:

# /etc/caddy/Caddyfile
dav.example.com {
    reverse_proxy 127.0.0.1:5232
    encode gzip
}

Caddy auto-issues a Let’s Encrypt cert. Now https://dav.example.com/ shows the Radicale login page; you log in with the htpasswd creds you set above, and it lists “(no collections yet)”.

Step 3 — connect from iOS

This is the part that’s surprisingly easy. iOS treats CalDAV and CardDAV as native account types — same dialog as adding a Google or Yahoo account.

  1. Settings → Calendar → Accounts → Add Account → Other → Add CalDAV Account.
  2. Server: dav.example.com (just the hostname, no https:// prefix). Username: your htpasswd user. Password: the password.
  3. iOS auto-discovers the principal URL, the home set, and creates a default calendar called “you” (your username). Save.
  4. Open Calendar. Tap “Calendars” at the bottom. Your new account is in the list. Add events to it.
  5. Repeat: Settings → Contacts → Accounts → Add Account → Other → Add CardDAV Account. Same server, same creds.

Add an event on the iPhone. Within a couple of seconds you’ll see a new .ics file appear in /volume1/docker/radicale/data/collections/collection-root/<username>/<calendar-id>/. That’s it round-tripping. Edit the event, the file gets rewritten. Delete it, file disappears.

The mistakes that cost me time

  • Don’t skip the bcrypt flag on htpasswd. The default htpasswd algorithm is MD5-crypt, which Radicale will accept but newer versions warn about. Use htpasswd -B (bcrypt) and set htpasswd_encryption = bcrypt to match.
  • Reverse-proxy timeouts. CalDAV’s REPORT method on a busy calendar can take a few seconds. Caddy’s default timeouts are fine; nginx’s may not be. If you use nginx, set proxy_read_timeout 60s;.
  • Don’t share an account between calendars and contacts on iOS. Even though Radicale serves both from the same auth, iOS configures CalDAV and CardDAV as separate accounts. That’s normal — don’t fight it.
  • Make a “shared family” calendar properly. In Radicale, create a separate collection by hand: data/collections/collection-root/family/calendar/ with an .Radicale.props file marking it as a calendar. Then grant rights via the [rights] section in config. Or simpler: make a separate user for each family member, share the calendar across iOS devices manually.
  • Backups: rsync the data/ directory. One rsync -av to a NAS share or external drive nightly. Because everything is plain .ics and .vcf files, you can untar a backup from two years ago and read your address book without Radicale running.

What you give up vs iCloud

  • Calendar sharing with non-tech family. iCloud calendars can be shared by sending an invite link to anyone with an Apple ID. With Radicale you’d have to give them an account on your server. Not insurmountable, but a real friction.
  • The shiny iOS extras like “suggested events from email” — those are iCloud-side and they don’t work against a custom CalDAV server. Apps that auto-add events from confirmation emails won’t add to Radicale calendars.
  • Find My (for contacts). Sharing a location with a contact requires iCloud Contacts. Pure CardDAV doesn’t carry that. If location sharing matters, keep your iCloud Contacts account active alongside CardDAV — they coexist on iOS.

For the core “my calendar and address book are mine, on my hardware, restorable from rsync, and Apple can’t quietly merge a duplicate contact” outcome — Radicale on a NAS is two evenings of work followed by years of nothing breaking. That’s the trade I wanted.

Photo: Weekly planner with smartphone flat lay by ann-h-45017 on Pexels.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.