baikal-docker packages the Baikal CalDAV server for Docker
Provides a ready-to-go Baikal server, incl. docker-compose.yml & Systemd service file
At a glance
- What is it?
- baikal-docker publishes ready-to-run Baikal images in Apache and nginx flavours, with PHP 8.2 variants, multi-arch support and a companion compose file and systemd unit. It suits a self-hoster who wants a contacts and calendar server in one command, and it is a poor fit for anyone who needs a second application on the same host without dealing with the file permission model.
- Who is it for?
- baikal-docker is a good fit for a self-hoster who wants a CalDAV and CardDAV server running in a single command, since the Apache and nginx flavours, the PHP 8.2 variants, the multi-arch builds and the compose examples remove most of the packaging work. If you want a database or external storage instead, the examples directory includes MariaDB and AWS S3 variants to start from, and if you cannot run containers at all, the systemd guide covers a bare-metal route instead.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Baikal is, and why the container exists
Baikal is a Cal and CardDAV server, based on sabre/dav, that includes an administrative interface for easy management. It is developed by Net Gusto and fruux, and the upstream project lives at sabre.io/baikal. In plain terms, it speaks the two protocols that Apple devices, Thunderbird and most modern phones use to sync contacts and calendars, and it gives you a web admin panel instead of the usual configuration-file gymnastics. The container exists because packaging a PHP application with a web server in front of it is repetitive work, and the repository here does that work once for you. The readme puts it plainly, this dockerfile provides a ready-to-go Baikal server, and the project description adds a docker-compose.yml and a systemd service file to the same package. The topic list makes the breadth explicit, with apache, nginx, docker, multi-arch images and the four architecture names, so a reader can tell at a glance that this is a distribution repository rather than an application repository.
The tag scheme mixes versions, web servers and PHP releases
Choosing an image means reading three things at once, and the tag naming scheme encodes all three. The first is the Baikal version, and the readme says the same version naming scheme as Baikal themselves is followed. The second is the web server, since there are Apache and nginx variants, and the third is the PHP version, with php8.2 variants alongside the default ones. There is also a set of tags without a version, and these are described as weekly re-builds that include the latest base image with the most recent updates. Concretely, latest and apache are re-builds of the latest *-apache version, apache-php8.2 re-builds the latest *-apache-php8.2 version, and nginx and nginx-php8.2 do the same for the nginx line. The readme notes that the plain latest and apache-php8.2 style tags omit the version, and it links the weekly build workflow for each. What that means in practice is a choice between reproducibility and freshness. Pin 0.10.1-nginx-php8.2 and you get the same image every time, and pin latest and you get a weekly rebuild with a newer base image under you. The version list also shows how far back the tags go, with earlier versions available in the tags tab of the Docker Hub repository all the way back to version 0.2.7.
Running it takes one command, and the compose file is the better route
The quick reference in the readme is minimal. The following command will start Baikal:
docker run --rm -it -p 80:80 ckulka/baikal:nginxThe alternative is the provided compose example from the repository, and the readme points you at examples/docker-compose.yaml:
docker compose upAfter that you open http://localhost, or http://host-ip on another machine, in your browser and use Baikal. The examples directory carries more than the default, and the file list is a good map of the configuration decisions you will face. There is docker-compose.apache.yaml for the Apache flavour, docker-compose.mariadb.yaml if you want a database, docker-compose.awss3.yaml and docker-compose.custom-storage-location.yaml for putting the data somewhere other than a local volume, docker-compose.email.yaml and docker-compose.email-gmail.yaml for outbound mail, docker-compose.ssl.yaml for TLS, and docker-compose.localvolumes.yaml for using local folders instead of Docker volumes. The last of those exists for a specific reason, which the readme explains. If you want to use local folders instead of Docker volumes, you can follow the localvolumes example to avoid file permission issues.
Persistent data and the chown that runs on every start
Two paths in the image hold the data that matters, and they are the only thing you must back up. The image exposes the /var/www/baikal/Specific and /var/www/baikal/config folders, which contain the persistent data, and the readme says these folders should be part of a regular backup. The permissions issue is handled inside the container, by a startup script. When the container starts, the script at /docker-entrypoint.d/40-fix-baikal-file-permissions.sh, in a separate copy for Apache httpd and for nginx, ensures that the file permissions are correct. You can disable this behaviour by setting the environment variable BAIKAL_SKIP_CHOWN to any value, with FALSE given as the example. That variable name is worth remembering, because it is the escape hatch when a host filesystem with unusual ownership, such as a network share or a bind mount owned by another user, is used. The default behaviour of the container is to fix up ownership at startup, which is convenient on a plain Docker volume and a source of confusion everywhere else. That is the whole reason the localvolumes example exists, and it is also the reason a bind mount on a shared filesystem needs its own care.
Apache by default, nginx if you want fewer resources
The image variants are described with a preference stated openly. The default ckulka/baikal:<version> image is the de facto image and follows the official guidelines most closely using Apache httpd, and the readme says that if you are unsure about what your needs are, you probably want to use this one. With that being said, it is worth checking out the nginx variant, since it requires fewer resources and produces no warning messages out of the box. The Apache variant relies on Apache httpd and uses the official PHP image that is packaged with the Apache web server, and it ships with HTTPS support and self-signed certificates which can be replaced by user-provided certificates. It also sets Apache's ServerName and ServerAlias directives through environment variables to avoid the usual log warnings, with BAIKAL_SERVERNAME setting the global ServerName directive. The PHP 8.2 variants exist as separate tags for both web servers, so the practical matrix is web server times PHP version, each published for amd64, arm32v7, arm64v8 and i386, with the caveat that version 0.4.5 and older are only available for amd64 and version 0.9.0 and older do not support i386.
Testing, the systemd route and the guides you will need
The repository is not only images. There is a package manifest for a test project called ckulka-baikal-docker-tests whose test script runs cypress run, with a cypress open variant for interactive work, plus prettier, eslint and typescript tooling, and a cypress directory and a cypress.config.ts at the root. So the images are exercised by an end to end browser test against the running application rather than by a shell script that only checks the container starts. Alongside that, the repository carries a baikal.service file at the root and a systemd guide in the docs directory, which covers the case of somebody who wants a managed service rather than a compose project. The docs folder holds a set of task-specific guides, an email guide, a Home Assistant fix guide, an SSL certificate guide, the systemd guide and an Unraid installation guide, and that list is a good indication of the situations this image is used in. Two of them deserve a note. The SSL guide is what you need to replace the self-signed certificates, and the Unraid guide covers one of the popular NAS platforms where the container runs with its own permission model. The first language of the project is PHP, since the application it wraps is a PHP application, and the licence is MIT.
Editorial conclusion
baikal-docker is a good fit for a self-hoster who wants a CalDAV and CardDAV server running in a single command, since the Apache and nginx flavours, the PHP 8.2 variants, the multi-arch builds and the compose examples remove most of the packaging work. If you want a database or external storage instead, the examples directory includes MariaDB and AWS S3 variants to start from, and if you cannot run containers at all, the systemd guide covers a bare-metal route instead. Verify first that your architecture is covered, that the /var/www/baikal/Specific and /var/www/baikal/config paths are on persistent storage, and that the file permission fix on container start does not conflict with your host's ownership. The last push was on 2026-04-02 and the newest release is 0.10.1+hafix2 from 2025-07-31.
Frequently asked questions
How do I start Baikal with baikal-docker?
Run docker run --rm -it -p 80:80 ckulka/baikal:nginx, or use the provided examples/docker-compose.yaml from the repository and run docker compose up. You can then open http://localhost in your browser.
Which Docker tags should I use for baikal-docker?
Versioned tags such as 0.10.1-nginx-php8.2 pin the Baikal version, the web server and the PHP version together, while latest, apache, apache-php8.2, nginx and nginx-php8.2 are weekly re-builds of the latest matching version with a fresh base image.
What do I need to back up for baikal-docker?
The /var/www/baikal/Specific and /var/www/baikal/config folders, which hold the persistent data, and the readme says they should be part of a regular backup.
What does BAIKAL_SKIP_CHOWN do?
It disables the startup script that fixes Baikal file permissions inside the container. The readme says you can set it to any value, for example FALSE, which is useful when a host filesystem with unusual ownership causes problems.
Which architectures does baikal-docker support?
amd64, arm32v7, arm64v8 and i386, with the caveat that version 0.4.5 and older are only available for amd64, and version 0.9.0 and older do not support i386.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ckulka-baikal-docker)Was this useful?