SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-21

Quel outil de diagrammes auto-hébergé choisir ?

draw.io et Excalidraw rendent les diagrammes dans le navigateur, tandis que Kroki reçoit leur texte via HTTP. Découvrez ce que voit réellement votre VPS.

Quel outil de diagrammes auto-hébergé devez-vous utiliser ?

Les outils de diagrammes auto-hébergés se répartissent en deux catégories, et cette distinction compte davantage que la liste des fonctionnalités. draw.io et Excalidraw sont des applications web : le conteneur fournit le JavaScript, votre navigateur crée le diagramme et le serveur ne voit jamais son contenu. Kroki fonctionne à l’inverse. Vous lui envoyez le texte du diagramme via HTTP et il vous renvoie une image. Chaque diagramme passe donc par votre propre machine.

Utilisez draw.io si vous voulez un éditeur complet à côté d’un wiki. Utilisez Excalidraw si vous voulez un espace de croquis rapide et acceptez que rien ne soit enregistré en dehors du navigateur dans lequel vous avez dessiné. Utilisez Kroki si vos diagrammes sont du texte versionné dans git, à côté du code qu’ils décrivent.

Ce que l’auto-hébergement d’un outil de création de diagrammes change réellement

Soyez précis sur les éléments qui utilisent votre serveur, car ce point détermine à lui seul si l’auto-hébergement apporte de la confidentialité ou uniquement de la disponibilité.

  • draw.io effectue le rendu dans le navigateur. Votre conteneur sert le code de l’application. Le fichier est enregistré à l’endroit que vous indiquez à l’éditeur.
  • Excalidraw effectue le rendu dans le navigateur et conserve la scène actuelle dans le stockage local de ce navigateur. Rien n’est écrit côté serveur.
  • Kroki effectue le rendu sur le serveur. La source du diagramme et l’image finale existent toutes deux dans votre conteneur.

Seul le troisième cas transfère les données vers du matériel que vous contrôlez. Pour les deux premiers, l’auto-hébergement apporte le contrôle des ressources et la disponibilité : le JavaScript provient de votre hôte, et l’éditeur continue donc de fonctionner lorsqu’un tiers subit une panne, modifie ses conditions d’utilisation ou devient inaccessible depuis votre réseau. Pour certaines équipes, cela représente une valeur réelle. C’est différent de l’affirmation selon laquelle « le diagramme ne quitte jamais les locaux ».

draw.io : un conteneur officiel qui ne stocke rien

Le projet publie sa propre image, et le démarrage rapide de son README tient en une ligne.

docker run -it --rm --name="draw" -p 8080:8080 -p 8443:8443 jgraph/drawio

Cette commande publie l’éditeur sur toutes les adresses du serveur. Sur un VPS, liez le port publié à l’interface loopback et accédez-y via un reverse proxy ou un tunnel SSH.

docker run -d --name drawio --restart unless-stopped -p 127.0.0.1:8080:8080 jgraph/drawio

Ouvrez http://127.0.0.1:8080/?offline=1&https=0 via le tunnel. Le README décrit ?offline=1 comme « une fonctionnalité de sécurité qui désactive la prise en charge du stockage cloud ». Sans ce paramètre, l’éditeur propose Google Drive, OneDrive et GitHub comme cibles d’enregistrement, c’est-à-dire des serveurs tiers.

La liaison à 127.0.0.1 empêche ce port d’être accessible depuis Internet. Un simple -p 8080:8080 n’est pas filtré par ufw, car Docker ajoute ses propres règles iptables avant les chaînes gérées par ufw. Le pare-feu semble donc correctement configuré alors que le port répond aux requêtes du monde entier. La publication Docker qui contourne directement ufw décrit le mécanisme et la correction.

Deux variables d’environnement deviennent importantes dès que l’éditeur n’est plus accessible uniquement sur localhost.

services:
  drawio:
    image: jgraph/drawio
    container_name: drawio
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      DRAWIO_SERVER_URL: "https://drawio.example.com/"
      DRAWIO_BASE_URL: "https://drawio.example.com"

La barre oblique finale est volontaire. Le README définit DRAWIO_SERVER_URL comme l’« URL de déploiement publique avec une barre oblique finale » et DRAWIO_BASE_URL comme la « même URL sans barre oblique finale », utilisées par le viewer, la lightbox et les chemins de code d’intégration. Si vous servez l’éditeur sous un sous-chemin tel que https://www.example.com/drawio/, les deux valeurs doivent inclure ce sous-chemin, car l’application construit ses URL de viewer et d’intégration à partir de ces valeurs.

