Pimsync-DOCKERIZED
Pimsync - a command line tool to synchronise calendars and contacts between different storages, including CalDAV and CardDAV. Pimsync is a successor and reimplementation of Vdirsyncer, and is free and open source software. DOCKERIZED!
Disclaimer: I am just the maintainer of this docker container, I did not write the software. Visit the Official Pimsync Website or the Official Sourcehut Repository to thank the author(s)! :)
Pimsync is a command line tool to synchronise calendars and contacts between different storages, including CalDAV and CardDAV. Pimsync is a successor and reimplementation of Vdirsyncer, and is free and open source software.
Pimsync synchronises documentation across storages. Currently supported storages are:
- CalDAV: HTTP extension which provides read and write access to calendars on servers.
- CardDAV: HTTP extension which provides read and write access to address books on servers.
- Vdir: Convention for storing calendars and address books in local directories using standardised and well-documented formats.
- WebCal: Convention for exposing a calendar or event read-only using HTTP.
Common use cases include:
- Synchronising a CalDAV or CardDAV server with a local directory. Local data can then be accessed and manipulated by a variety of programs, none of which have to know or worry about synchronisation, network connectivity, or remote servers. The changes are then synced back to the server periodically.
- Synchronising from server to a local directory with the intent of keeping back-ups using a tool that backs up local directory trees.
- Synchronising data between two different CalDAV or CardDAV servers.
Pimsync is configured via a configuration file. It can then be used to synchronise data once (via the pimsync sync command) or to keep data synchronised continuously (via the pimsync daemon command).
Official Website: https://pimsync.whynothugo.nl/
Official Sourcehut Repository: https://git.sr.ht/~whynothugo/pimsync
Docs: https://pimsync.whynothugo.nl/
My Github Repository: https://github.com/Bleala/Pimsync-DOCKERIZED
Docker Hub: https://hub.docker.com/r/bleala/pimsync
Github Container Registry: https://github.com/-/bleala/packages/container/package/pimsync
Quay.io: https://quay.io/repository/bleala/pimsync
I built this image based on Alpine Linux and compiled pimsync during the container build.
There will always be a latest image and the semantic versioning images:
| Tag | Content |
|---|---|
| Latest | Contains the latest stable version |
| x.x.x | Contains the Pimsync and Alpine versions mentioned at the bottom of the page and in the release notes |
I am using semantic versioning for this image. For all supported architectures there are the following versioned tags:
- Latest
- Major (1)
- Minor (1.0)
- Patch (1.0.0)
There are also several platforms supported:
Platforms:
- linux/amd64
- linux/arm64
To ensure the authenticity and integrity of my images, all bleala/pimsync images pushed to Docker Hub, GitHub Container Registry and Quay.io (and maybe more in the future) are signed using Cosign.
I use a static key pair for signing. The public key required for verification, cosign.pub, is available in the root of this GitHub repository:
- Public Key:
cosign.pub
You can verify the signature of an image to ensure it hasn't been tampered with and originates from me.
-
Install Cosign: If you don't have Cosign installed, follow the official installation instructions: Cosign Installation Guide.
-
Obtain the Public Key: Download the
cosign.pubfile from this repository or clone the repository to access it locally. -
Verify the Image: Use the
cosign verifycommand. It is highly recommended to verify against the image digest (e.g.,sha256:...) rather than a mutable tag (likelatestor1.23.0). You can find image digests on Docker Hub or GitHub Container Registry.# Ensure 'cosign.pub' is in your current directory, or provide the full path to it. # Replace <registry>/bleala/pimsync@sha256:<image-digest> with the actual image reference and its digest. # Example for an image on Docker Hub: cosign verify --key cosign.pub docker.io/bleala/pimsync@sha256:<ACTUAL_IMAGE_DIGEST_HERE> # Example for an image on GitHub Container Registry: cosign verify --key cosign.pub ghcr.io/bleala/pimsync@sha256:<ACTUAL_IMAGE_DIGEST_HERE>
For instance, to verify the
devtag with the following digestsha256:bd9b65a3a65425bd4b67de6a61670aa0e551f996ac5f466da8aa603ab9acd005:cosign verify --key cosign.pub docker.io/bleala/pimsync@sha256:bd9b65a3a65425bd4b67de6a61670aa0e551f996ac5f466da8aa603ab9acd005
A successful verification will output information like this:
cosign verify --key cosign.pub docker.io/bleala/pimsync@sha256:bd9b65a3a65425bd4b67de6a61670aa0e551f996ac5f466da8aa603ab9acd005 Verification for index.docker.io/bleala/pimsync@sha256:bd9b65a3a65425bd4b67de6a61670aa0e551f996ac5f466da8aa603ab9acd005 -- The following checks were performed on each of these signatures: - The cosign claims were validated - Existence of the claims in the transparency log was verified offline - The signatures were verified against the specified public key [{"critical":{"identity":{"docker-reference":"index.docker.io/bleala/pimsync"},"image":{"docker-manifest-digest":"sha256:bd9b65a3a65425bd4b67de6a61670aa0e551f996ac5f466da8aa603ab9acd005"},"type":"cosign container image signature"},"optional":{"Bundle":{"SignedEntryTimestamp":"MEUCIQDRzntAex381nJLU3DpBVYbpRJB4ikVD27AfxbmQVrrwgIgVExRV2P1jOIZjUjAw6N9cwLOWIDPo1RIK0+qF/zeoUY=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiIzZTgzNjY5MWM5NzM3NGNhMmExNjllMjUwNTllMjY4MGI4ZjRkODEyZTcyMDliZTAzNjEwMDAwMDI5YTBjZjNlIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUUM4WnFrZDIrblB1czVKNUJvQVUweFYyZGxRaW5tSlpubXlUeSt2VXIwSlJnSWdRSFFNZ01lYy9hVk93ODVKMGFXangyblg5MlhmTnJWTWU2VTlMdFpyTzVRPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCUVZVSk1TVU1nUzBWWkxTMHRMUzBLVFVacmQwVjNXVWhMYjFwSmVtb3dRMEZSV1VsTGIxcEplbW93UkVGUlkwUlJaMEZGU0VWWFRFYzVjVVI2VFdGdlJ6TlJTSGxXTUhoVFRVZzNRblF3VGdvMVRVWkRNWEV3VFhabE5DOHZVMmwxZVZWbU5VRnBaRVJZY2s5S1kwaEdSalYxZERWUVMyNVViMUZ6YjNWNWRGVTBXVmhoWlM5bU1UQlJQVDBLTFMwdExTMUZUa1FnVUZWQ1RFbERJRXRGV1MwdExTMHRDZz09In19fX0=","integratedTime":1756893469,"logIndex":463255555,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}}]
To start the container you can run the following
docker run -d -v /path/to/your/config:/pimsync/pimsync.conf \
bleala/pimsync:latestBut since docker compose is easier to maintain, I'll give you a valid docker compose example.
---
networks:
pimsync:
driver: bridge
volumes:
pimsync:
name: pimsync
driver: local
services:
# Pimsync - a command line tool to synchronise calendars and contacts between different storages, including CalDAV and CardDAV.
# Pimsync is a successor and reimplementation of Vdirsyncer, and is free and open source software. DOCKERIZED!
# https://hub.docker.com/r/bleala/pimsync
# https://github.com/Bleala/Pimsync-DOCKERIZED
pimsync:
image: bleala/pimsync:latest
container_name: pimsync
hostname: pimsync
restart: unless-stopped
security_opt:
- no-new-privileges:true
environment:
# Optional: set your timezone, for correct container and log time, default to `Europe/Vienna`
TZ: Europe/Vienna
# Optional: set the container mode, `auto` will run the PIMSYNC_COMMAND, `manual` will only run the container, so you can exec into it and run your commands manually, default to auto
CONTAINER_MODE: auto
# Optional: set the Pimsync command for `auto` mode, default to `daemon`, can be extended with flags, e.g. "sync -n" or "daemon -r"
PIMSYNC_COMMAND: daemon
# Optional: set the Pimsync config path, default to `/pimsync/pimsync.conf`
PIMSYNC_CONFIG: /pimsync/pimsync.conf
# Optional: set the Pimsync executable path, default to `/usr/local/bin/pimsync`
PIMSYNC_EXECUTABLE_PATH: /usr/local/bin/pimsync
# Optional: set the Pimsync log level, default to `info`, other options are `trace`, `debug`, `warn` or `error`
PIMSYNC_LOG_LEVEL: info
env_file:
- path: .env
required: false
networks:
pimsync: {}
volumes:
- type: volume
source: pimsync
target: /pimsync
read_only: false
- type: bind
source: /path/to/pimsync.conf
target: /pimsync/pimsync.conf
read_only: trueYou can start the docker-compose.yml with the following command
docker compose up -dIf you want to see the container logs, you can run
docker compose logs -for
docker logs -f pimsyncYou have to mount a local configuration file inside the container to work properly. How to config
In the /pimsnyc folder you will also find the pimsync.conf.example which I copied inside the container for a quick reference.
You can also find the pimsync.conf.example in this GitHub repository. (pimsync.conf.example)
The configuration file name is pimsync.conf. Write everything like it is shown in the docs and in my pimsync.conf.example!
Attention: It is not recommended to use CONTAINER_MODE: auto and PIMSYNC_COMMAND: daemon by default, if you have never used Pimsync before! If you set it to auto and daemon, it will automatically start to sync your defined storages, so don't ruin your calender/contacts structure! Use it only if you know what you are doing! --> DYOR and READ THE DOCS!
For first time use I recommend running the container with CONTAINER_MODE: manual.
Now you can either exec into the container with docker exec -it pimsync sh or run the commands directly from your host.
After the container is started and your pimsync.conf is mounted, I suggest that you run docker exec -it pimsync pimsync check to validate your config file.
Now you can discover your defined pairs with docker exec -it pimsync pimsync discover, to check if the connection to your configured storages does work as expected.
After you ran docker exec -it pimsync pimsync discover you can either run docker exec -it pimsync pimsync sync or, if you have not set CONTAINER_MODE: auto and PIMSYNC_COMMAND: daemon, set it to auto/daemon and restart the container with docker compose restart or deploy it again with docker compose up -d.
Now it will sync everything for the first time.
For futher collections/pairs you do not have to run pimsync discover again. Pimsync will do this automatically in daemon mode. You should only do it for the first time to unterstand how Pimsync does work.
Everything that is done by Pimsync will get written to the docker logs! Run docker logs -f pimsync or docker compose logs -f to watch the logs.
Attention: If you would like to use the a local storage, be sure that the folder already exists, otherwise Pimsync produces errors!
As you can see in the pimsync.conf.example, I set /pimsync/calendars/ as path for the local storage and for the pair test as local folder. So to work properly the path/folder /pimsync/calendars/test has to exist before you run your first sync!
Either create it with docker exec -it pimsync "mkdir -p /path/to/your/local/folder" (in my example this would be docker exec -it pimsync "mkdir -p /pimsync/calendars/test") or if you have mounted a local folder to /pimsync create the subfolder and make sure, that it is readable and writable by the pimsync user (UID/GID 1000)!
For further information look at the available man pages:
Pimsync does run with an user called pimsync inside the container and not as root.
The UID and GID for this user are 1000 by default, so be careful if you mount your pimsync.conf, that it is readable for this user and if you use a bind mount instead of a docker volume.
If you need to set a custom UID and GID, add the user key to your docker-compose.yml.
Example:
user: "your_UID:your_GID"
Complete docker-compose.yml with the `user` key
---
networks:
pimsync:
driver: bridge
volumes:
pimsync:
name: pimsync
driver: local
services:
# Pimsync - a command line tool to synchronise calendars and contacts between different storages, including CalDAV and CardDAV.
# Pimsync is a successor and reimplementation of Vdirsyncer, and is free and open source software. DOCKERIZED!
# https://hub.docker.com/r/bleala/pimsync
# https://github.com/Bleala/Pimsync-DOCKERIZED
pimsync:
image: bleala/pimsync:latest
container_name: pimsync
hostname: pimsync
restart: unless-stopped
user: "your_UID:your_GID"
security_opt:
- no-new-privileges:true
environment:
# Optional: set your timezone, for correct container and log time, default to `Europe/Vienna`
TZ: Europe/Vienna
# Optional: set the container mode, `auto` will run the PIMSYNC_COMMAND, `manual` will only run the container, so you can exec into it and run your commands manually, default to auto
CONTAINER_MODE: auto
# Optional: set the Pimsync command for `auto` mode, default to `daemon`, can be extended with flags, e.g. "sync -n" or "daemon -r"
PIMSYNC_COMMAND: daemon
# Optional: set the Pimsync config path, default to `/pimsync/pimsync.conf`
PIMSYNC_CONFIG: /pimsync/pimsync.conf
# Optional: set the Pimsync executable path, default to `/usr/local/bin/pimsync`
PIMSYNC_EXECUTABLE_PATH: /usr/local/bin/pimsync
# Optional: set the Pimsync log level, default to `info`, other options are `trace`, `debug`, `warn` or `error`
PIMSYNC_LOG_LEVEL: info
env_file:
- path: .env
required: false
networks:
pimsync: {}
volumes:
- type: volume
source: pimsync
target: /pimsync
read_only: false
- type: bind
source: /path/to/pimsync.conf
target: /pimsync/pimsync.conf
read_only: trueYou can set a few different environment variables if you want to:
| Variable | Info | Value |
|---|---|---|
TZ |
to set the correct container and log time | optional, default to Europe/Vienna, look here for possible values |
CONTAINER_MODE |
is used automatically run pimsync ${PIMSYNC_COMMAND} or to just start the container for manual pimsync commands |
optional, default to auto, can be manual |
PIMSYNC_COMMAND |
is used to specify the Pimsync command in auto mode |
optional, default to daemon, can be any of these commands |
PIMSYNC_CONFIG |
is used to set the Pimsync config file location |
optional, default to /pimsync/pimsync.conf |
PIMSYNC_EXECUTABLE_PATH |
is used to set the Pimsync executable path |
optional, default to /usr/local/bin/pimsync, should not be changed! |
PIMSYNC_LOG_LEVEL |
is used to set the Pimsync log level |
optional, default to info, can be trace, debug, info, warn or error |
Clone this repo and then:
cd Pimsync-DOCKERIZED/docker
docker build -t bleala/pimsync:dev .Or you can use the provided docker-compose.override.yml file:
docker compose -f docker-compose.override.yml buildFor more information on using multiple compose files see here. You can also find a prebuilt docker image from Docker Hub, which can be pulled with this command:
docker pull bleala/pimsync:latestI'm glad, if you want to contribute something to the Pimsync container.
Feel free to create a PR with your changes and I will merge it, if it's ok.
Attention: Please use the main branch for pull requests, a CI pipeline is going to run to check, if the container will build!
1.0.4 - 19.03.2026:
- Pimsync update to version 0.5.7
1.0.3 - 03.03.2026:
- Pimsync update to version 0.5.6
- Alpine update to version 3.23.3
Current Versions:
- Pimsync 0.5.6, Alpine 3.23.3
Old Version History
1.0.2 - 02.12.2025:
- Pimsync update to version 0.5.5
1.0.1 - 17.10.2025:
- Pimsync update to version 0.5.4
- Alpine update to version 3.22.2
- Moved to official Rust install script instead of apk
1.0.0 - 04.09.2025:
- Initial Release!
- Build on Alpine 3.22.1 with Pimsmync Version 0.4.4.
- Official Documentation.