ITSkillsCenter
Blog

Excalidraw self-hosted : tableau blanc collaboratif — déploiement Caddy 2026

14 min de lecture

Excalidraw self-hosted : tableau blanc collaboratif — déploiement Caddy 2026

📍 Article principal de la série : Productivité PME en self-hosted : la stack open-source 2026

Cet article fait partie de la série « Productivité self-hosted ». Pour la vue d’ensemble (Penpot, Cal.com, Affine, Excalidraw, AppFlowy), commencez par le guide général.

Introduction

Combien de fois avez-vous, dans un atelier produit ou une réunion d’architecture technique, ouvert un tableau blanc Miro ou FigJam pour ressortir un schéma une heure plus tard, le partager dans Slack, puis ne plus jamais y revenir ? Ces outils SaaS facturent entre 8 et 16 USD par utilisateur et par mois, soit 4 800 à 9 600 FCFA, pour un usage qui reste marginal dans la plupart des PME ouest-africaines. Pour une équipe de dix personnes, on parle vite de 60 000 à 100 000 FCFA mensuels — un budget qui pourrait financer un VPS en région européenne pendant un an, hébergeant non pas un mais cinq services collaboratifs.

Excalidraw est devenu en cinq ans le standard de fait pour les schémas dessinés à main levée dans la communauté tech. Son rendu « bloc-notes » caractérisé, ses formes générées de façon procédurale, et sa simplicité d’utilisation le rendent particulièrement adapté à la diagramatisation rapide pendant les sessions de brainstorming. La version self-hosted permet à votre équipe de bénéficier des mêmes fonctionnalités — y compris la collaboration temps-réel — sans dépendance vis-à-vis d’un service tiers. Ce guide vous accompagne dans le déploiement complet d’Excalidraw avec son backend de collaboration, derrière Caddy comme reverse proxy. Caddy est choisi ici plutôt que Nginx car il gère le HTTPS automatiquement avec Let’s Encrypt, sans configuration manuelle des certificats.

Prérequis

  • VPS : Hetzner CX21 (2 vCPU, 4 Go RAM) suffit largement — ~4,15 €/mois
  • OS : Ubuntu 24.04 LTS
  • Nom de domaine : sous-domaine pointant vers l’IP du VPS (par exemple draw.votre-pme.sn)
  • Niveau requis : intermédiaire — manipulation Docker Compose, édition de fichiers de configuration
  • Temps estimé : 1 h 30 pour une installation complète et testée
  • Compte Hetzner ou tout autre fournisseur (Scaleway PRO1-S, OVH VLE-1 conviennent aussi)

1. Pourquoi Caddy plutôt que Nginx pour Excalidraw

Le choix du reverse proxy n’est pas anodin. Nginx reste un excellent serveur, mais pour un déploiement Excalidraw qui doit gérer du WebSocket pour la collaboration temps-réel et qui n’aura souvent qu’un ou deux services frontend à servir, Caddy présente trois avantages décisifs. Premièrement, la gestion automatique des certificats Let’s Encrypt sans configuration : il suffit d’écrire draw.votre-pme.sn dans le Caddyfile, et Caddy obtient et renouvelle le certificat tout seul. Deuxièmement, la configuration WebSocket native sans directive supplémentaire : Caddy détecte automatiquement les upgrades de protocole. Troisièmement, le format de configuration extrêmement lisible — un Caddyfile fait souvent dix lignes là où une configuration Nginx équivalente en fait cinquante.

Pour une PME qui ne dispose pas d’un administrateur système dédié et qui veut limiter le temps consacré à la maintenance d’infrastructure, Caddy est probablement le meilleur choix en 2026. Il consomme très peu de ressources (typiquement moins de 50 Mo de RAM) et a démontré sa stabilité dans des déploiements production sur les cinq dernières années. Si vous gérez déjà un parc de services derrière Nginx, vous pouvez bien sûr garder votre configuration existante — l’équivalent Nginx sera fourni en annexe à la fin de ce guide.

2. Architecture Excalidraw self-hosted

