Sync Proton Mail contacts with any CardDAV server (Nextcloud, Radicale, Baikal).
1.4K
Sync your Proton Mail contacts with any CardDAV server — Nextcloud, Radicale, Baïkal, iCloud, and others. A small, self-hosted Go daemon.
📦 Source & full docs: https://github.com/secbyd/proton-carddav-sync
PCS_ENCRYPTION_KEY. Nothing secret is written to the config file.latest — the current main buildvX.Y.Z — tagged releasessha-<short> — a specific commitImages are multi-arch: linux/amd64 and linux/arm64.
| Mount | Purpose |
|---|---|
/config | holds config.yaml (set database.path: /data/sync.db) |
/data | holds the SQLite database (credentials + sync state) |
PCS_ENCRYPTION_KEY (a long random passphrase) must be passed at runtime — it is
never baked into the image, and the same value is required by init and the
daemon.
The container runs as a non-root user (uid 10001). Named volumes (as below) work out of the box. If you bind-mount host directories owned by another user, run the container as that user —
--user $(id -u):$(id -g)(oruser: "1000:1000"in compose), applied to theinitrun too — orchown -R 10001:10001the host directories.
docker run --rm -it \
-e PCS_ENCRYPTION_KEY="a-long-random-passphrase" \
-v pcs-config:/config -v pcs-data:/data \
secbyd/proton-carddav-sync \
init --config /config/config.yaml
With no config present, init asks for every setting (set database.path to
/data/sync.db), logs in to Proton (asking for a TOTP code if 2FA is enabled),
and stores the encrypted session.
If your platform can't run an interactive one-off container (e.g. Portainer or
Unraid), start the container with the idle command instead, then:
docker exec -it <container> proton-carddav-sync init --config /config/config.yaml
…and restart it with the default command afterwards.
docker run -d --name proton-carddav-sync --restart unless-stopped \
-e PCS_ENCRYPTION_KEY="a-long-random-passphrase" \
-v pcs-config:/config -v pcs-data:/data \
secbyd/proton-carddav-sync
services:
proton-carddav-sync:
image: secbyd/proton-carddav-sync:latest
restart: unless-stopped
environment:
PCS_ENCRYPTION_KEY: "a-long-random-passphrase"
volumes:
- pcs-config:/config
- pcs-data:/data
volumes:
pcs-config:
pcs-data:
Run init once before up -d:
docker compose run --rm -it proton-carddav-sync init --config /config/config.yaml
| Variable | Required | Description |
|---|---|---|
PCS_ENCRYPTION_KEY | yes | Master key encrypting the stored Proton session + CardDAV password |
PCS_PROTON_APP_VERSION | no | Override the Proton x-pm-appversion header |
PCS_PROTON_USER_AGENT | no | Override the browser User-Agent sent to Proton |
debian:bookworm-slim base so the CGO SQLite driver works
without musl/static-link complications.See the repository for license and full documentation.
Content type
Image
Digest
sha256:120c18de3…
Size
37.1 MB
Last updated
4 days ago
docker pull secbyd/proton-carddav-sync