Persistance : il n’y en a pas, et c’est voulu. Aucun volume n’apparaît dans ce fichier Compose, car le conteneur ne contient aucune donnée de diagramme. Un fichier .drawio est un fichier XML que l’éditeur transmet à votre navigateur. La cible d’enregistrement que vous choisissez détermine ensuite où il est enregistré : un téléchargement sur votre propre machine ou l’application qui a intégré l’éditeur. Sauvegardez cette destination. Si elle correspond à un dossier sur le VPS, c’est ce dossier qu’il faut protéger, ainsi que le gestionnaire de fichiers que vous utilisez pour y accéder, car draw.io ne conserve aucune copie.

Ce qui quitte malgré tout votre serveur. L’export au format PDF est le cas le plus évident. Le README décrit DRAWIO_SELF_CONTAINED comme suit : « Définir sur 1 pour acheminer les requêtes d’export via ExportProxyServlet de Tomcat (/service/0), au lieu d’appeler directement le serveur d’export ». Il faut comprendre cette phrase à l’envers : par défaut, une requête d’export ne reste pas dans votre déploiement. Le projet publie également jgraph/export-server, un « serveur autonome d’export d’images de draw.io », pour les utilisateurs qui veulent effectuer ce rendu sur leur propre matériel. ENABLE_DRAWIO_PROXY est désactivé par défaut et active un endpoint /proxy qui récupère des URL d’images externes pour le compte du navigateur. Laissez-le désactivé sauf si vous en avez besoin.

Excalidraw : un bundle statique sans serveur en arrière-plan

La page officielle de l’image fournit cette commande.

docker run --rm -dit --name excalidraw -p 5000:80 excalidraw/excalidraw:latest

Liez le port publié à loopback, pour la même raison que précédemment.

docker run -d --name excalidraw --restart unless-stopped -p 127.0.0.1:5000:80 excalidraw/excalidraw:latest

Dans le conteneur, nginx sert un bundle JavaScript compilé sur le port 80. L’image publiée fait environ 41 MB une fois compressée (Docker Hub, août 2026), ce qui montre qu’elle contient très peu de choses. Il n’y a ni base de données, ni session store, ni répertoire d’upload, car rien ne doit être stocké sur le serveur.

La page de l’image indique clairement la limite : « Pour le moment, l’auto-hébergement de votre propre instance ne prend pas en charge les fonctions de partage et de collaboration. » Les boutons sont toujours présents dans l’interface, il est donc utile d’en connaître la raison. La collaboration en temps réel nécessite un serveur websocket, publié séparément sous le nom excalidraw/excalidraw-room. Un lien de partage nécessite un service de stockage pour conserver la scène chiffrée. Les adresses de ces deux services sont intégrées au bundle lors du build sous forme de variables Vite (VITE_APP_WS_SERVER_URL, VITE_APP_BACKEND_V2_GET_URL, VITE_APP_BACKEND_V2_POST_URL), et les valeurs de production du dépôt pointent vers les services hébergés par Excalidraw. Vite remplace ces valeurs pendant le build ; elles deviennent donc des chaînes littérales dans le JavaScript. Les définir comme variables d’environnement du conteneur ne change rien, car aucun code ne les lit au runtime. Pour faire pointer la collaboration vers votre propre room server, vous devez construire le frontend depuis les sources avec vos propres valeurs. Vérifiez l’état de ce serveur avant de concevoir votre déploiement autour de lui : en août 2026, l’image excalidraw/excalidraw-room sur Docker Hub n’avait pas été reconstruite depuis plus de deux ans.

Où un dessin est réellement stocké. La scène se trouve dans le local storage du navigateur, sur cet appareil et pour cette origine. Ouvrez la même URL dans une fenêtre privée : le canvas est vide. C’est le moyen le plus rapide de le vérifier. La suppression des données du site efface le dessin, et aucune copie serveur ne permet de le restaurer. Apprenez donc aux utilisateurs à utiliser « Save to... » et à conserver le fichier .excalidraw, au format JSON, dans un emplacement sauvegardé. Une instance partagée fournit à chaque personne son propre canvas privé. Considérez-la comme un bloc-notes personnel simplement hébergé sur un serveur.

Kroki : les diagrammes sous forme de code, rendus sur votre serveur

Kroki est une passerelle HTTP unique placée devant plusieurs moteurs de rendu. Vous envoyez du texte avec POST et vous récupérez un fichier SVG ou PNG. Graphviz, PlantUML, D2 et plusieurs autres moteurs sont intégrés à l’image de la passerelle. Le rendu Mermaid, BPMN et Excalidraw s’exécute dans des conteneurs associés ; Compose est donc la méthode adaptée pour les lancer. Cet exemple vient de la documentation de Kroki.