Comprendre la séparation entre les composants d’Excalidraw vous évitera des erreurs de débogage frustrantes. Le projet officiel se compose de plusieurs briques que vous pouvez déployer ensemble ou séparément selon vos besoins.

  • excalidraw : l’application web frontend (React) qui tourne dans le navigateur du client. Aucune donnée n’est stockée côté serveur dans la version de base — chaque dessin reste dans le localStorage du navigateur.
  • excalidraw-room : le serveur de collaboration WebSocket. Il ne stocke rien non plus : il ne fait que relayer les événements (mouvements de curseur, ajouts d’éléments) entre les utilisateurs connectés à la même salle.
  • excalidraw-storage-backend (optionnel) : un serveur léger qui permet le partage de dessins via lien — il stocke les dessins chiffrés côté client. Sans lui, les dessins ne peuvent pas être partagés via une URL publique.

Le point essentiel : Excalidraw applique le chiffrement de bout en bout côté client. La clé de déchiffrement est dans le fragment d’URL (après le #), qui n’est jamais transmis au serveur. Cela signifie que même votre propre serveur ne peut pas lire les dessins partagés. Cette propriété est précieuse pour les équipes manipulant des architectures sensibles ou des informations clientes confidentielles.

Étape 1 — Préparer le VPS et installer Docker

Cette étape établit un environnement propre pour héberger Excalidraw. Si vous avez déjà un VPS configuré pour d’autres services Docker, vous pouvez sauter directement à l’étape 2. Sinon, suivez la procédure complète : elle prend une dizaine de minutes et vous évitera des problèmes de permissions ou de versions plus tard.

# Connexion SSH au VPS Hetzner fraîchement créé
ssh root@<IP_DU_VPS>

# Mise à jour système et création d'un utilisateur non-root
apt update && apt upgrade -y
adduser deploy
usermod -aG sudo deploy
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy

# Installer Docker depuis le dépôt officiel (recommandé en 2026)
apt install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release; echo $VERSION_CODENAME) stable" | \
  tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
usermod -aG docker deploy

Une fois ces commandes exécutées, déconnectez-vous puis reconnectez-vous en tant qu’utilisateur deploy pour que l’appartenance au groupe Docker soit prise en compte. Vérifiez la version avec docker compose version — vous devriez voir au minimum la 2.30. Si vous obtenez une erreur de permission Docker, c’est que la session n’a pas rechargé le groupe : déconnectez complètement votre terminal SSH et reconnectez-vous, ne vous contentez pas de relancer un nouveau shell.

Étape 2 — Préparer la stack Docker Compose

Plutôt que d’installer chaque composant séparément, nous orchestrons l’ensemble avec un seul fichier docker-compose.yml. Cette approche permet de relancer toute la stack en une commande, de versionner la configuration dans Git, et de répliquer facilement le déploiement sur un environnement de test si besoin. Créez un dossier dédié dans /opt/excalidraw qui contiendra tout ce qui concerne ce service.

# Créer la structure de dossiers
sudo mkdir -p /opt/excalidraw
sudo chown deploy:deploy /opt/excalidraw
cd /opt/excalidraw

# Créer le docker-compose.yml
cat > docker-compose.yml <<'YAML'
services:
  excalidraw:
    image: excalidraw/excalidraw:latest
    restart: unless-stopped
    networks: [internal]
    environment:
      - PUBLIC_URL=https://draw.votre-pme.sn

  excalidraw-room:
    image: excalidraw/excalidraw-room:latest
    restart: unless-stopped
    networks: [internal]

  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports: ["80:80", "443:443"]
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks: [internal]
    depends_on: [excalidraw, excalidraw-room]

networks:
  internal:

volumes:
  caddy_data:
  caddy_config:
YAML

La stack contient trois services interconnectés via un réseau Docker privé nommé internal. Seul Caddy est exposé sur l’internet via les ports 80 et 443. Les volumes caddy_data et caddy_config persistent entre les redémarrages : ils stockent notamment le certificat Let’s Encrypt obtenu, ce qui évite à Caddy de redemander un certificat à chaque restart (et de risquer un dépassement du quota Let’s Encrypt).

Étape 3 — Écrire le Caddyfile

Le Caddyfile décrit comment Caddy doit router les requêtes entrantes. Pour Excalidraw, nous avons besoin de servir l’application web sur la racine et de proxifier les WebSockets vers le serveur de collaboration. Le format Caddy rend cette configuration triviale comparé à un équivalent Nginx.

