Développement10 min de lecture

Héberger HedgeDoc sur VPS : l'éditeur Markdown collaboratif

Google Docs est pratique jusqu'au jour où votre équipe préfère écrire de la documentation technique en Markdown, intégrer des blocs de code avec coloration syntaxique, ou simplement éviter d'héberger ses notes de réunion et spécifications chez Google. HedgeDoc (anciennement CodiMD) est un éditeur Markdown collaboratif en temps réel, open source (AGPL-3.0), qui se déploie en moins de quinze minutes sur un VPS avec Docker Compose. Chaque note a une URL partageable, l'édition est simultanée à plusieurs curseurs, et vos données restent sur votre infrastructure.

Pourquoi HedgeDoc plutôt que Notion ou Google Docs ?

Notion et Google Docs ont chacun leurs avantages — mais tous deux hébergent vos données sur leurs serveurs, imposent leurs formats propriétaires et peuvent modifier leurs tarifs ou conditions sans préavis. Pour une équipe technique qui documente des architectures, rédige des API docs, prépare des RFCs ou gère des notes de réunion, HedgeDoc offre une alternative radicalement différente :

- Markdown natif avec rendu temps réel côté éditeur et aperçu split-screen.
- Édition collaborative avec plusieurs curseurs visibles simultanément.
- Blocs de code avec coloration syntaxique pour 200+ langages.
- Diagrammes intégrés : Mermaid, PlantUML, Vega-lite, flowcharts directement dans la note.
- Formules mathématiques : LaTeX via MathJax.
- Export : PDF, Markdown, HTML en un clic depuis l'interface.
- Hébergement sur votre VPS : vos données ne quittent pas votre infrastructure.

Prérequis avant de commencer

  • Un VPS sous Ubuntu 22.04 ou Debian 12 avec au minimum 1 Go de RAM (512 Mo peut fonctionner en test, mais 1 Go est recommandé pour la collaboration simultanée).
  • Docker Engine ≥ 24 et Docker Compose V2 installés.
  • Un nom de domaine pointant vers votre VPS pour configurer TLS (obligatoire en production : HedgeDoc utilise des WebSockets qui nécessitent une connexion sécurisée).
  • Le port 3000 disponible (HedgeDoc écoute sur ce port par défaut).
  • Nginx installé pour le reverse proxy (avec support WebSocket — indispensable).

Installation de HedgeDoc avec Docker Compose

01

Étape 1 — Créer la structure du projet

mkdir -p /opt/hedgedoc && cd /opt/hedgedoc

Créez le fichier docker-compose.yml :

version: '3.8'
services:
  database:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: hedgedoc
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: hedgedoc
    volumes:
      - db-data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U hedgedoc']
      interval: 10s
      timeout: 5s
      retries: 5

  app:
    image: quay.io/hedgedoc/hedgedoc:1.11.1
    environment:
      CMD_DB_URL: postgres://hedgedoc:${POSTGRES_PASSWORD}@database/hedgedoc
      CMD_DOMAIN: ${CMD_DOMAIN}
      CMD_PROTOCOL_USESSL: 'true'
      CMD_SESSION_SECRET: ${CMD_SESSION_SECRET}
      CMD_ALLOW_ANONYMOUS: 'false'
      CMD_ALLOW_REGISTRATION: 'true'
      CMD_ALLOW_FREEURL: 'true'
    volumes:
      - uploads:/hedgedoc/public/uploads
    ports:
      - '127.0.0.1:3000:3000'
    depends_on:
      database:
        condition: service_healthy
    restart: unless-stopped

volumes:
  db-data:
  uploads:
02

Étape 2 — Créer le fichier d'environnement

cat > /opt/hedgedoc/.env << 'EOF'
POSTGRES_PASSWORD=MOT_DE_PASSE_FORT_ICI
CMD_DOMAIN=hedgedoc.votredomaine.com
CMD_SESSION_SECRET=UNE_CHAINE_ALEATOIRE_LONGUE_ET_FIXE
EOF

⚠️ CMD_SESSION_SECRET doit être une valeur fixe générée une seule fois et ne jamais changer. Si vous la changez après le premier démarrage, toutes les sessions existantes seront invalidées. Générez-la avec :

openssl rand -base64 32
03

Étape 3 — Lancer les conteneurs

docker compose up -d

Vérifiez que les deux conteneurs sont opérationnels :

docker compose ps
docker compose logs app

