Baikal
Overview
Baikal is a lightweight, self-hosted CalDAV and CardDAV server built on the sabre/dav library. It syncs calendars, tasks and contacts across phones, laptops and mail clients using open standards: iOS and macOS Calendar and Contacts, Android with DAVx5, Thunderbird, Evolution and others. A small web admin console manages users, calendars and address books. Everything is stored in SQLite, so there is no database server to run.
This guide covers deploying and using Baikal 0.12.1 on Ubuntu 24.04 from SecureAnyCloud on Microsoft Azure.
What the SecureAnyCloud image adds:
- HTTPS from the first boot. nginx serves Baikal on port 443 with a certificate generated on your VM's first boot. Port 80 redirects to HTTPS, and requests for a host name that the VM does not serve are dropped.
- A password unique to your VM. The web
adminand the CalDAV/CardDAV account admin share one password, generated on first boot and written to/root/baikal-credentials.txt(root only). The image ships with random password hashes that match no password. nginx and PHP-FPM refuse to start until first boot has finished. - No setup wizard. Upstream Baikal's
/admin/install/database step answers without a login until the installer is disabled. On this image the configuration is written in advance, the installer is disabled (Specific/INSTALL_DISABLED) and nginx returns 404 for/admin/install/. - The admin console security fix included. Baikal 0.12.0 and earlier let any signed-in CalDAV user take over the admin console by renaming a calendar or address book to HTML (advisory GHSA-j44x-cj7p-vx2w). Baikal 0.12.1 fixes this upstream, and the image ships 0.12.1 unmodified. Every build proves the fix. It renames a calendar to an HTML payload over CalDAV and checks that the admin pages show the name as text. It also checks that the same test does catch the payload when the escaping is switched off.
- Hardened defaults. nginx and PHP-FPM are blocked from the Azure Instance Metadata Service and the Azure wire server. PHP is handed the configured host name and the real client address from the connection, never values a client sends. Cross-site form posts are refused.
- A dedicated data disk.
/var/www/baikal(code, configuration and the SQLite database) is its own 20 GiB Azure managed data disk that you can grow or snapshot independently. - Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
- 24/7 SecureAnyCloud support
What is on the image: Baikal 0.12.1 (the official release zip, checksum verified, sabre/dav 4.7.1), nginx 1.24, PHP 8.3 FPM with OPcache, SQLite, Ubuntu 24.04 LTS, cloud-init and the Azure Linux Agent. Build tools used only during the image build (such as unzip) are removed, and no compiler is installed.
Default user: the admin user you choose (examples use azureuser). Architecture: x64, Gen2. Recommended size: Standard_B2s.
Prerequisites
Before you deploy, make sure you have:
- An Azure subscription, and a subscription to this offer in Azure Marketplace.
- An SSH public key or a password for the VM's admin user.
- A network security group that allows TCP 22 (SSH) from your admin network. It must also allow TCP 443 (Baikal) and TCP 80 (redirects to HTTPS) from the networks your calendar and contact clients use.
Deploy the virtual machine
In Azure Marketplace, search for Baikal, select the SecureAnyCloud offer and click Create.
On the Basics tab, choose your subscription, resource group and region, and name the VM. Choose Standard_B2s, because Baikal itself is light, and set the administrator account. Under Inbound port rules, allow SSH (22), HTTP (80) and HTTPS (443).
Keep the 20 GiB data disk on the Disks tab, because it holds Baikal and its data. Click Review + create, then Create.
To deploy with the Azure CLI instead, replace the values in angle brackets:
az vm image terms accept --urn sac1647283583153:baikal-ubuntu-24-04:default:latest
az vm create --resource-group <your-resource-group> --name baikal \
--image sac1647283583153:baikal-ubuntu-24-04:default:latest \
--size Standard_B2s --admin-username azureuser --ssh-key-values ~/.ssh/id_rsa.pub
az vm open-port --resource-group <your-resource-group> --name baikal --port 80,443 --priority 900First boot takes well under a minute after the VM is running.
Connect to your VM
Connect over SSH with the admin user you chose:
ssh azureuser@<vm-public-ip>Check the services
First boot generates the certificate and the password, and then nginx and PHP-FPM start. Run:
systemctl is-active nginx php8.3-fpm baikal-firstboot
sudo test -f /var/lib/sac/data/baikal-firstboot.done && echo FIRSTBOOT_DONEAll three units report active, and the first-boot marker is present:
active active active FIRSTBOOT_DONEOnly SSH and nginx listen on network ports. PHP-FPM uses a local socket:
sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0.5' | sort0.0.0.0:22 users:(("sshd",...)) 0.0.0.0:443 users:(("nginx",...)) 0.0.0.0:80 users:(("nginx",...)) [::]:22 users:(("sshd",...)) [::]:443 users:(("nginx",...)) [::]:80 users:(("nginx",...))Confirm that Baikal and its SQLite database live on the dedicated data disk:
df -h /var/www/baikal | tail -1/dev/sdc 20G 12M 19G 1% /var/www/baikalGet your URLs and password
Read the credentials file. Only root can read it:
sudo cat /root/baikal-credentials.txtThe file looks like this:
# Baikal 0.12.1 - generated on first boot by baikal-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret.
# The same password signs in to the web admin and to CalDAV/CardDAV as user admin. baikal.admin.url=https://52.147.201.16/admin/ baikal.dav.url=https://52.147.201.16/dav.php/ baikal.admin.user=admin baikal.admin.pass=<BAIKAL_ADMIN_PASSWORD>
# The certificate is self signed (minted on this instance's first boot); port 80 redirects to https. # Change the name Baikal is served as:
sudo baikal-set-hostname <your-dns-name>
# User guide: https://secureanycloud.com/stacks/baikal/The URLs use the VM's public IP address from the Azure Instance Metadata Service, or the private address if the VM has no public IP. The certificate names the public and private addresses.
Open the web admin at the address in baikal.admin.url. Its pages link to that configured name, so a sign-in started at another name is treated as cross-site and refused (HTTP 403). To serve Baikal under your own DNS name, see Step 9.
Sign in to the web admin
Open the baikal.admin.url in your browser. The certificate is self-signed, so your browser asks you to confirm it the first time. Alternatively, install your own certificate (Step 9).
Sign in as admin with the password from Step 4.
The dashboard shows the Baikal version, which services are on (web admin, CalDAV, CardDAV) and counts of users, calendars, events, address books and contacts. Your browser also asks GitHub for the latest Baikal release and may show a newer version there. The server itself makes no such call.
Users, calendars and address books
Open Users and resources. The image ships with one account, admin, with a default calendar and a default address book.
Use + Add user to create an account for each person who will sync. Each user signs in to CalDAV and CardDAV with the user name and password you set here.
Use Calendars and Address Books on each user row to manage that user's collections.
Open System Settings to control CalDAV and CardDAV, the time zone, the invite sender address, the authentication type and the web admin password.
A CalDAV and CardDAV round trip from the command line
The following block signs in with the VM's password over HTTPS and lists the admin calendars. It creates an event and a contact, reads them back and deletes them. It also shows that a wrong password is refused. The block passes the password to curl on standard input, so it never appears in a process list or your shell history:
sudo bash -c ' set -e F=/root/baikal-credentials.txt P=$(grep "^baikal.admin.pass=" $F | cut -d= -f2-) H=$(grep "^baikal.dav.url=" $F | cut -d= -f2- | sed -E "s#https://([^/]+)/.*#\1#") D="https://$H/dav.php"; R="--resolve $H:443:127.0.0.1" dav() { printf "user = \"%s\"\n" "$1" | curl -K - --digest -sk $R "${@:2}"; } want() { printf "%-16s %s\n" "$1" "$2"; [ "$2" = "$3" ] || { echo "FAIL: expected $3"; exit 1; }; } has() { case "$2" in *"$3"*) printf "%-16s %s\n" "$1" "$3";; *) echo "FAIL: $1"; exit 1;; esac; } T=$(mktemp -d); trap "rm -rf $T" EXIT printf "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//sac//guide//EN\r\nBEGIN:VEVENT\r\nUID:guide-event\r\nDTSTAMP:20261020T120000Z\r\nDTSTART:20261021T090000Z\r\nDTEND:20261021T100000Z\r\nSUMMARY:Guide test event\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n" > $T/guide-event.ics printf "BEGIN:VCARD\r\nVERSION:3.0\r\nUID:guide-card\r\nFN:Guide Test Contact\r\nEND:VCARD\r\n" > $T/guide-card.vcf want "no login:" "HTTP $(curl -sk $R -o /dev/null -w %{http_code} -X PROPFIND -H "Depth: 0" $D/)" "HTTP 401" want "wrong password:" "HTTP $(dav "admin:not-the-password" -o /dev/null -w %{http_code} -X PROPFIND -H "Depth: 0" $D/)" "HTTP 401" has "calendar home:" "$(dav "admin:$P" -X PROPFIND -H "Depth: 1" $D/calendars/admin/)" "/dav.php/calendars/admin/default/" want "PUT event:" "HTTP $(dav "admin:$P" -X PUT -H "Content-Type: text/calendar" --data-binary @$T/guide-event.ics -o /dev/null -w %{http_code} $D/calendars/admin/default/guide-event.ics)" "HTTP 201" has "GET event:" "$(dav "admin:$P" $D/calendars/admin/default/guide-event.ics)" "SUMMARY:Guide test event" want "PUT contact:" "HTTP $(dav "admin:$P" -X PUT -H "Content-Type: text/vcard" --data-binary @$T/guide-card.vcf -o /dev/null -w %{http_code} $D/addressbooks/admin/default/guide-card.vcf)" "HTTP 201" has "GET contact:" "$(dav "admin:$P" $D/addressbooks/admin/default/guide-card.vcf)" "FN:Guide Test Contact" want "DELETE event:" "HTTP $(dav "admin:$P" -X DELETE -o /dev/null -w %{http_code} $D/calendars/admin/default/guide-event.ics)" "HTTP 204" want "DELETE contact:" "HTTP $(dav "admin:$P" -X DELETE -o /dev/null -w %{http_code} $D/addressbooks/admin/default/guide-card.vcf)" "HTTP 204" 'no login: HTTP 401 wrong password: HTTP 401 calendar home: /dav.php/calendars/admin/default/ PUT event: HTTP 201 GET event: SUMMARY:Guide test event PUT contact: HTTP 201 GET contact: FN:Guide Test Contact DELETE event: HTTP 204 DELETE contact: HTTP 204Connect your calendar and contacts apps
Use the baikal.dav.url from Step 4 as the server address, together with the Baikal user name and password:
Client Where to add it Server address
iOS / iPadOS Settings, Calendar (or Contacts), Accounts, Add Account, Other, Add CalDAV (or CardDAV) Account <your-domain> or the public IP address
macOS Calendar (or Contacts), Settings, Accounts, +, Other CalDAV (CardDAV) Account, Manual https://<your-domain>/dav.php/
Android DAVx5, Login with URL and user name https://<your-domain>/dav.php/
Thunderbird New Calendar, On the Network https://<your-domain>/dav.php/
Clients that discover the server automatically use the well-known addresses, which redirect to the DAV endpoint:
H=$(sudo grep '^baikal.dav.url=' /root/baikal-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/.*#\1#')
curl -sk -o /dev/null -w '.well-known/caldav -> %{http_code} %{redirect_url}\n' --resolve "$H:443:127.0.0.1" "https://$H/.well-known/caldav"
curl -sk -o /dev/null -w '.well-known/carddav -> %{http_code} %{redirect_url}\n' --resolve "$H:443:127.0.0.1" "https://$H/.well-known/carddav"
curl -s -o /dev/null -w 'http:// -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/admin/" [ "$(curl -sk -o /dev/null -w '%{redirect_url}' --resolve "$H:443:127.0.0.1" "https://$H/.well-known/caldav")" = "https://$H/dav.php/" ].well-known/caldav -> 301 https://52.147.201.16/dav.php/ .well-known/carddav -> 301 https://52.147.201.16/dav.php/ http:// -> 301 https://52.147.201.16/admin/Most phones and desktop clients refuse a self-signed certificate for sync, or ask you to trust it once. For everyday use, give the VM a DNS name and a certificate that your devices trust (Step 9).
Your own DNS name and certificate
Point a DNS record at the VM. A static public IP keeps the address stable, and Azure can also give the VM a <label>.<region>.cloudapp.azure.com name.
Then set the name that Baikal is served as. This mints a new self-signed certificate for the name, updates nginx and the URLs in /root/baikal-credentials.txt, and keeps the name across reboots:
sudo baikal-set-hostname <your-domain>To use a certificate from a public or internal certificate authority instead (for example one issued by Let's Encrypt for <your-domain>), copy it over the generated pair and reload nginx. Running baikal-set-hostname again replaces it with a self-signed one:
sudo install -m 0644 <your-domain>.crt /etc/ssl/baikal/baikal.crt
sudo install -m 0600 <your-domain>.key /etc/ssl/baikal/baikal.key
sudo nginx -t && sudo systemctl reload nginxSecurity checks
Confirm that the setup wizard cannot be reached and that the configured version matches the installed one. A mismatch would open Baikal's upgrade page, which asks for no login.
H=$(sudo grep '^baikal.admin.url=' /root/baikal-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/.*#\1#')
curl -sk -o /dev/null -w '/admin/install/ -> HTTP %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/admin/install/" ls /var/www/baikal/Specific/INSTALL_DISABLED grep -E 'BAIKAL_VERSION"' /var/www/baikal/Core/Distrib.php
sudo grep configured_version /var/www/baikal/config/baikal.yaml [ "$(curl -sk -o /dev/null -w '%{http_code}' --resolve "$H:443:127.0.0.1" "https://$H/admin/install/")" = "404" ]/admin/install/ -> HTTP 404 /var/www/baikal/Specific/INSTALL_DISABLED define("BAIKAL_VERSION", "0.12.1"); configured_version: '0.12.1'The upstream fix for GHSA-j44x-cj7p-vx2w escapes user-supplied names wherever the admin console shows them. The edit page title, for example, escapes the calendar or address book name in four places:
grep -c 'htmlspecialchars($this->modelInstance()->label())' /var/www/baikal/Core/Frameworks/Formal/Form.php4The VM generated the certificate itself, and it names the VM's own addresses:
H=$(sudo grep '^baikal.admin.url=' /root/baikal-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/.*#\1#')
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -subject -ext subjectAltNamesubject=CN = 52.147.201.16, O = sac X509v3 Subject Alternative Name: IP Address:52.147.201.16, IP Address:10.0.0.11, IP Address:127.0.0.1, DNS:localhostNeither nginx nor PHP-FPM can reach the Azure Instance Metadata Service or the wire server:
systemctl show nginx php8.3-fpm -p Id -p IPAddressDenyIPAddressDeny=169.254.169.254/32 168.63.129.16/32 Id=nginx.service IPAddressDeny=169.254.169.254/32 168.63.129.16/32 Id=php8.3-fpm.servicenginx hands PHP the configured host name and the client address from the connection, never values a client sends:
grep -E 'fastcgi_param (HTTP_HOST|HTTP_X_FORWARDED_FOR|HTTP_X_REAL_IP|HTTP_CLIENT_IP)' /etc/nginx/sites-available/sac-baikalfastcgi_param HTTP_HOST $baikal_host; fastcgi_param HTTP_X_FORWARDED_FOR $remote_addr; fastcgi_param HTTP_X_REAL_IP $remote_addr; fastcgi_param HTTP_CLIENT_IP $remote_addr;nginx also refuses a form post or a DAV change whose Origin is another website (HTTP 403). CalDAV and CardDAV apps send no Origin and are unaffected.
Changing passwords
Baikal keeps two passwords, and first boot set both to the same value. Change each one separately:
- Web admin password: open System Settings, enter a new Admin password and its confirmation, then select Save changes.
- CalDAV/CardDAV password of the
adminaccount: open Users and resources, select Edit on theadminrow, then enter a new password.
After changing them, update or delete baikal.admin.pass in /root/baikal-credentials.txt so that it does not hold an old password. Give each person their own Baikal user rather than sharing admin.
Backup and maintenance
All Baikal state is under /var/www/baikal on the data disk: the configuration in config/baikal.yaml and the database in Specific/db/db.sqlite.
The simplest backup is an Azure snapshot of that disk (or Azure Backup for the VM). For a file-level copy that is safe while Baikal is running, use SQLite's online backup:
sudo sqlite3 /var/www/baikal/Specific/db/db.sqlite ".backup '<backup-dir>/baikal-$(date +%F).sqlite'"
sudo cp /var/www/baikal/config/baikal.yaml <backup-dir>/Operating system security updates install automatically. Run sudo apt-get update && sudo apt-get upgrade to apply everything else. nginx and PHP-FPM restart cleanly, and Baikal keeps all of its data.
Component Path
Baikal /var/www/baikal (data disk)
Configuration /var/www/baikal/config/baikal.yaml
Database /var/www/baikal/Specific/db/db.sqlite
nginx site /etc/nginx/sites-available/sac-baikal
Certificate and key /etc/ssl/baikal/
First boot script /usr/local/sbin/baikal-firstboot.sh
Host name helper /usr/local/sbin/baikal-set-hostname
Credentials /root/baikal-credentials.txt (mode 0600)
Security recommendations
- Restrict network access. Allow port 22 from your admin network only, and ports 80 and 443 only from the networks your devices sync from.
- Use your own name and certificate. Set your own DNS name and a certificate that your devices trust (Step 9).
- Rotate shared passwords. Change the passwords if they may have been shared, and give each person their own Baikal user (Step 11).
- Keep the VM patched and backed up. Keep the operating system patched and snapshot the data disk regularly.
Support and licensing
Baikal is open source under the GNU General Public License version 3, and there is no per-user or per-CPU licence fee. The image price covers SecureAnyCloud's hardening, first-boot setup and support.
- Email: sales@secureanycloud.com
- Website: https://secureanycloud.com
- Support: 24/7, with a 24-hour response SLA
Deploy on Azure
Launch Baikal 0.12.1 on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Baikal is an open source, self-hosted CalDAV and CardDAV server built on the Sabre/dav library. It syncs calendars and contacts across all of your devices using the open CalDAV and CardDAV standards, and keeps that data private on infrastructure you control.
This image runs Baikal behind nginx, with PHP FPM 8.3 and OPcache enabled.
What you get:
- A self-contained appliance. Baikal stores its data in SQLite, so there is no separate database server to install, secure or back up.
- A dedicated data volume. The configuration, the SQLite database and the DAV data live under
/var/www/baikalon a dedicated, independently resizable EBS volume. You can grow your calendar and contact store without touching the operating system disk. - No setup wizard. The browser setup wizard is already completed in the image, so there is no first-run configuration to step through.
- Per-instance credentials. The Baikal administrator password and the application encryption key are generated on the first boot of every deployed instance. The admin web console and the CalDAV/CardDAV account use that same per-instance password, so two instances launched from the same Amazon Machine Image never share credentials.
- A root-only credentials file. The initial administrator password is written to
/root/baikal-credentials.txtwith mode 0600, so only the root user can read it. - 24/7 SecureAnyCloud support
Prerequisites
Before you deploy this image, make sure you have:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network and inbound ports 80 and 443 from the networks your client devices will use
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Launch the instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Baikal. Select the SecureAnyCloud listing, choose Select, then choose Continue on the subscription summary.
Pick an instance type of m5.large or larger. Choose your EC2 key pair under Key pair (login). Leave the root and data volumes at their default sizes or larger.
Under Network settings, select your VPC and subnet. Create or select a security group that allows inbound port 22 from your management network and inbound ports 80 and 443 from the networks your client devices use.
Select Launch instance. First-boot initialisation takes approximately one minute after the instance state becomes Running and the status checks pass.
Launch the instance from the AWS CLI
Run the following command to launch an instance from the SecureAnyCloud Baikal Marketplace AMI into an existing subnet and security group.
Replace <ami-id> with the AMI ID shown on the Marketplace listing and <key-name> with your EC2 key pair name. Replace <subnet-id> with your subnet ID and <security-group-id> with a security group that opens ports 22, 80 and 443 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":12,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=baikal-01}]'On success, the command prints a JSON document. Note the instance ID. Once the instance is running, retrieve its public address with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.
Connect and retrieve the initial credentials
Connect over SSH with the key pair you selected and the public IP address from Step 2. The SSH login user depends on the operating system of the AMI variant you launched. For Baikal 0.11 on Ubuntu 24.04, the login user is ubuntu:
Connect with ssh -i <path-to-key.pem> ubuntu@<instance-public-ip>.
First boot stores the administrator credentials in a root-only file. Run the following command to print the Baikal administrator user name and password for this instance:
sudo cat /root/baikal-credentials.txtThe file lists the admin administrator user name, 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.
Verify the Baikal service
The web stack is two systemd services: nginx and PHP FPM. Confirm that both are active:
systemctl is-active nginx php8.3-fpmBoth lines read active. Confirm that nginx is listening on port 80:
ss -tlnp 2>/dev/null | grep ':80 ' || sudo ss -tlnp | grep ':80 'Confirm that the dedicated data volume holding the configuration and SQLite database is mounted:
df -h /var/www/baikal | tail -1Confirm that the Baikal admin console is 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 that the application is up.
Next, confirm that the DAV endpoint requires authentication and accepts the generated administrator password. The first command reports 401 and the second reports 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/Sign in to the admin console
Open a web browser and go to http://<instance-public-ip>/admin/. The Baikal Web Admin sign-in page opens. Sign in with the user name admin and the password from /root/baikal-credentials.txt.
The dashboard summarises the running system. It shows the Baikal version, which of the Web admin, CalDAV and CardDAV services are enabled, and statistics for users, calendars, events, address books and contacts.
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. 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.
Connect CalDAV and CardDAV clients
Point any CalDAV or CardDAV client at your instance to sync calendars and contacts. Examples are the calendar and contacts apps on iOS and macOS, Android with DAVx5, Thunderbird and Evolution. The base DAV endpoint is:
http://<instance-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 instance, your calendar and contact data never leaves infrastructure you control.
Enable HTTPS with Let's Encrypt
For production, 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 instance's public IP address, then install Certbot:
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginxRun Certbot against your own domain name and email address, and follow the prompts to obtain and install the certificate. Then point your CalDAV and CardDAV clients at the https:// URL.
After enabling HTTPS, restrict inbound port 80 to redirect-only or close it at the security group. Leave port 443 open to your client networks.
Backup and maintenance
All Baikal state lives under /var/www/baikal on the dedicated data volume: the configuration in config/baikal.yaml and the SQLite database under Specific/db. The data volume is a separate EBS volume, so the simplest backup is a point-in-time EBS snapshot:
aws ec2 create-snapshot --volume-id <data-volume-id> --description "Baikal data backup"To find the data volume ID, describe the instance's block device mappings. For a file-level backup, 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-get update && sudo apt-get upgrade. The nginx and PHP FPM services restart cleanly. Baikal resumes serving immediately, because all state is on the persistent data volume.
Support
SecureAnyCloud publishes and supports this image. For deployment help, client configuration questions, upgrade guidance or storage administration, contact SecureAnyCloud support by email or chat. Baikal itself is open source software licensed under the GNU GPL version 3.
Deploy on AWS
Launch Baikal on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com