This is a custom fork of tomsquest/docker-radicale that adds shared collection support using symlinks. This allows multiple users to see shared calendars alongside their private calendars, while maintaining read/write access for all shared calendars.
- Shared collections appear inside each user’s personal collection.
- Users retain their private calendars.
- Symlinks are created automatically on container startup.
SHARED_COLLECTIONSis configurable via environment variables.- Fully compatible with the upstream Radicale Docker image.
Family calendar setup:
- Users:
bob,alice,dad - Each user has a private calendar.
- A shared collection called
familycalendarcontains one calendar per family member:- /data/collections/collection-root/familycalendar/bob
- /data/collections/collection-root/familycalendar/alice
- /data/collections/collection-root/familycalendar/dad
- After symlink creation, users see shared calendars inside their personal collection:
- /data/collections/collection-root/bob/bob.ics # private
- /data/collections/collection-root/bob/familycalendar -> ../familycalendar # shared
- Same for
aliceanddad.
✅ All shared calendars are read/write, while private calendars remain isolated.
| Variable | Default | Description |
|---|---|---|
| UID | 1065 | UID to run Radicale inside container |
| GID | 100 | GID to run Radicale inside container |
| COLLECTION_ROOT | /data/collections/collection-root | Root folder for user collections |
| SHARED_ROOT | /data/collections/collection-shared | Root folder for shared collections |
| SHARED_COLLECTIONS | empty | Comma-separated list of shared collections to symlink for all users |
Example in docker-compose.yml:
environment:
- UID=1065
- GID=100
- COLLECTION_ROOT=/data/collections/collection-root
- SHARED_ROOT=/data/collections/collection-shared
- SHARED_COLLECTIONS=/data/collections/collection-root/dad/Dads-Work-cal
Folder Structure
Before Symlinks
/data/collections/collection-root/
├── bob/ 🧑
│ └── Private-cal 📅 private
├── alice/ 👩
│ └── Private-cal 📅 private
├── dad/ 👨
│ └── Private-cal 📅 private
│ └── Dads-Work-cal 📅 private
/data/collections/collection-shared
├── bob 📅 shared
├── alice 📅 shared
└── dad 📅 shared
└── family 📅 shared
After Symlinks
/data/collections/collection-root/
├── bob/ 🧑
│ ├─ Private-cal 📅 private
│ └─ familycalendar 🔗 ──> ../familycalendar # shared
│ └─ Dads-Work-cal ../dad/Dads-Work-cal # shared
├── alice/ 👩
│ ├─ Private-cal 📅 private
│ └─ familycalendar 🔗 ──> ../familycalendar # shared
│ └─ Dads-Work-cal ../dad/Dads-Work-cal # shared
├── dad/ 👨
│ ├─ Private-cal 📅 private
│ └─ Dads-Work-cal 📅 private
│ └─ familycalendar 🔗 ──> ../familycalendar # shared
Quick Start Diagram
┌─────────────────────────────┐
│ Environment Variables │
│-----------------------------│
│ UID=1065 │
│ GID=100 │
│ COLLECTION_ROOT=/data/... │
│ SHARED_ROOT=/data/collections/collection-shared|
└─────────────┬──────────────┘
│
▼
┌─────────────────────────────┐
│ Container Startup │
│-----------------------------│
│ 1️⃣ Run create_symlinks.py │
│ 2️⃣ Create symlinks for │
│ each user to shared │
│ collections │
└─────────────┬──────────────┘
│
▼
┌─────────────────────────────┐
│ Folder Structure After │
│ Symlinks │
│-----------------------------│
│ bob/ │
│ ├─ bob.ics 📅 private │
│ └─ familycalendar 🔗 ─────► /data/.../familycalendar/ │
│ alice/ │
│ ├─ alice.ics 📅 private │
│ └─ familycalendar 🔗 ─────► /data/.../familycalendar/ │
│ dad/ │
│ ├─ dad.ics 📅 private │
│ └─ familycalendar 🔗 ─────► /data/.../familycalendar/ │
└─────────────────────────────┘
│
▼
┌─────────────────────────────┐
│ Radicale & CalDAV Clients │
│-----------------------------│
│ Users can now access │
│ both private and shared │
│ calendars in the same view │
└─────────────────────────────┘
Assigning Rights to Shared Calendars
Creating symlinks is not enough—you must also grant access to the shared calendars in Radicale’s rights file.
Otherwise, users won’t see the shared collections in the GUI or CalDAV clients.
Example rights entries:
# Allow all users read/write access to shared collection "familycalendar"
[familycalendar]
user: .+
collection: familycalendar(|/.*)
permissions: RW
user: .+ means all authenticated users.
collection can include subfolders using (|/.*) syntax.
permissions: RW gives read/write access to the shared calendar(s).
After updating the rights file, restart the container or reload Radicale to apply changes:
docker-compose restart radicale
Setup Instructions
Build the custom image:
docker build -t radicale-custom -f Dockerfile.custom .
Run the container:
docker-compose up -d
Add shared collections under COLLECTION_ROOT if not already present.
Verify symlinks inside each user folder:
/data/collections/collection-root/bob/familycalendar -> ../familycalendar
Add new shared calendars: place the .ics files in the shared collection folder and restart the container or rerun the symlink script manually:
docker exec -it radicale su-exec 1065:100 python3 /usr/local/bin/create_symlinks.py
Notes / Best Practices
Keep SHARED_COLLECTIONS empty by default if you don’t want any pre-linked collections.
The symlink script is idempotent; safe to run multiple times.
Ensure correct UID/GID for permissions; otherwise, symlink creation may fail.
Users’ private calendars remain untouched.
Compatible with CalDAV clients like DavX5, Thunderbird, or Apple Calendar.
License
Same as the upstream tomsquest/docker-radicale
repository (MIT License).