HedgeDoc va migrer automatiquement la base de données PostgreSQL au premier démarrage. Une fois que les logs affichent listening on port 3000, l'application est prête.

04

Étape 4 — Configurer Nginx avec support WebSocket

⚠️ La configuration Nginx pour HedgeDoc doit inclure un bloc /socket.io/ avec les en-têtes WebSocket appropriés. Omettre ce bloc provoque des échecs silencieux de la collaboration en temps réel : les notes s'ouvrent mais les changements des autres utilisateurs n'apparaissent pas.

apt install -y nginx certbot python3-certbot-nginx

cat > /etc/nginx/sites-available/hedgedoc << 'EOF'
server {
    server_name hedgedoc.votredomaine.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /socket.io/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
EOF

ln -s /etc/nginx/sites-available/hedgedoc /etc/nginx/sites-enabled/
certbot --nginx -d hedgedoc.votredomaine.com
nginx -t && systemctl reload nginx
05

Étape 5 — Créer le premier compte utilisateur

Ouvrez votre navigateur sur https://hedgedoc.votredomaine.com. Sur la page d'accueil, cliquez sur Sign InRegister pour créer votre premier compte administrateur.

Si vous avez défini CMD_ALLOW_REGISTRATION: 'false', vous pouvez créer le premier compte via la CLI :

docker compose exec app npm run manage_users -- --add [email protected] --password VotreMotDePasse

Une fois connecté, cliquez sur New note pour créer votre première note collaborative.

Fonctionnalités à découvrir

Partager une note : chaque note HedgeDoc a une URL unique. Cliquez sur le bouton de partage pour obtenir l'URL et choisissez le mode d'accès (lecture seule, commentaires, édition). Envoyez l'URL à vos collaborateurs — ils peuvent éditer sans compte si vous l'autorisez.

Insérer un diagramme Mermaid :

graph LR
    A[Client] --> B[API]
    B --> C[Base de données]
    C --> D[Cache Redis]

HedgeDoc rend le diagramme en temps réel dans l'aperçu.

Exporter la note : dans le menu (icône ≡), choisissez Export pour télécharger en Markdown, HTML ou PDF. L'export PDF utilise un navigateur headless côté serveur — il nécessite que Chromium soit disponible, ce qui est inclus dans l'image Docker officielle.

Mode présentation : ajoutez --- entre les sections pour les transformer en slides. Dans le menu, choisissez Slide Mode pour passer en présentation plein écran.

Bloc Socket.io manquant = collaboration silencieusement cassée

C'est le piège le plus fréquent avec HedgeDoc derrière Nginx. Symptôme : l'interface s'affiche normalement, vous pouvez écrire dans la note, mais les modifications des autres utilisateurs n'apparaissent pas en temps réel — sans aucun message d'erreur visible.

Cause : la route /socket.io/ nécessite une connexion WebSocket (protocole ws:// ou wss://). Sans le bloc Nginx dédié qui envoie les en-têtes Upgrade: websocket et Connection: upgrade, Nginx traite la requête comme du HTTP classique et la connexion temps réel échoue silencieusement.

Vérification rapide :

# Depuis votre poste, vérifiez que le WebSocket est atteignable
curl -v -N -H "Connection: Upgrade" -H "Upgrade: websocket" \
  https://hedgedoc.votredomaine.com/socket.io/?transport=websocket

Vous devez voir 101 Switching Protocols dans la réponse. Un 200 ou un 400 indique que le bloc /socket.io/ est manquant ou mal configuré.

Proxy sans slash final = page blanche ou erreur 404

Dans la directive proxy_pass de Nginx, la présence ou l'absence du slash final change le comportement :

# CORRECT — sans slash final (HedgeDoc gère lui-même ses routes)
proxy_pass http://127.0.0.1:3000;

# INCORRECT — le slash final fait que Nginx réécrit le chemin
proxy_pass http://127.0.0.1:3000/;

Avec un slash final, une requête vers /s/ma-note devient une requête vers /s/ma-note dans un contexte différent, cassant les redirections et le routage interne de HedgeDoc. Résultat : page blanche ou erreur 404 sur les notes. Toujours omettre le slash final dans proxy_pass quand vous configurez HedgeDoc.

HedgeDoc vs Notion vs Confluence

CritèreHedgeDoc (self-hosted)NotionConfluence (Cloud)
PrixGratuit (coût VPS)Gratuit jusqu'à 10 membres, ~10$/membre/mois~5.75$/utilisateur/mois (min 10)
FormatMarkdown natifBlocs propriétairesEditeur riche (WYSIWYG)
Collaboration temps réelOui (WebSocket)OuiOui
Diagrammes natifsMermaid, PlantUML, Vega-liteLimité (via intégrations)Via macros (Confluence)
Blocs de code200+ langages avec colorationOui (limité)Oui (via plugin)
Hébergement donnéesVotre VPSServeurs Notion (US)Serveurs Atlassian
Export MarkdownOui (natif)Partiel (import/export)Non natif
Formules LaTeXOui (MathJax)OuiVia plugin
Mode présentationOui (intégré)NonVia plugin

Gérer les utilisateurs et les permissions

HedgeDoc gère trois niveaux d'accès par note, définis dans le menu de chaque note :

- Freely : tout le monde peut éditer, sans compte.
- Editable : seuls les utilisateurs connectés peuvent éditer.
- Limited : seul le propriétaire peut éditer, les autres peuvent commenter.
- Locked : lecture seule pour tous sauf le propriétaire.
- Private : accessible uniquement au propriétaire.

Désactiver l'inscription publique :

Si votre instance est publique, un inconnu pourrait créer un compte. Pour réserver l'accès à votre équipe, définissez CMD_ALLOW_REGISTRATION: 'false' dans .env et recréez le conteneur (docker compose up -d --force-recreate app). Créez ensuite les comptes via la CLI.

Activer l'authentification OAuth (GitHub, GitLab…) :

HedgeDoc supporte OAuth2 pour GitHub, GitLab, Google, Twitter et plusieurs autres fournisseurs. Configurez les variables CMD_GITHUB_CLIENTID / CMD_GITHUB_CLIENTSECRET dans .env après avoir créé une OAuth App sur GitHub.

Sauvegardes et mises à jour

Sauvegarder les données :

# Sauvegarde de PostgreSQL
docker compose exec -T database \
  pg_dump -U hedgedoc hedgedoc | gzip > /opt/hedgedoc/backups/hedgedoc-$(date +%Y%m%d).sql.gz

# Sauvegarde des fichiers uploadés (images, pièces jointes)
tar czf /opt/hedgedoc/backups/uploads-$(date +%Y%m%d).tar.gz \
  -C /opt/hedgedoc uploads-volume

Automatisez avec un cron quotidien et synchronisez vers un stockage distant (rclone vers S3 ou SFTP).

Mettre à jour HedgeDoc :

cd /opt/hedgedoc
docker compose pull app
docker compose up -d app
docker compose logs -f app

Les migrations de base de données s'appliquent automatiquement au démarrage de la nouvelle version. Vérifiez les logs pour confirmer que les migrations se sont bien passées avant de reprendre l'utilisation normale. L'image actuelle est quay.io/hedgedoc/hedgedoc:1.11.1.

Résoudre les problèmes courants

L'interface s'affiche mais la collaboration ne fonctionne pas
Vérifiez en premier le bloc /socket.io/ dans Nginx (voir l'encadré dédié ci-dessus).

Erreur 502 Bad Gateway après le démarrage
HedgeDoc attend que PostgreSQL soit prêt grâce au depends_on: condition: service_healthy. Si le 502 persiste après 60 secondes, vérifiez que le conteneur database est bien en état healthy : docker compose ps. Si non, inspectez ses logs : docker compose logs database.

Les images uploadées disparaissent après un redémarrage
Assurez-vous que le volume uploads est correctement monté. Vérifiez avec docker inspect hedgedoc-app-1 | grep Mounts que le volume est persistant (type volume, pas bind).

Erreur lors de l'export PDF
L'export PDF nécessite Chromium en mode headless. Si l'image Docker officielle ne l'inclut pas dans la version que vous utilisez, vous pouvez désactiver l'export PDF avec CMD_ALLOW_PDF_EXPORT: 'false' dans .env.

Un VPS pour votre stack de collaboration documentaire

HedgeDoc tourne parfaitement sur 1 Go de RAM. Nos VPS démarrent à partir de quelques euros par mois et incluent des snapshots quotidiens pour protéger vos notes d'équipe. Vos specs techniques, vos RFCs et vos notes de réunion restent sur votre infrastructure.

Besoin d'aide ?

Parcourez notre centre d'aide et notre FAQ, ou contactez notre équipe — rappel, WhatsApp ou e-mail. Support en français, anglais et arabe.