# Toujours dans /opt/excalidraw
cat > Caddyfile <<'CADDY'
draw.votre-pme.sn {
    encode gzip zstd

    # Route /socket.io/ vers le serveur de collaboration
    @websocket {
        path /socket.io/*
    }
    handle @websocket {
        reverse_proxy excalidraw-room:80
    }

    # Tout le reste vers l'app frontend
    handle {
        reverse_proxy excalidraw:80
    }

    log {
        output file /data/access.log {
            roll_size 100mb
            roll_keep 5
        }
    }
}
CADDY

La directive encode gzip zstd active la compression à la volée — Excalidraw étant une SPA React, le bundle initial fait environ 1,2 Mo, gzip le ramène à 400 Ko, ce qui change radicalement l’expérience sur des connexions limitées. Les logs sont configurés pour tourner automatiquement à 100 Mo et conserver les 5 derniers fichiers, évitant la saturation disque sur un VPS modeste. Avant de lancer la stack, assurez-vous que votre enregistrement DNS A pour draw.votre-pme.sn pointe bien vers l’IP de votre VPS — sans ça, Caddy ne pourra pas valider la propriété du domaine auprès de Let’s Encrypt.

Étape 4 — Lancer la stack et vérifier la collaboration

Tout est en place. Le premier docker compose up va télécharger les images (environ 200 Mo), démarrer les conteneurs, puis Caddy va négocier automatiquement le certificat avec Let’s Encrypt. Cette négociation prend généralement entre 10 et 30 secondes lors du premier lancement. Si elle échoue, c’est presque toujours un problème DNS (l’enregistrement A n’a pas encore propagé) ou de port (un autre service occupe déjà 80 ou 443).

# Démarrer en arrière-plan
docker compose up -d

# Suivre les logs Caddy spécifiquement (pour voir l'obtention du certificat)
docker compose logs -f caddy --tail=50

# Une fois certificat obtenu, tester depuis l'extérieur :
curl -I https://draw.votre-pme.sn

# Tester la collaboration en ouvrant deux fenêtres incognito
# avec la même URL contenant un fragment de salle :
# https://draw.votre-pme.sn/#room=ABCDEF,clé_de_chiffrement

La commande curl -I doit renvoyer un HTTP/2 200 — si vous voyez HTTP/2 502, c’est que le frontend Excalidraw n’a pas terminé son démarrage, attendez 30 secondes. Pour tester la collaboration multi-utilisateurs, le plus simple est d’ouvrir deux fenêtres en navigation privée sur la même URL contenant un identifiant de salle. Vous devriez voir le curseur de l’autre fenêtre apparaître en temps réel et toute modification se synchroniser. Si la synchronisation ne fonctionne pas, vérifiez l’onglet Network des DevTools — vous devez voir une connexion wss://draw.votre-pme.sn/socket.io/ active.

Étape 5 — Sécuriser et limiter l’accès (optionnel mais recommandé)

Par défaut, votre Excalidraw self-hosted est accessible à toute personne connaissant l’URL. Pour un usage interne PME, on souhaite généralement restreindre l’accès aux seuls membres de l’équipe. Deux approches simples existent : l’authentification basique HTTP gérée par Caddy, ou la mise en place d’un proxy d’authentification comme Authelia (couvert dans un autre tutoriel du cluster).

# Pour l'authentification basique HTTP, générer un hash de mot de passe :
docker compose exec caddy caddy hash-password --plaintext "votre_mot_de_passe_fort"

# Le résultat est un hash bcrypt à coller dans le Caddyfile :
# Modifiez le bloc draw.votre-pme.sn pour ajouter avant les handle :
#
#   basic_auth {
#       equipe_pme JDJhJDE0JFhWRDdQNUlw...
#   }
#
# Puis recharger Caddy sans interruption :
docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile

L’authentification basique HTTP est rudimentaire (un seul couple login/mot de passe partagé par toute l’équipe), mais elle suffit largement pour une dizaine de collaborateurs internes qui veulent simplement empêcher l’indexation publique. Pour une gestion utilisateur fine avec rôles, comptes individuels et audit log, basculez sur Authelia — la configuration est plus longue mais offre une sécurité de niveau professionnel.

Adaptation au contexte ouest-africain

Trois aspects rendent Excalidraw particulièrement bien adapté aux PME francophones d’Afrique de l’Ouest. Premièrement, le poids minimal de l’application : le bundle JavaScript chargé une seule fois fait moins de 500 Ko après gzip, ce qui charge en quelques secondes même sur une connexion 3G dégradée. Pour une équipe répartie entre Dakar, Bamako et Cotonou, les conditions réseau peuvent varier énormément d’un site à l’autre, et un outil collaboratif léger fait toute la différence.

Deuxièmement, la nature WebSocket de la collaboration tolère bien les latences. Contrairement à un appel vidéo qui se dégrade vite au-delà de 200 ms de latence, le dessin collaboratif reste utilisable avec des latences de 500 ms à 1 seconde — vous voyez juste les autres curseurs avec un léger décalage. Pour les équipes hybrides où certains membres travaillent depuis des connexions 4G mobiles ou des lignes ADSL plus anciennes, c’est un avantage net par rapport à des outils plus exigeants comme Miro ou Mural.

Troisièmement, la persistence locale dans le navigateur (localStorage) signifie qu’un dessin sur lequel vous travaillez reste accessible même si la connexion tombe en cours de session. Vous pouvez continuer à dessiner hors-ligne, et la synchronisation reprend automatiquement au retour de la connexion. Ce comportement est particulièrement précieux pour les consultants en mission ou les commerciaux en déplacement qui ne peuvent pas garantir une connexion internet stable pendant toute leur réunion.

Erreurs fréquentes

Erreur Cause Solution
Caddy n’obtient pas le certificat DNS pas encore propagé ou port 80 bloqué Vérifier dig draw.votre-pme.sn, ouvrir le port 80 dans le firewall Hetzner
502 Bad Gateway Conteneur Excalidraw pas démarré Vérifier docker compose ps, relancer docker compose up -d
Curseurs collaboratifs absents WebSocket bloqué par un proxy intermédiaire Vérifier que wss:// passe via DevTools Network, vérifier la conf entreprise si présente
Erreur « Limit exceeded » Let’s Encrypt Trop de redemandes de certificat (test, redéploiement) Attendre 7 jours ou utiliser le staging Let’s Encrypt en attendant
Disque saturé après 6 mois Logs Caddy qui ne tournent pas Vérifier la directive roll_size dans le Caddyfile

Sauvegarder les dessins partagés

Si vous avez déployé le module excalidraw-storage-backend pour permettre le partage par lien, ses données sont stockées dans un volume Docker. Sauvegardez-le en même temps que vos autres backups système. La taille reste modeste (les dessins Excalidraw chiffrés font typiquement quelques centaines de kilo-octets), donc une simple synchronisation rsync vers une Storage Box Hetzner ou un bucket S3 quotidienne suffit largement. Pour les dessins importants, l’export manuel au format .excalidraw ou PNG depuis l’interface utilisateur reste la meilleure garantie : le fichier est petit, indépendant, et lisible par n’importe quelle instance Excalidraw future.

Articles connexes

FAQ

Excalidraw conserve-t-il mes dessins sur le serveur ?
Non, dans la configuration de base de ce tutoriel, aucun dessin n’est stocké côté serveur. Tout reste dans le localStorage de votre navigateur. Si vous activez l’option de partage par lien (storage-backend), les dessins partagés sont stockés sous forme chiffrée que le serveur ne peut pas déchiffrer.

Combien d’utilisateurs peuvent collaborer simultanément sur un dessin ?
Le serveur de collaboration peut techniquement gérer des dizaines d’utilisateurs sur une même salle, mais l’expérience reste optimale jusqu’à 10-15 collaborateurs simultanés. Au-delà, l’écran devient illisible avec trop de curseurs.

Puis-je migrer mes dessins Miro ou FigJam vers Excalidraw ?
Pas automatiquement. Les formats sont incompatibles. Vous devrez exporter vos dessins existants en PNG/PDF puis les recréer manuellement dans Excalidraw. C’est l’occasion d’un nettoyage souvent bénéfique.

Excalidraw fonctionne-t-il hors-ligne ?
Oui, totalement. Une fois la PWA installée (icône d’installation dans la barre d’URL), Excalidraw fonctionne sans connexion internet. La collaboration temps-réel nécessite la connexion mais le dessin individuel non.

Que faire si Excalidraw upstream sort une nouvelle version ?
Mettez à jour avec docker compose pull && docker compose up -d. Les images Docker officielles sont mises à jour sous quelques jours après chaque release. Lisez le CHANGELOG avant pour repérer d’éventuels changements de configuration.

Pour aller plus loin

Mots-clés : excalidraw self-hosted, tableau blanc collaboratif open-source, caddy reverse proxy, docker compose hetzner, alternative miro, brainstorming équipe pme.

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité