Skip to main content

D_la solution contacts et calendrier

Solution d'unification des contacts et dedu calendrier de Julien par ClaudeJulien.

État Solutionau Contacts3 août 2026 — déployé et Calendrierfonctionnel, —à Baïkall'exception +de Roundcube
vdirsyncer (agrégation Google/Infomaniak) et du calendrier web.

1. Objectif

Unifier la base de contacts et calendriersde calendriers, dispersée entre plusieurs sources (Google, Infomaniak, téléphone), autour d'un point central self-hostéauto-hébergé sur le VPS juxjux.ovh, synchronisé vers tous les clients existants.
Vue

d'ensemble de l'architecture
Composant
Rôle
Emplacement
Baïkal
Serveur CardDAV + CalDAV — stockage central des contacts et calendriers
Docker, VPS juxjux.ovh
Roundcube
Interface web de saisie/lecture (contacts + calendrier)
Docker, VPS juxjux.ovh
Nginx
Reverse proxy HTTPS pour les deux services
Hôte VPS
DAVx5
Pont de synchronisation CardDAV/CalDAV vers Android
Téléphone
Fossify Agenda
Client calendrier
Téléphone (via DAVx5)
Thunderbird
Client mail (indépendant de ce circuit)
Téléphone
vdirsyncer (à mettre en place)
Agrège les contacts Google et Infomaniak vers Baïkal
VPS, cron
Schéma de flux
Code

Baïkal est la source de vérité unique.unique. Roundcube et DAVx5 en sont des clients ; vdirsyncer estsera le seul composant qui écrit depuis l'extérieur (Google/Infomaniak)vers Baïkal.

2. Architecture réellement déployée

Composant Rôle Emplacement État Baïkal Serveur CardDAV + CalDAV, stockage central Docker, VPS juxjux En service Roundcube Interface web de saisie/lecture des contacts Docker, VPS juxjux En service Nginx Reverse proxy HTTPS des deux services Hôte VPS En service DAVx5 Pont de synchronisation vers Baïkal.
PourquoiAndroid Téléphone À configurer Fossify Agenda Client calendrier Téléphone (via DAVx5) À configurer vdirsyncer Agrège Google et Infomaniak vers Baïkal VPS, cron Non déployé Thunderbird Client mail, indépendant de ce choix
Radicalecircuit Téléphone Inchangé

3. Accès

Service URL Identifiant Baïkal (admin) https://baikal.juxjux.ovh/admin/ compte admin Baïkal Roundcube https://secretariat.juxjux.ovh julien.bertrand@ik.me (compte mail Infomaniak) Découverte DAV https://baikal.juxjux.ovh/dav.php/ Julien

Utilisateur Baïkal : Julien — avec un J majuscule. La casse compte dans les URLs DAV.

    Contacts : https://baikal.juxjux.ovh/dav.php/addressbooks/Julien/default/ Calendrier : https://baikal.juxjux.ovh/dav.php/calendars/Julien/default/

    Certificats Let's Encrypt valides jusqu'au 1er novembre 2026 pour les deux domaines. Celui de baikal.juxjux.ovh existait déjà mais avait expiré le 8 février 2026 (vestige d'une tentative antérieure) ; il a été renouvelé le 3 août.

    4. Déploiement

    Stack sur le VPS : /home/debian/baikal/docker-compose.yml, projet compose baikal. Sources versionnées : Syncthing/Jux_univers/Jux-scripts/Baikal-Contacts/.

    Fichier Rôle docker-compose.yml Stack Baïkal + Roundcube baikal.juxjux.ovh.conf Vhost Baïkal (avec le correctif .well-known) secretariat.juxjux.ovh.conf Vhost Roundcube finaliser_tls.sh Vérifie le DNS puis lance certbot vps_backup.sh Script de sauvegarde complet, Baïkal inclus
    cd /home/debian/baikal && sudo docker compose -p baikal up -d
    
    Service Image Port local Base RAM baikal ckulka/baikal:nginx 127.0.0.1:8088 SQLite ~30 Mo roundcube roundcube/roundcubemail:latest (1.7.2) 127.0.0.1:8083 SQLite ~41 Mo

    Les deux services pèsent 71 Mo au total, contre environ 600 Mo avec l'architecture MariaDB initialement prévue. Ce choix était important : le VPS était en pression mémoire au moment du déploiement (swap à 3,8/4,0 Go).

    5. Écarts avec le plan initial

    Le plan préparé prévoyait une configuration qui ne pouvait pas fonctionner en l'état. Écarts constatés et corrigés :

    Point Prévu Réel Raison Port Baïkal 8081 8088 8081 est occupé par FreshRSS. 8088 correspond au vhost baikal.juxjux.ovh préexistant Port Roundcube 8082 8083 8082 est ciblé par un vhost nextcloud mort Domaine Roundcube mail.juxjux.ovh secretariat.juxjux.ovh Aucun DNS n'existait ; mail. prêtait à confusion avec les MX OVH du domaine Base Roundcube MariaDB SQLite ~400 Mo de RAM économisés, suffisant en mono-utilisateur Vhost Baïkal À créer Déjà présent Le fichier baikal.conf préparé n'a pas servi Plugin calendar Activé Non déployé Incompatible, voir §6

    6. Pièges rencontrés

    6.1 Les plugins carddav et calendar ne sont pas dans l'image Roundcube

    L'image officielle ne fournit ni carddav ni calendar. Les déclarer dans ROUNDCUBEMAIL_PLUGINS ne fait que les activer — s'ils sont absents, Roundcube part en erreur fatale.

    Il faut les faire installer par composer au démarrage, via ROUNDCUBEMAIL_COMPOSER_PLUGINS (et non ROUNDCUBEMAIL_INSTALL_PLUGINS, qui n'existe pas dans cette image) :

    ROUNDCUBEMAIL_COMPOSER_PLUGINS: "roundcube/carddav"
    ROUNDCUBEMAIL_PLUGINS: "carddav"
    

    Le premier démarrage est alors plus long (téléchargement composer).

    6.2 Le plugin calendar casse tout le démarrage

    La seule version résolvable est kolab/calendar 3.3.3 (ancienne, alors que libcalendaring monte en 3.6.1). Son script d'initialisation de base s'exécute avant que l'entrypoint n'écrive la configuration Roundcube : il tombe donc sur le DSN MySQL par défaut et échoue en SQLSTATE[HY000] [2002] No such file or directory.

    Cette erreur fatale empêche la régénération de l'autoloader composer, ce qui casse aussi le plugin carddav :

    PHP Fatal error: Uncaught Error: Interface
    "MStilkerich\RCMCardDAV\Frontend\RcmInterface" not found
    in /var/www/html/plugins/carddav/carddav.php:43
    

    Symptôme : HTTP 500 permanent, alors que les fichiers du plugin sont bien présents sur le disque — c'est vendor/composer/autoload_psr4.php qui ne contient aucune entrée carddav.

    Le plugin calendar a donc été retiré. Conséquence : Roundcube gère les contacts, pas l'agenda. Ce n'est pas bloquant, DAVx5 couvre l'agenda sur le téléphone. Pour un agenda web, la piste est InfCloud (un vhost infcloud.conf traîne déjà sur le VPS).

    6.3 Baïkal ignore X-Forwarded-Proto — fuite HTTP sur la découverte

    Baïkal ne tient pas compte de X-Forwarded-Proto et générait ses redirections de découverte en HTTP nu :

    /.well-known/carddav -> http://baikal.juxjux.ovh/dav.php
    

    C'est exactement le risque identifié dès la conception : CardDAV et CalDAV envoient les identifiants en Basic Auth à chaque synchronisation (DAVx5 notamment). Un client suivant cette redirection part sur du HTTP.

    Corrigé en court-circuitant Baïkal directement dans le vhost :

    location = /.well-known/carddav {
        return 301 https://$host/dav.php/;
    }
    location = /.well-known/caldav {
        return 301 https://$host/dav.php/;
    }
    

    À vérifier après tout reload nginx : le rechargement n'est pas instantané, un test lancé dans la foulée peut encore montrer l'ancien comportement.

    6.4 Roundcube exige un serveur IMAP pour authentifier

    Roundcube n'a pas de base d'utilisateurs propre : son écran de login valide les identifiants contre le serveur IMAP configuré. Sans IMAP joignable, aucune connexion n'est possible — donc aucun accès aux contacts non plus.

    L'idée d'un Roundcube « contacts et agenda seulement, sans IMAP » n'est pas réalisable. La configuration retenue pointe vers ssl://mail.infomaniak.com:993, ce qui couvre le compte julien.bertrand@ik.me (le domaine ik.me est servi par l'infrastructure Infomaniak).

    Si un jour le compte passe en double authentification, il faudra générer un mot de passe d'application Infomaniak.

    6.5 Baïkal doit être installé en SQLite

    L'installeur Baïkal propose MySQL ou SQLite. Choisir SQLite : la stack ne contient aucun serveur MySQL, cocher « Enable MySQL » mène à une impasse. Base à /var/www/baikal/Specific/db/db.sqlite, dans le volume baikal-data.

    7. Sauvegarde

    Baïkal a été ajouté à /opt/backups/vps_backup.sh le 3 août 2026 (cron quotidien à 2h UTC).

      Dossier kDrive de destination : 1467771 (SYNC-pour_VPS/backups/baikal) Le bilan de fin de log passe de 5 à 6 services (le total est calculé dynamiquement, pas codé en dur) Sauvegarde de l'ancien script : /opt/backups/vps_backup.sh.bak-260803

      La fonction archive deux volumes, via un tar intermédiaire puis 7z :

        Specific/ — la base db.sqlite (contacts et calendriers) config/ — baikal.yaml (paramètres et hash du mot de passe admin)

        Sans le second, la restauration est incomplète. Testée le 3 août : upload HTTP 200, aucun résidu temporaire.

        8. Vérifications effectuées le 3 août 2026

        Test Résultat GET /dav.php/ HTTP 401 — authentification bien exigée PROPFIND /dav.php/ HTTP 401 et non 405 — nginx laisse passer les méthodes DAV étendues .well-known/carddav et caldav 301 vers HTTPS Installation Baïkal Utilisateur Julien, carnet et calendrier default créés Login Roundcube IMAP Infomaniak accepté Découverte CardDAV Carnet résolu à .../dav.php/addressbooks/Julien/default/ Écriture d'un contact vCard 3.0 écrite par RCMCardDAV v5.1.3, relue dans Baïkal, accents UTF-8 préservés Synchronisation incrémentale sync_token à http://sabre.io/ns/sync/2 Sauvegarde Baïkal Archive uploadée sur kDrive, HTTP 200

        Note : dans la table carddav_addressbooks de Roundcube, une seconde ligne nommée %N avec une URL vide n'est pas une erreur — c'est le template de rcmcarddav v5, qui porte les réglages appliqués aux carnets découverts.

        9. Reste à faire

        9.1 DAVx5 sur le téléphone

        Ajouter un compte avec l'URL de base https://baikal.juxjux.ovh/dav.php/ et l'utilisateur Julien. DAVx5 découvre seul le carnet et le calendrier ; router ensuite la synchronisation vers l'app Contacts Android et Fossify Agenda.

        9.2 vdirsyncer — agrégation Google et Infomaniak

        Seule brique du plan initial encore absente. Objectif : faire remonter dans Baïkal les contacts existants sur Google et Infomaniak, pour que Baïkal devienne le point central réel et pas un silo de plus.

          Google Contacts : CardDAV via https://www.google.com/carddav/v1/principals/EMAIL/ — nécessite un mot de passe d'application (compte en 2FA) Infomaniak : CardDAV natif, identifiants standards du compte mail vdirsyncer : outil CLI léger, une paire de synchronisation par source, exécuté par cron sur le VPS

          Décision à prendre avant déploiement :

            one-way (Google/Infomaniak → Baïkal, lecture seule) : sans risque, mais les modifications faites dans Baïkal ne remontent pas vers Google two-way : tout reste aligné, mais un conflit ou une erreur de configuration peut propager des suppressions dans les deux sens

            Recommandation : démarrer en one-way le temps de vérifier que l'import est fidèle, puis basculer si besoin.

            9.3 Agenda web

            Roundcube n'affiche pas le calendrier (§6.2). Piste : déployer InfCloud, dont le vhost existe déjà.

            9.4 Nettoyage

            Quatre vhosts morts traînent dans /etc/nginx/sites-enabled/, vestiges des tentatives précédentes : radicale, agendav, infcloud, nextcloud. Le dernier cible le port 8082, ce qui a contraint le choix du port de Roundcube.

            10. Checklist sécurité

               Aucun mot de passe CHANGE_ME_... en production — la bascule vers SQLite a supprimé les identifiants MariaDB du compose  HTTPS forcé sur les deux vhosts (redirection 80 vers 443)  Certificats Let's Encrypt valides, renouvellement automatique certbot en place  Découverte DAV forcée en HTTPS (§6.3)  Les deux containers n'écoutent que sur 127.0.0.1 — seul nginx les expose  Sauvegarde quotidienne des volumes Baïkal vers kDrive  Mot de passe d'application dédié pour l'accès CardDAV Google — à faire au moment de vdirsyncer

              11. Commandes utiles

              # État de la stack
              sudo docker ps --filter name=baikal --filter name=roundcube
              
              # Logs
              sudo docker logs roundcube --tail 50
              sudo docker logs baikal --tail 50
              
              # Redéployer
              cd /home/debian/baikal && sudo docker compose -p baikal up -d
              
              # Inspecter la base Baïkal (contacts, carnets, utilisateurs)
              sudo docker cp baikal:/var/www/baikal/Specific/db/db.sqlite /tmp/bk.sqlite
              sudo sqlite3 /tmp/bk.sqlite "SELECT COUNT(*) FROM cards;"
              sudo sqlite3 /tmp/bk.sqlite "SELECT id, uri, displayname FROM addressbooks;"
              
              # Vérifier la découverte DAV
              curl -s -o /dev/null -w "%{http_code} -> %{redirect_url}\n" \
                https://baikal.juxjux.ovh/.well-known/carddav
              
              # Tester la sauvegarde Baïkal seule (sans relancer les 14 min du run complet)
              # voir /tmp/test_baikal.sh — filtre les autres run_service et loggue dans /tmp
              

              12. Choix d'architecture — pourquoi ces outils

              Radicale écarté (: stockage fichier brut, pas de vraie gestion)gestion. — clarification : laLa stack Radicale/InfCloud initialement envisagée n'a finalement pas été mise en place.

              Nextcloud a été écarté : trop lourd pour l'usage visé (PHP-FPM + DBbase + Redis + écosystème complet), alors que le VPS fait déjà tourner PostGIS, Metabase, BookStack, FreshRSS.

              Baïkal retenu : léger (PHP + SQLite/MariaDB, quelques dizaines de Mo de RAM),léger, CardDAV +et CalDAV natifs, interface d'adminadministration suffisantesuffisante. pour la gestion des carnets/calendriers.
              Roundcube retenu comme interface de saisie/lecture (Baïkal n'a pas de vraie UI de consultation) : léger, traduit en français, projet actif (dernière version majeure 1.7.0, mises à jour de sécurité régulières).
              Alternative envisagée puis écartée : Thunderbird containerisé (VNC/noVNC) — fonctionnel mais plus lourd en ressources et moins adapté au multi-accès qu'un vrai webmail.
              Déploiement — Stack Docker
              Fichiers de référence : docker-compose.yml, config/carddav.php, nginx/baikal.conf, nginx/roundcube.conf.
              1. Lancer les conteneurs
              Bash
              Services démarrés :
              baikal (image ckulka/baikal:nginx) — exposé en local sur 127.0.0.1:8081
              roundcube-db (MariaDB) — base de données Roundcube
              roundcube (image roundcube/roundcubemail) — exposé en local sur 127.0.0.1:8082
              ⚠️ Remplacer les valeurs CHANGE_ME_... du compose (mots de passe DB) avant le premier démarrage.
              2. Configuration initiale Baïkal
              Aller sur https://baikal.juxjux.ovh/admin/
              Créer le compte administrateur
              Créer un utilisateur
              Créer pour cet utilisateur :
              un carnet de contacts (ex. default)
              un calendrier (ex. default)
              Noter les URLs générées :
              Contacts : https://baikal.juxjux.ovh/dav.php/addressbooks/USERNAME/default/
              Calendrier : https://baikal.juxjux.ovh/dav.php/calendars/USERNAME/default/
              3. Reverse proxy Nginx
              Deux vhosts à activer sur l'hôte (/etc/nginx/sites-available/) :
              baikal.juxjux.ovh → proxy vers 127.0.0.1:8081
              mail.juxjux.ovh → proxy vers 127.0.0.1:8082
              Bash
              Point d'attention : CardDAV/CalDAV envoient les identifiants en Basic Auth à chaque synchronisation (DAVx5 notamment) → HTTPS obligatoire, jamais de HTTP nu au-delà du proxy local.
              4. Plugins Roundcube
              Deux plugins activés via ROUNDCUBEMAIL_PLUGINS dans le compose : carddav et calendar.
              Contacts (carddav) — config dans config/carddav.php, monté dans le conteneur :
              URL pointée vers le carnet de contacts Baïkal créé à l'étape 2
              %u / %p réutilisent les identifiants de connexion Roundcube (si mêmes comptes que Baïkal)
              Calendrier (calendar) — configuration depuis l'interface :
              Se connecter à Roundcube
              Réglages → Calendrier → Calendriers
              Ajouter une source CalDAV avec l'URL calendrier Baïkal
              Côté téléphone — DAVx5
              Ajouter un compte avec l'URL de base : https://baikal.juxjux.ovh/dav.php/
              DAVx5 découvre automatiquement le carnet de contacts et le calendrier
              Activer la synchronisation vers :
              Fossify Agenda (calendrier)
              App Contacts Android (contacts)
              Thunderbird sur le téléphone reste indépendant de ce circuit (gère uniquement les mails)
              Agrégation Google / Infomaniak — vdirsyncer (étape suivante, non encore déployée)
              Objectif : faire remonter dans Baïkal les contacts existants sur les comptes Google et Infomaniak, pour que Baïkal devienne le point central réel et pas seulement un nouveau silo.
              Google Contacts : accès CardDAV via https://www.google.com/carddav/v1/principals/EMAIL/ — nécessite un mot de passe d'application (compte avec 2FA)
              Infomaniak : CardDAV natif, identifiants standards du compte mail
              vdirsyncer : outil CLI léger, une paire de synchronisation par source (Google ↔ Baïkal, Infomaniak ↔ Baïkal), exécuté via cron sur le VPS
              Décision à prendre au moment de la mise en place : synchronisation one-way (Baïkal source de vérité, lecture seule depuis Google/Infomaniak) ou two-way (modifications propagées dans les deux sens)
              Sécurité — checklist
              [ ] Tous les mots de passe CHANGE_ME_... remplacés avant mise en production
              [ ] HTTPS forcé sur les deux vhosts (redirection 80 → 443 en place)
              [ ] Certificats Let's Encrypt valides et renouvellement automatique vérifié
              [ ] Mot de passe d'application dédié pour l'accès CardDAV Google (pas le mot de passe principal du compte)
              [ ] Sauvegarde régulière des volumes baikal-config, baikal-data, roundcube-db
              Statut du projet Baïkal (pour référence)
              Développé aujourd'hui par des bénévoles sous l'organisation sabre-io (mainteneurs de SabreDAV, la librairie sous-jacente). Pas— pas de société commerciale derrière, mais communauté active et outil considéré comme robuste pour un usage personnel/petite structurepersonnel sur la durée.
              Statut

              du

              Roundcube retenu comme interface de saisie/lecture, Baïkal n'ayant pas de vraie UI de consultation : léger, traduit en français, projet Roundcubeactif (pour référence)
              Projet actif, version majeure 1.7.0 sortie2 en maiaoût 2026, mises à jour de sécurité régulières.régulières). A rejoint la famille Nextcloud en 2023 tout en restant indépendantindépendant, sous licence GPL. Réserve constatée à l'usage : il impose une authentification IMAP (licence§6.4) GPL)et ne couvre pas l'agenda (§6.2). Interface traduite en français en natif.

              Thunderbird containerisé (VNC/noVNC) envisagé puis écarté : fonctionnel mais plus lourd et moins adapté au multi-accès qu'un vrai webmail.