services:
  kroki:
    image: yuzutech/kroki
    depends_on:
      - mermaid
      - bpmn
      - excalidraw
    environment:
      - KROKI_MERMAID_HOST=mermaid
      - KROKI_BPMN_HOST=bpmn
      - KROKI_EXCALIDRAW_HOST=excalidraw
    ports:
      - "8000:8000"
    tmpfs:
      - /tmp:exec
  mermaid:
    image: yuzutech/kroki-mermaid
    expose:
      - "8002"
  bpmn:
    image: yuzutech/kroki-bpmn
    expose:
      - "8003"
  excalidraw:
    image: yuzutech/kroki-excalidraw
    expose:
      - "8004"

expose n’expose aucun port sur l’hôte. Les conteneurs associés sont donc accessibles uniquement depuis la passerelle sur le réseau Compose. C’est le comportement recherché. Remplacez la ligne de la passerelle par "127.0.0.1:8000:8000", sauf si le wiki qui l’appelle s’exécute sur un autre hôte. Si vous n’avez jamais écrit de fichier Compose sur un serveur, exécuter Docker Compose sur un VPS présente la structure des fichiers et le cycle docker compose up -d.

Exécutez deux tests de fonctionnement, dans cet ordre, car ils échouent pour des raisons différentes.

curl -s -X POST http://127.0.0.1:8000/graphviz/svg \
  -H 'Content-Type: text/plain' \
  --data-binary 'digraph G {Hello->World}' | head -c 60

Graphviz s’exécute dans la passerelle. Un document SVG obtenu ici confirme donc que la passerelle elle-même fonctionne. Testez maintenant le chemin qui traverse plusieurs conteneurs.

curl -s -X POST http://127.0.0.1:8000/mermaid/svg \
  -H 'Content-Type: text/plain' \
  --data-binary 'graph TD; A-->B;' | head -c 60

Le SVG renvoyé par la deuxième commande confirme que KROKI_MERMAID_HOST a été résolu et que le conteneur associé a répondu. Si le premier test fonctionne mais pas le deuxième, le problème se situe entre les deux conteneurs. Consultez donc docker compose logs kroki avant de modifier la syntaxe du diagramme.

La méthode GET encode le diagramme dans l’URL. C’est ainsi qu’un wiki peut intégrer une image sans aucun plugin. La documentation fournit cet encodeur.

cat hello.dot | python -c "import sys; import base64; import zlib; print(base64.urlsafe_b64encode(zlib.compress(sys.stdin.read().encode('utf-8'), 9)).decode('ascii'))"

Sur Ubuntu, cette commande affiche python: command not found, car le système fournit python3 et aucun python sans numéro de version. Utilisez python3. La sortie est ajoutée à la fin d’une URL de la forme /{diagram-type}/{output-format}/{encoded-diagram}, et toute balise <img> peut pointer vers cette URL. Il existe toutefois une limite : KROKI_MAX_URI_LENGTH vaut 4096 octets par défaut. Un diagramme long doit donc être envoyé avec POST.

Kroki lit le texte que vous lui envoyez. Ses paramètres de sécurité sont donc déterminants. KROKI_SAFE_MODE vaut SECURE par défaut, le niveau le plus restrictif des trois, et KROKI_PLANTUML_ALLOW_INCLUDE vaut false par défaut. Ces valeurs par défaut existent parce que la directive !include de PlantUML lit des fichiers et des URL depuis le point de vue du moteur de rendu. Si vous assouplissez ces paramètres sur un endpoint accessible à tous, vous donnez à Internet accès à un lecteur de fichiers exécuté dans votre conteneur. Ne les modifiez pas sans savoir quel chemin d’inclusion est nécessaire ; indiquez alors ce chemin avec KROKI_PLANTUML_INCLUDE_PATH.

Mémoire : quel composant pèse le plus sur un petit VPS

L’ordre est prévisible dès que vous savez ce que chaque conteneur exécute.

  • L’image Excalidraw utilise nginx pour servir des fichiers statiques. C’est de loin la moins coûteuse des trois.
  • draw.io utilise Tomcat, un serveur d’applications Java. Il embarque donc une JVM (machine virtuelle Java), même lorsque personne ne dessine.
  • La gateway Kroki est également un service Java, fourni sous forme de fichier jar pour les installations manuelles.
  • Le compagnon mermaid est le plus coûteux. Son Dockerfile installe Chromium et définit PUPPETEER_EXECUTABLE_PATH=/usr/lib/chromium/chrome, car Mermaid effectue le rendu avec un véritable moteur de navigateur.

