Pourquoi auto-héberger Cal.com sur un VPS
Cal.com est une application Next.js adossée à PostgreSQL qui gère la planification de rendez-vous, les types d'événements, les disponibilités et la synchronisation avec les calendriers (Google, CalDAV, Office 365). L'auto-hébergement répond à un besoin précis : maîtriser les données de disponibilité et de prise de rendez-vous de vos clients, qui transitent normalement par un service tiers américain. Sur VPS, vous éliminez les limites du plan gratuit (un seul type d'événement, marque imposée), vous branchez vos propres clés d'API Google/visio et vous intégrez le widget de réservation directement dans votre site sous votre domaine. Comme Cal.com est une application Node persistante avec base de données et build de production, elle exige un VPS — un mutualisé ne peut ni faire tourner le processus ni héberger PostgreSQL.
Bénéfices concrets de Cal.com auto-hébergé
- Types d'événements illimités : entretiens 15 min, démos 30 min, ateliers de groupe, sans paywall.
- Données de réservation chez vous : aucune fuite des coordonnées et créneaux clients vers un SaaS tiers.
- White-label total : le lien de réservation porte votre domaine, pas celui d'un éditeur.
- Webhooks et API : déclenchez des automatisations (CRM, facturation) à chaque rendez-vous pris.
- Intégrations Google Agenda, CalDAV et visio (Jitsi, Google Meet) configurées avec vos propres clés.
- Réservations d'équipe et round-robin pour distribuer les rendez-vous entre plusieurs collaborateurs.
Prérequis techniques
Cal.com est plus exigeant que la moyenne du self-hosting à cause de son socle Next.js et de l'étape de build. Prévoyez 2 vCPU, 4 Go de RAM et 20 Go de disque pour une instance d'équipe confortable ; 2 Go de RAM peuvent suffire pour un usage individuel mais le build initial est plus serré. Il faut Docker et Docker Compose, une base PostgreSQL (incluse dans le compose officiel), un domaine rdv.votredomaine.com pointé vers le VPS, et plusieurs variables d'environnement obligatoires : NEXTAUTH_SECRET, CALENDSO_ENCRYPTION_KEY (clés générées aléatoirement) et NEXT_PUBLIC_WEBAPP_URL réglée sur votre URL HTTPS finale. Pour la synchro agenda et la visio, prévoyez les identifiants OAuth Google.
Déployer Cal.com pas à pas
Cloner le dépôt de déploiement Docker
Sur le VPS : git clone https://github.com/calcom/docker.git cal-docker && cd cal-docker. Ce dépôt fournit un docker-compose.yml et un fichier .env.example à adapter.
Générer les secrets et configurer l'environnement
Copiez .env.example en .env, puis générez les clés : openssl rand -base64 32 pour NEXTAUTH_SECRET et pour CALENDSO_ENCRYPTION_KEY. Renseignez NEXT_PUBLIC_WEBAPP_URL=https://rdv.votredomaine.com et les identifiants PostgreSQL. Conservez immédiatement ces trois valeurs dans un gestionnaire de secrets — vous ne pourrez plus les changer après le premier démarrage sans perdre toutes vos intégrations.
Construire et lancer la stack
Démarrez avec docker compose up -d. Le premier démarrage construit l'image Next.js et applique les migrations Prisma sur PostgreSQL — c'est l'étape la plus longue, suivez-la avec docker compose logs -f.
Placer le reverse proxy et le SSL
Mettez Cal.com (port interne 3000) derrière un reverse proxy HTTPS. Avec Caddy : rdv.votredomaine.com { reverse_proxy calcom:3000 }. Le certificat est obtenu automatiquement. L'URL doit correspondre exactement à NEXT_PUBLIC_WEBAPP_URL, sans quoi l'authentification échoue.
Créer le compte et configurer les disponibilités
Ouvrez https://rdv.votredomaine.com, créez le compte propriétaire, définissez vos plages horaires et un premier type d'événement. Testez une réservation de bout en bout pour valider la chaîne.
Connecter agenda et visio
Dans les intégrations, ajoutez vos identifiants OAuth Google pour la synchro bidirectionnelle de l'agenda, et activez Jitsi ou Google Meet pour générer automatiquement un lien de visio à chaque réservation.
Se connecter la première fois
Ouvrez l'URL : Cal.com vous redirige vers son assistant de première configuration (/auth/setup) où vous créez VOTRE compte administrateur. Faites-le dès la fin de l'installation : cet assistant n'est protégé par rien tant que le premier compte n'existe pas.
Le build mémoire de Cal.com peut échouer sur un VPS à 2 Go pendant la compilation Next.js. Si vous voyez une erreur « JavaScript heap out of memory », ajoutez temporairement un fichier swap de 2 Go (fallocate -l 2G /swapfile && mkswap /swapfile && swapon /swapfile) le temps du build, puis retirez-le. Pour les mises à jour, faites toujours une sauvegarde de la base PostgreSQL avant docker compose pull car les migrations Prisma ne sont pas réversibles.
Invariants critiques du premier démarrage
Trois variables d'environnement sont figées définitivement au premier démarrage de Cal.com. Les modifier après coup corrompt silencieusement toutes les intégrations stockées : l'application redémarre normalement, affiche zéro erreur, mais Google Calendar, Zoom et toutes les connexions OAuth cessent de fonctionner — leurs tokens sont chiffrés avec la clé d'origine, désormais incompatible. Ce comportement est documenté dans calcom/docker issue #333 et calcom/cal.diy issue #13290 : des utilisateurs ont perdu toutes leurs intégrations après une mise à jour qui avait régénéré le fichier .env.
CALENDSO_ENCRYPTION_KEY — chiffre les tokens OAuth stockés en base. Toute modification invalide silencieusement toutes les intégrations existantes.
NEXTAUTH_URL — ancre les cookies de session. Un changement casse l'authentification pour tous les utilisateurs actifs.
NEXT_PUBLIC_WEBAPP_URL — intégrée dans les builds Next.js lors de la compilation. Changer cette valeur exige un rebuild complet et une reconnexion de toutes les intégrations.
Bonne pratique : copiez ces trois valeurs dans un gestionnaire de secrets (Bitwarden, HashiCorp Vault, Ansible Vault) dès leur génération. Si vous gérez votre VPS en infrastructure-as-code, stockez-les dans un vault chiffré — ne laissez jamais le fichier .env être leur seul emplacement.
Mettre à jour Cal.com en toute sécurité
Sauvegarder la base PostgreSQL
Avant toute mise à jour : docker exec cal-docker-db-1 pg_dump -U calcom calcom | gzip > /opt/backup/calcom-$(date +%Y%m%d).sql.gz. Les migrations Prisma ne sont pas réversibles — cette sauvegarde est votre seul filet.
Vérifier que CALENDSO_ENCRYPTION_KEY est inchangée
Comparez la valeur dans votre .env avec celle conservée dans votre gestionnaire de secrets. Si elles diffèrent, n'allez pas plus loin : restaurez la valeur d'origine avant de continuer. Une clé différente détruira toutes vos intégrations OAuth au redémarrage.
Tirer la nouvelle image et relancer
Mettez à jour avec docker compose pull && docker compose up -d. Suivez le démarrage avec docker compose logs -f calcom — attendez le message indiquant que le serveur est prêt avant de tester.
Vérifier les intégrations après la mise à jour
Ouvrez Paramètres → Intégrations et confirmez que chaque connexion existante (Google Calendar, Zoom, etc.) est toujours active. Un statut « non connecté » est le signe que la clé a changé entre deux démarrages — restaurez la sauvegarde et le .env d'origine.
Dépannage
Intégrations perdues après une mise à jour — La cause est presque toujours une CALENDSO_ENCRYPTION_KEY différente entre deux démarrages. Vérifiez que votre .env n'a pas été écrasé par un .env.example lors du pull. Comparez la valeur actuelle avec celle dans votre gestionnaire de secrets. Si les valeurs diffèrent : restaurez la base PostgreSQL, remettez l'ancienne clé dans le .env et relancez avec docker compose up -d.
Build « JavaScript heap out of memory » — Le compilateur Next.js manque de RAM. Solution : fallocate -l 2G /swapfile && mkswap /swapfile && swapon /swapfile, puis relancez docker compose build. Sur un VPS à 2 Go, le swap est souvent indispensable pour le premier build et les mises à jour majeures. Pensez à retirer le fichier swap une fois le build terminé.
Redirect loop ou « Unable to find valid origin » — NEXT_PUBLIC_WEBAPP_URL ne correspond pas à l'URL réelle. Vérifiez que cette variable est bien https://rdv.votredomaine.com (sans barre oblique finale, avec le bon domaine et le bon protocole HTTPS), que le reverse proxy ne modifie pas l'en-tête Host, puis relancez avec docker compose up -d --build pour forcer un rebuild avec la bonne URL.
Automatisez la sauvegarde de votre base PostgreSQL avec un cron quotidien. Exemple de commande à planifier : docker exec cal-docker-db-1 pg_dump -U calcom calcom | gzip > /opt/backup/calcom-$(date +%Y%m%d-%H%M).sql.gz. Conservez au minimum 7 jours de sauvegardes rotatives et externalisez-les sur un stockage objet (S3-compatible, Backblaze B2) : en cas de perte du VPS, la base PostgreSQL est la seule partie non-reproductible de votre instance Cal.com.