Baikal on Ubuntu 24.04 on Azure User Guide
Overview
Baikal is an open source self-hosted CalDAV and CardDAV server built on the proven Sabre/dav library. It lets you sync calendars and contacts across all of your devices using the open CalDAV and CardDAV standards, while keeping that data private on infrastructure you control. The cloudimg image runs Baikal 0.11 behind nginx, with PHP FPM 8.3 and OPcache enabled. Backed by 24/7 cloudimg support.
Baikal stores its data in SQLite, so the appliance is fully self-contained: there is no separate database server to install, secure or back up. The configuration, the SQLite database and the DAV data live under /var/www/baikal on a dedicated, independently resizable Azure data disk, so you can grow your calendar and contact store without touching the operating system disk.
The browser setup wizard is already completed in the image, so there is no first-run configuration to step through. The Baikal administrator password and the application encryption key are generated on the first boot of every deployed VM, and both the admin web console and the CalDAV/CardDAV account are set to that same per-VM password. Two VMs deployed from the same image never share credentials. The initial administrator password is written to /root/baikal-credentials.txt with mode 0600 so that only the root user can read it.

What is included:
- Baikal 0.11 (sabre/dav) with the setup wizard already completed
- nginx + PHP FPM 8.3 with OPcache and every PHP extension Baikal requires
- Self-contained SQLite storage on a dedicated Azure data disk at
/var/www/baikal, separate from the OS disk and re-provisioned with every VM - Per-VM administrator password and encryption key generated at first boot, stored in a root-only file
- CalDAV/CardDAV well-known service discovery redirects preconfigured
- 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point for personal and small-team calendar and contact sync; scale up for larger user counts. NSG inbound: allow 22/tcp from your management network and 80/tcp (plus 443/tcp once you enable HTTPS) from the networks your client devices use.
Step 1 — Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Baikal by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Review the dedicated data disk on the Disks tab, then Review + create → Create. First boot initialisation takes approximately one minute after the VM starts.
Step 2 — Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name baikal \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name baikal --port 80 --priority 1010
Step 3 — Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 — Verify the Baikal service
The web stack is two systemd services: nginx and PHP FPM. Confirm both are active:
systemctl is-active nginx php8.3-fpm
Both lines should read active. Confirm nginx is listening on port 80 and that the dedicated data disk holding the configuration and SQLite database is mounted:
ss -tlnp 2>/dev/null | grep ':80 ' || sudo ss -tlnp | grep ':80 '
df -h /var/www/baikal | tail -1
Confirm the Baikal admin console is being served locally:
curl -s -o /dev/null -w 'Baikal admin HTTP %{http_code}\n' http://127.0.0.1/admin/
An HTTP 200 response confirms the application is up.

Step 5 — Retrieve your credentials
The administrator credentials generated on the first boot of your VM are stored in a root-only file. Retrieve them with the following command, which prints the Baikal administrator user name and password for this specific VM:
sudo cat /root/baikal-credentials.txt
The file lists the administrator user name (admin), the generated password, the admin console URL and the CalDAV/CardDAV endpoint URL. Store the password in your password manager and treat the file as sensitive.

Step 6 — Verify DAV authentication
The DAV endpoint requires authentication and accepts the generated administrator password. The first command should report 401 and the second 207:
curl -s -o /dev/null -w 'anonymous PROPFIND HTTP %{http_code}\n' -X PROPFIND -H 'Depth: 0' http://127.0.0.1/dav.php/
PASS=$(sudo grep '^baikal.admin.pass=' /root/baikal-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'authenticated PROPFIND HTTP %{http_code}\n' -X PROPFIND --digest -u admin:$PASS -H 'Depth: 0' http://127.0.0.1/dav.php/

Step 7 — First login to the admin console
Open a web browser and navigate to http://<vm-public-ip>/admin/. You are presented with the Baikal Web Admin sign-in page. Sign in with the user name admin and the password from /root/baikal-credentials.txt.
The dashboard summarises the running system: the Baikal version, which of the Web admin, CalDAV and CardDAV services are enabled, and statistics for users, calendars, events, address books and contacts.

Step 8 — Create users, calendars and address books
Open Users and resources in the top navigation to manage Baikal accounts. The image ships with a single administrator account. Use + Add user to create an account for each person who will sync calendars and contacts, and use the Calendars and Address Books buttons on each user row to create and manage their resources.

Each user authenticates to the CalDAV and CardDAV endpoints with the user name and password you set here.
Step 9 — Connect CalDAV and CardDAV clients
Point any CalDAV or CardDAV client (the calendar and contacts apps on iOS, macOS, Android with DAVx5, Thunderbird, Evolution, and others) at your VM to sync calendars and contacts. The base DAV endpoint is:
http://<vm-public-ip>/dav.php/
Most clients also support automatic service discovery through the well-known URLs /.well-known/caldav and /.well-known/carddav, which this image redirects to the DAV endpoint. Enter the user name and password of the Baikal account you want to sync. Because this is your own self-hosted VM, your calendar and contact data never leaves infrastructure you control.

Enabling HTTPS
For production use you should serve Baikal over HTTPS so that client credentials and your calendar and contact data are encrypted in transit. Point a DNS A record at the VM's public IP address, then install a certificate with Certbot (replace the domain):
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com
After enabling HTTPS, point your CalDAV and CardDAV clients at the https:// URL instead, open 443/tcp in the NSG, and restrict or close inbound port 80.
Backup and maintenance
All Baikal state lives under /var/www/baikal on the dedicated Azure data disk: the configuration in config/baikal.yaml and the SQLite database under Specific/db. Because the data disk is separate from the OS disk, the simplest backup is an Azure disk snapshot:
az snapshot create --resource-group <your-rg> --name baikal-data-backup --source <data-disk-id>
For a file-level backup you can instead copy the config directory and the Specific/db/db.sqlite database file to object storage on a schedule. Apply operating system security updates with sudo apt update && sudo apt upgrade; the nginx and PHP FPM services restart cleanly, and Baikal resumes serving immediately because all state is on the persistent data disk.
Support
This image is backed by 24/7 cloudimg support. Contact us by email and chat for deployment help, client configuration questions, upgrade guidance, or storage administration. Baikal itself is open source software licensed under the GNU GPL version 3.
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.