Les valeurs au repos sont donc peu représentatives. La valeur importante est le pic observé pendant le rendu d’un diagramme. KROKI_MERMAID_MAX_CONCURRENCY vaut 6 par défaut : six rendus dans un navigateur peuvent donc être exécutés simultanément. Mesurez la consommation sur votre propre serveur au lieu de vous fier à une valeur publiée.

docker stats --no-stream
docker system df

Exécutez d’abord la commande lorsque tout est au repos, puis de nouveau pendant que vous effectuez en boucle le rendu d’un grand diagramme mermaid. Si le pic est trop élevé sur une petite offre, définissez une limite au lieu de l’estimer : définir des limites de mémoire sur un service Compose présente la syntaxe et le comportement lorsqu’un conteneur atteint sa limite. Supprimer le compagnon mermaid est également une solution valide, car la gateway continue de servir tous les renderers qu’elle intègre.

Aucun de ces logiciels ne fournit de gestion des utilisateurs. Placez donc un système d’authentification devant eux.

draw.io ne gère aucun compte. Excalidraw ne gère aucun compte. Kroki répond à toute requête qui lui parvient. L’authentification doit donc être assurée par le proxy.

sudo apt update && sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd alice

htpasswd -c crée le fichier et remplace un fichier existant. Utilisez donc -c la première fois, et jamais ensuite.

