Setup Home Calendar Service
We earn commissions when you shop through the links on this page, at no additional cost to you.
I stopped trusting Google Calendar years ago. Every calendar entry gets mined, every scheduling pattern analyzed, every meeting time leaked into shadow profiles. When I decided to self-host, a calendar service was non-negotiable. After testing both Nextcloud and Radicale, I settled on a lightweight Radicale instance paired with Nextcloud for occasional sync—the best of both worlds without the surveillance overhead.
Why Self-Host Your Calendar?
Calendar data is intimate. It reveals your routine, your priorities, your health appointments, your financial meetings. Cloud calendar vendors don't just store events; they timestamp your behavior, correlate it with email metadata, and sell insights to advertisers. Self-hosting gives you absolute control.
I also needed something that worked across devices without vendor lock-in. CalDAV (Calendaring Extensions to WebDAV) is the open standard that makes this possible. Any client that speaks CalDAV—whether it's GNOME Calendar, Thunderbird, Apple Calendar, or Nextcloud—can sync seamlessly with your home server.
Radicale: The Lightweight Choice
Radicale is a minimal CalDAV and CardDAV server written in Python. It's stateless, requires minimal resources, and scales from a Raspberry Pi to production environments. I prefer it over Nextcloud when calendars are the only requirement because it demands less CPU, memory, and storage.
Here's my Docker Compose setup for Radicale with persistent storage and basic authentication:
version: '3.8'
services:
radicale:
image: tomsquest/docker-radicale:latest
container_name: radicale
ports:
- "5232:5232"
volumes:
- ./radicale/data:/data
- ./radicale/config:/etc/radicale
environment:
- RADICALE_AUTHENTICATION_TYPE=htpasswd
- RADICALE_AUTHENTICATION_HTPASSWD_FILENAME=/etc/radicale/.htpasswd
- RADICALE_STORAGE_FILESYSTEM_FOLDER=/data/collections
restart: unless-stopped
networks:
- homelab
Before starting the container, create the authentication file:
mkdir -p radicale/config radicale/data
cd radicale/config
# Install htpasswd utility (on Ubuntu/Debian)
sudo apt-get install apache2-utils
# Create .htpasswd with your username (you'll be prompted for password)
htpasswd -c .htpasswd myusername
# Fix permissions
chmod 644 .htpasswd
Start the service with docker-compose up -d. Radicale will be available at http://localhost:5232. The initial login creates a default calendar automatically.
Configuring Client Access
Once Radicale is running, connecting clients is straightforward. I'll show you GNOME Calendar (Linux), Thunderbird (cross-platform), and iOS since those cover most of my devices.
GNOME Calendar: Open Settings → Online Accounts → Add Account → Select "CalDAV" → Enter:
- Server:
http://your-homelab-ip:5232 - Username: your Radicale username
- Password: your Radicale password
Thunderbird: Open Calendar view → Right-click calendar list → Create New Calendar → Choose "On the Network" → Add:
- Location:
http://your-homelab-ip:5232/your-username/calendar.ics/ - Authentication: Basic (username/password)
iOS (Apple Calendar): Settings → Mail → Accounts → Add Account → Other → Add CalDAV Account:
- Server:
your-homelab-ip - Port: 5232
- Username & Password: your Radicale credentials
Adding a Reverse Proxy for HTTPS
If you want calendar access from outside your home network, a reverse proxy with automatic TLS is essential. I use Caddy because it handles Let's Encrypt renewal painlessly.
Update your Docker Compose to use a shared network, then add Caddy:
version: '3.8'
services:
radicale:
image: tomsquest/docker-radicale:latest
container_name: radicale
ports:
- "127.0.0.1:5232:5232"
volumes:
- ./radicale/data:/data
- ./radicale/config:/etc/radicale
environment:
- RADICALE_AUTHENTICATION_TYPE=htpasswd
- RADICALE_AUTHENTICATION_HTPASSWD_FILENAME=/etc/radicale/.htpasswd
- RADICALE_STORAGE_FILESYSTEM_FOLDER=/data/collections
restart: unless-stopped
networks:
- homelab
caddy:
image: caddy:latest
container_name: caddy
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./caddy/data:/data
- ./caddy/config:/config
restart: unless-stopped
networks:
- homelab
networks:
homelab:
driver: bridge
Create a Caddyfile in your project root:
calendar.example.com {
reverse_proxy radicale:5232
# Optional: Basic auth layer
basicauth / {
myusername HASHED_PASSWORD_HERE
}
}
# Generate hashed password: caddy hash-password "your_password"
Replace calendar.example.com with your actual domain. Caddy will automatically fetch a certificate from Let's Encrypt and keep it renewed.
Nextcloud Integration (Optional)
If you already run Nextcloud for files, notes, and contacts, you get calendars built-in. But I prefer Radicale for its simplicity. However, Nextcloud and Radicale can coexist—Nextcloud can sync its calendars to Radicale as a backup.
In Nextcloud, install the "Sync my calendar" app, configure it to push to your Radicale instance, and you have automatic backup. This adds redundancy without the resource overhead of running Nextcloud as your primary calendar server.
Maintenance and Backups
Radicale stores calendars as ICS files in the data directory. Backup is trivial—just copy the entire radicale/data folder periodically:
#!/bin/bash
BACKUP_DIR="/mnt/backup/radicale"
TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
mkdir -p "$BACKUP_DIR"
cp -r radicale/data "$BACKUP_DIR/radicale-$TIMESTAMP"
# Keep last 30 days of backups
find "$BACKUP_DIR" -type d -name "radicale-*" -mtime +30 -exec rm -rf {} \;
I run this daily via cron. Since calendars are text-based ICS files, they compress exceptionally well—a year of events typically occupies under 100 KB.
Performance on Limited Hardware
Radicale runs comfortably on a Raspberry Pi 4 with under 50 MB RAM usage. GNOME Calendar syncs in milliseconds, and even bulk imports of 500+ events complete in seconds. The bottleneck is usually network latency, not the server.
If you're running on older hardware, keep the authentication method simple (htpasswd, not complex LDAP). Avoid enabling WebDAV explorers or plugins that scan collections on every request—stick to the CalDAV core functionality.
Privacy Considerations
Self-hosting calendar is a privacy win, but be mindful: your server's IP logs contain timing data. If threat modeling includes nation-state adversaries, add Cloudflare Tunnel or WireGuard before Caddy to obfuscate your origin IP. For most people, standard TLS is sufficient.
Also, encrypt calendar backups at rest. If backups live on a NAS or cloud storage, apply file-level encryption with tools like age or gpg.
Next Steps
Once your calendar is self-hosted, consider adding contacts (CardDAV) with the same Radicale instance—it supports both calendar and address book protocols. From there, integrate with a personal task manager like Vikunja or Plane for unified scheduling. Your calendar becomes the source of truth, not Google's.
Discussion