Skip to main content

How to Self-Host Baikal: CalDAV/CardDAV Server with Web Admin 2026

·OSSAlt Team
baikalcaldavcarddavcalendarself-hostingdocker2026

TL;DR

Baikal (GPL 3.0, ~2K GitHub stars, PHP) is a CalDAV/CardDAV server built on the sabre/dav library — the same library powering many hosting providers' calendar sync. Its key advantage over Radicale is the browser-based admin UI for managing users, calendars, and address books without touching config files. If you want CalDAV/CardDAV that non-technical users can manage via a web interface, Baikal is the right choice.

Key Takeaways

  • Baikal: GPL 3.0, ~2K stars, PHP — CalDAV/CardDAV with a web admin UI
  • sabre/dav: Battle-tested CalDAV/CardDAV library used by Nextcloud, ownCloud, and hosting providers
  • Web admin: Create users, calendars, and address books in a browser
  • SQLite or MySQL: Choice of database backend
  • vs Radicale: Baikal has a web UI; Radicale is even more minimal (config file only)
  • vs Nextcloud: Baikal is just calendar/contacts — no files, no apps overhead

Part 1: Docker Setup

# docker-compose.yml
services:
  baikal:
    image: ckulka/baikal:nginx
    container_name: baikal
    restart: unless-stopped
    ports:
      - "8800:80"
    volumes:
      - baikal_config:/var/www/baikal/config
      - baikal_specific:/var/www/baikal/Specific
    environment:
      - TZ=America/Los_Angeles

volumes:
  baikal_config:
  baikal_specific:
docker compose up -d

Visit http://your-server:8800/admin/ for first-time setup.


Part 2: First-Run Setup

  1. Admin Panel URL: https://cal.yourdomain.com/admin/
  2. Set admin password
  3. Database: Choose SQLite (simple) or MySQL (multi-user production)
  4. Click Save changes

With MySQL backend

services:
  baikal:
    image: ckulka/baikal:nginx
    environment:
      - BAIKAL_MYSQL=true
      - BAIKAL_MYSQL_HOST=db
      - BAIKAL_MYSQL_DBNAME=baikal
      - BAIKAL_MYSQL_USERNAME=baikal
      - BAIKAL_MYSQL_PASSWORD="${MYSQL_PASSWORD}"
    depends_on:
      - db

  db:
    image: mariadb:10.11
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: baikal
      MARIADB_USER: baikal
      MARIADB_PASSWORD: "${MYSQL_PASSWORD}"
      MARIADB_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD}"
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:

Part 3: HTTPS with Caddy

cal.yourdomain.com {
    reverse_proxy localhost:8800
}

Part 4: Create Users and Collections

Via web admin

  1. Log in at https://cal.yourdomain.com/admin/
  2. Users and resources → + Add user
    • Username: alice
    • Display name: Alice Smith
    • Email: alice@yourdomain.com
    • Password: set password
  3. Click the user → Add calendar
    • Calendar ID: personal
    • Display name: Personal
    • Description: Personal calendar
  4. Click the user → Add address book
    • Address book ID: contacts
    • Display name: Contacts

Via URL structure

After creating users, the CalDAV/CardDAV URLs are:

# Calendar (CalDAV):
https://cal.yourdomain.com/dav.php/principals/alice/
https://cal.yourdomain.com/dav.php/calendars/alice/personal/

# Contacts (CardDAV):
https://cal.yourdomain.com/dav.php/addressbooks/alice/contacts/

Part 5: iOS / macOS Setup

Calendar (CalDAV) — iOS

  1. Settings → Calendar → Accounts → Add Account → Other
  2. Add CalDAV Account
  3. Server: https://cal.yourdomain.com
  4. Username: alice
  5. Password: your password
  6. Description: Baikal Calendar

iOS auto-discovers calendars. After adding account, check Settings → Calendar → Accounts → your account — calendars should appear.

Contacts (CardDAV) — iOS

  1. Settings → Contacts → Accounts → Add Account → Other
  2. Add CardDAV Account
  3. Server: https://cal.yourdomain.com
  4. Username: alice, Password: your password

macOS

  1. System Settings → Internet Accounts → Add Account → Other
  2. Add both CalDAV Account and CardDAV Account
  3. Account type: Advanced → enter server URL manually

Part 6: Android with DAVx⁵

  1. Install DAVx⁵ from F-Droid (free) or Google Play
  2. + → Login with URL and username
  3. Base URL: https://cal.yourdomain.com/dav.php
  4. Username: alice, Password: your password
  5. DAVx⁵ discovers all calendars and address books
  6. Toggle each to enable sync

Part 7: Thunderbird

Calendar

  1. Calendar → New Calendar → On the Network → CalDAV
  2. URL: https://cal.yourdomain.com/dav.php/calendars/alice/personal/
  3. Username: alice, Password: your password

Contacts

  1. Address Book → New Address Book → CardDAV
  2. URL: https://cal.yourdomain.com/dav.php/addressbooks/alice/contacts/
  3. Username: alice, Password: your password

Part 8: Sharing Calendars

Baikal supports shared calendars via the admin UI:

  1. Admin → Users → alice → [Calendar] → Share
  2. Add user bob with read or read/write access
  3. Bob's device syncs to: https://cal.yourdomain.com/dav.php/calendars/alice/shared-calendar/

For family or team use, create a dedicated shared user:

User: family (password: shared-password)
Calendar: family-events
Address book: family-contacts

Everyone connects with username "family" to sync shared data.

Maintenance

# Update:
docker compose pull
docker compose up -d

# Backup SQLite:
docker cp baikal:/var/www/baikal/Specific/db/baikal.db \
  ./baikal-backup-$(date +%Y%m%d).db

# Backup all config and data:
tar -czf baikal-backup-$(date +%Y%m%d).tar.gz \
  $(docker volume inspect baikal_baikal_config --format '{{.Mountpoint}}') \
  $(docker volume inspect baikal_baikal_specific --format '{{.Mountpoint}}')

# Logs:
docker compose logs -f baikal

See also: Radicale (even more minimal, config-file only)

See all open source calendar tools at OSSAlt.com/categories/productivity.

Comments