server {
    listen 443 ssl;
    server_name drawio.example.com;

    location / {
        auth_basic "diagrams";
        auth_basic_user_file /etc/nginx/.htpasswd;
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Appliquez la configuration avec sudo nginx -t && sudo systemctl reload nginx. La partie nginx -t est la plus importante : si la configuration est incorrecte, un reload conserve l’ancienne configuration. Le site continue donc de fonctionner, mais votre modification n’est pas active. La configuration du reverse proxy, expliquée ligne par ligne détaille le bloc d’en-têtes et les chemins des certificats absents de cet extrait.

L’authentification de base n’est pas adaptée à Kroki, et il est utile d’en comprendre la raison. Une page de wiki intègre une image Kroki avec une balise <img>. Le navigateur du lecteur récupère cette URL comme une sous-ressource. Il n’envoie pas vos identifiants à une autre origine. La requête reçoit donc une réponse 401 et chaque diagramme de la page s’affiche comme une image manquante. Gardez plutôt Kroki hors de l’Internet public. Placez-le sur le même réseau Docker que le conteneur du wiki et laissez le wiki y accéder par le nom du service, sans publier le moindre port sur l’hôte. Résolution des noms de service par les réseaux Compose explique le mécanisme qui permet cela.

Des schémas associés à un wiki auto-hébergé

C’est la raison habituelle pour laquelle on cherche ce type de solution. Une page de wiki a besoin d’une image, et personne ne veut que cette image soit une capture d’écran provenant de l’ordinateur portable de quelqu’un.

BookStack propose une intégration native avec un éditeur auto-hébergé. Son URL d’intégration par défaut est https://embed.diagrams.net/?embed=1&proto=json&spin=1&configure=1, et une ligne dans .env permet de la rediriger vers votre conteneur.

DRAWIO=https://drawio.example.com/?embed=1&proto=json&spin=1&configure=1

Copiez la chaîne de requête à l’identique. La documentation de BookStack indique que embed=1&proto=json&spin=1 « sont nécessaires au fonctionnement de l’intégration avec BookStack », car ces paramètres sélectionnent le protocole de messages JSON utilisé par les deux pages pour communiquer. La même page recommande stealth=1 « si vous ne voulez pas utiliser d’autres services externes ». C’est l’option à ajouter lorsque l’objectif de l’auto-hébergement est de bloquer les appels sortants. Une fois cette configuration en place, BookStack enregistre le schéma dans son propre stockage d’images, à côté de la page. La sauvegarde du wiki que vous effectuez déjà sert donc aussi de sauvegarde des schémas.

Si vous n’avez pas encore choisi le wiki, commencez par régler cette question. Choisir entre BookStack, Wiki.js et Outline est l’étape précédente, car le wiki détermine la manière dont un schéma est associé à une page et, par conséquent, lequel de ces outils vous devez lui ajouter.

Modes de panne et messages affichés

L’éditeur de diagrammes s’ouvre dans BookStack et tourne indéfiniment. Le spinner attend spin=1 une négociation qui n’arrive jamais. Vérifiez que embed=1&proto=json&spin=1 figure dans la valeur DRAWIO et que la partie correspondant à l’hôte ne contient pas de faute de frappe.

Le cadre de l’éditeur reste vide sur un wiki HTTPS. La console du navigateur signale du contenu mixte lors du chargement de http:// dans https://. Le navigateur bloque le cadre et draw.io ne s’exécute jamais. Servez l’éditeur en HTTPS.

Kroki renvoie 413 Request Entity Too Large. Ce message vient de nginx, pas de Kroki. La valeur par défaut de client_max_body_size dans nginx est de 1 MB et la valeur par défaut de KROKI_MAX_BODY_SIZE dans Kroki est 1mb. Une source PlantUML volumineuse atteint donc la limite la plus basse. Augmentez les deux valeurs.

Mermaid échoue alors que graphviz fonctionne. La gateway fonctionne, mais le companion n’est pas joignable. Vérifiez que le service est démarré avec docker compose ps, puis vérifiez que KROKI_MERMAID_HOST correspond au nom du service. Cette variable vaut par défaut 127.0.0.1, ce qui désigne la gateway elle-même depuis le conteneur de la gateway.

La collaboration Excalidraw ne se connecte jamais. Si vous avez compilé un frontend utilisant votre propre room server et que vous l’avez placé derrière nginx, le proxy doit mettre à niveau la connexion avec proxy_set_header Upgrade $http_upgrade; et proxy_set_header Connection "upgrade";. Sans ces directives, la négociation websocket reçoit une réponse HTTP ordinaire et la session ne démarre jamais.

Le canevas est vide après le nettoyage du navigateur. La scène était stockée dans le stockage local de cet appareil et aucune copie n’existe sur le serveur. La solution relève d’une habitude plutôt que d’un réglage : exportez le fichier .excalidraw pour tout contenu à conserver.

FAQ

Le fait d’auto-héberger draw.io garde-t-il mes diagrammes privés ?

Le code de l’application reste sur votre serveur, mais cela ne signifie pas que les données restent privées. draw.io effectue le rendu dans votre navigateur. Le conteneur ne contient donc jamais de diagramme. La confidentialité dépend alors de l’emplacement où vous enregistrez le fichier et des appels sortants que vous laissez activés. Utilisez ?offline=1 pour désactiver les cibles de stockage cloud. N’oubliez pas que les demandes d’export sont envoyées à un serveur d’exportation, sauf si vous définissez DRAWIO_SELF_CONTAINED=1 et exécutez vous-même jgraph/export-server.

Pourquoi la collaboration ne fonctionne-t-elle pas sur mon instance Excalidraw auto-hébergée ?

La page officielle de l’image indique que l’auto-hébergement « ne prend pas en charge les fonctionnalités de partage ou de collaboration ». La collaboration en temps réel nécessite le serveur WebSocket excalidraw/excalidraw-room. Les liens de partage nécessitent quant à eux un service de stockage. Les adresses de ces deux services sont intégrées au bundle JavaScript lors de la compilation, sous forme de variables Vite telles que VITE_APP_WS_SERVER_URL. Définir une variable d’environnement sur le conteneur en cours d’exécution n’a donc aucun effet. Pour utiliser votre propre serveur de salles, vous devez compiler le frontend depuis les sources avec vos valeurs.

Comment effectuer le rendu de diagrammes Mermaid sur mon propre serveur ?

Exécutez Kroki avec son conteneur compagnon Mermaid et définissez KROKI_MERMAID_HOST sur le nom de ce service. Envoyez ensuite le texte du diagramme avec une requête POST vers /mermaid/svg et lisez le SVG dans la réponse. Vous pouvez aussi encoder le diagramme dans une URL GET et pointer une balise <img> vers cette URL. Le conteneur compagnon pilote Chromium avec Puppeteer, car Mermaid a besoin d’un moteur de navigateur. Prévoyez donc suffisamment de mémoire : KROKI_MERMAID_MAX_CONCURRENCY est défini par défaut sur six rendus simultanés.

Dois-je placer un mot de passe devant ces outils ?

Oui, car aucun de ces outils ne gère de comptes. draw.io et Excalidraw donnent accès à un éditeur complet à toute personne qui découvre l’URL. Kroki effectue quant à lui le rendu de tout texte qui lui est envoyé. Une authentification basique au niveau du reverse proxy suffit pour les deux éditeurs. Pour Kroki, laissez le service non publié sur un réseau Docker partagé avec le wiki. Une requête <img> provenant du navigateur d’un lecteur ne transmettra pas les identifiants vers une autre origine, et chaque diagramme intégré ne fonctionnerait plus.

#diagrams#drawio#excalidraw#mermaid#kroki#docker