Contexte : éditeur Markdown collaboratif auto-hébergé, installé manuellement avec MariaDB, un service systemd et un reverse proxy Nginx en HTTPS · Testé sur : Debian 11, HedgeDoc 1.9.4, Node.js 16, Yarn 1.22, MariaDB · Dernière vérification : contenu de 2023 non revérifié
Les versions citées sont celles de 2023 : Node.js 16 n'est plus maintenu. Pour une nouvelle installation, prenez la dernière version de HedgeDoc 1.x et la version de Node.js qu'elle exige (voir ses notes de version), puis adaptez les commandes ci-dessous.
Installer HedgeDoc sur Debian avec une base MariaDB, le lancer automatiquement avec systemd, le publier derrière Nginx pour faire disparaître le port 3000, et le servir en HTTPS avec un certificat Let's Encrypt renouvelé automatiquement.
root ou sudo.<DOMAINE>, qui pointe vers le serveur (nécessaire pour le certificat HTTPS).sudo apt update && sudo apt upgrade -y
sudo adduser --system --group --home /srv/hedgedoc hedgedoc
Cet utilisateur système hedgedoc possède le dossier /srv/hedgedoc et fera tourner le service. Effectuez les manipulations propres à HedgeDoc (installation, configuration) avec cet utilisateur plutôt qu'avec root.
Pour ajouter un utilisateur existant à des groupes supplémentaires :
sudo usermod -aG grp1,grp2 nom-utilisateur. L'option-aajoute les groupes sans retirer l'utilisateur de ceux dont il fait déjà partie.
Ajoutez le dépôt NodeSource de Node.js 16, puis installez Node.js :
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo bash -
sudo apt install -y nodejs
node -v
npm -v
Le paquet nodejs de NodeSource fournit aussi npm. Installez le paquet npm de Debian (sudo apt install npm) uniquement si npm -v ne renvoie rien.
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/yarnkey.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install -y yarn
yarn --version
sudo npm install -g node-gyp
Pour vérifier qu'un outil est installé et connaître sa version, tapez son nom suivi de
-vou--version, par exemplenpm -vounpm --version.
sudo apt install -y mariadb-server
sudo mariadb-secure-installation
sudo mysql -u root -p
Créez la base, l'utilisateur hedgedoc et ses droits :
CREATE DATABASE hedgedoc;
CREATE USER 'hedgedoc'@'localhost' IDENTIFIED BY '<MOT_DE_PASSE_DB>';
GRANT ALL PRIVILEGES ON hedgedoc.* TO 'hedgedoc'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Conservez ce mot de passe dans un gestionnaire de mots de passe (voir Utiliser Bitwarden).
Récupérez la version choisie dans /srv/hedgedoc, puis lancez le script d'installation :
sudo -u hedgedoc git clone -b 1.9.4 https://github.com/hedgedoc/hedgedoc.git /srv/hedgedoc
cd /srv/hedgedoc
sudo -u hedgedoc bin/setup
Si vous partez de l'archive de la version plutôt que de Git, extrayez-la dans /srv avec tar -xvf hedgedoc-<VERSION>.tar.gz, puis lancez bin/setup de la même façon.
Gardez une copie du fichier de configuration généré, puis ouvrez-le :
cd /srv/hedgedoc
sudo -u hedgedoc cp config.json config.json.old
sudo -u hedgedoc nano config.json
Remplacez son contenu par ce minimum, qui utilise une base SQLite locale :
{
"production": {
"db": {
"dialect": "sqlite",
"storage": "./db.hedgedoc.sqlite"
},
"urlAddPort": true,
"domain": "localhost"
}
}
Lancez HedgeDoc à la main pour vérifier qu'il démarre, puis arrêtez-le avec Ctrl+C :
sudo -u hedgedoc NODE_ENV=production yarn start
Modifiez config.json pour utiliser la base créée à l'étape 5 :
{
"production": {
"db": {
"username": "hedgedoc",
"password": "<MOT_DE_PASSE_DB>",
"database": "hedgedoc",
"host": "localhost",
"port": "3306",
"dialect": "mariadb"
},
"urlAddPort": true,
"domain": "<DOMAINE>"
}
}
Relancez la commande de test de l'étape 7 : la page d'accueil de HedgeDoc s'affiche sur http://<DOMAINE>:3000/. Arrêtez ensuite HedgeDoc avec Ctrl+C : c'est systemd qui le lancera désormais.

Vérifiez que l'utilisateur et le groupe hedgedoc existent et possèdent le dossier d'installation (sinon, adaptez User et Group dans l'unité ci-dessous) :
sudo chown -R hedgedoc:hedgedoc /srv/hedgedoc
Créez le fichier /etc/systemd/system/hedgedoc.service :
[Unit]
Description=HedgeDoc
After=network.target
After=mariadb.service
[Service]
Type=exec
Environment=NODE_ENV=production
Restart=always
RestartSec=2s
ExecStart=/usr/bin/yarn start --production
NoNewPrivileges=true
PrivateDevices=true
RemoveIPC=true
LockPersonality=true
ProtectControlGroups=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectClock=true
ProtectHostname=true
ProtectProc=noaccess
RestrictRealtime=true
RestrictSUIDSGID=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
ProtectSystem=strict
# ProtectHome=true (laissé désactivé dans l'installation d'origine)
PrivateTmp=true
SystemCallArchitectures=native
SystemCallFilter=@system-service
# À adapter si besoin
User=hedgedoc
Group=hedgedoc
WorkingDirectory=/srv/hedgedoc
# Seul dossier accessible en écriture : les fichiers envoyés
# (ajoutez le fichier SQLite si vous restez sur SQLite)
ReadWritePaths=/srv/hedgedoc/public/uploads
[Install]
WantedBy=multi-user.target
Rechargez systemd, puis activez et démarrez le service :
sudo systemctl daemon-reload
sudo systemctl enable --now hedgedoc.service
Pour suivre les journaux du service :
sudo journalctl -u hedgedoc.service
Installez Nginx et Certbot :
sudo apt install -y nginx python3-certbot-nginx
Demandez le certificat en mode autonome (standalone), en déclarant dès maintenant l'arrêt et le redémarrage de Nginx autour de chaque renouvellement. Certbot enregistre ces commandes et les réutilise à chaque renouvellement :
sudo certbot certonly --standalone -d <DOMAINE> --pre-hook "systemctl stop nginx" --post-hook "systemctl start nginx"
En mode autonome, Certbot ouvre lui-même le port 80. Sans ces deux commandes, le renouvellement échoue tant que Nginx occupe ce port : c'est le problème rencontré avec l'installation d'origine (voir « Dépannage »).
Créez le fichier /etc/nginx/sites-available/hedgedoc.conf :
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Redirige tout le trafic HTTP vers HTTPS
server {
listen 80;
listen [::]:80;
server_name <DOMAINE>;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name <DOMAINE>;
ssl_certificate /etc/letsencrypt/live/<DOMAINE>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<DOMAINE>/privkey.pem;
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_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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
Comment Nginx choisit un bloc
server: il retient d'abord les blocs qui écoutent sur le port de la requête (listen), puis, parmi eux, celui dont leserver_namecorrespond au nom de domaine demandé.
Activez le site (le lien symbolique prend le chemin complet), testez la configuration puis rechargez Nginx :
sudo ln -s /etc/nginx/sites-available/hedgedoc.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Le test doit renvoyer :
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Dans config.json, passez urlAddPort à false et ajoutez protocolUseSSL :
{
"production": {
"db": {
"username": "hedgedoc",
"password": "<MOT_DE_PASSE_DB>",
"database": "hedgedoc",
"host": "localhost",
"port": "3306",
"dialect": "mariadb"
},
"urlAddPort": false,
"protocolUseSSL": true,
"domain": "<DOMAINE>"
}
}
Redémarrez le service pour appliquer la configuration :
sudo systemctl restart hedgedoc.service
email et allowEmailRegister de config.json (voir la documentation de configuration de HedgeDoc)./srv/hedgedoc/public/uploads, le seul dossier que l'unité systemd autorise en écriture.systemctl status hedgedoc.service
https://<DOMAINE>/ affiche HedgeDoc, sans numéro de port et avec un certificat valide.sudo certbot renew --dry-run
systemctl list-timers | grep certbot
Job for nginx.service failed because the control process exited with error code : lancez sudo nginx -t pour voir la ligne fautive. Causes fréquentes : certificat pas encore obtenu (le chemin ssl_certificate n'existe pas), faute de frappe dans une directive (la version d'origine contenait un > parasite après fullchain.pem), ou port 80 déjà occupé.Failed to renew certificate … Problem binding to port 80: Could not bind to IPv4 or IPv6 : le certificat a été obtenu en mode autonome, qui a besoin du port 80, déjà pris par Nginx. Solutions : déclarer les commandes d'arrêt et de redémarrage de Nginx (étape 10), ou obtenir le certificat avec le greffon Nginx (sudo certbot --nginx -d <DOMAINE>), qui n'a pas besoin d'arrêter Nginx. Pour diagnostiquer :sudo cat /etc/letsencrypt/renewal/<DOMAINE>.conf
sudo ls -lah /etc/letsencrypt/live/<DOMAINE>/
sudo tail /var/log/nginx/error.log
sudo journalctl -u hedgedoc.service, puis vérifiez que /srv/hedgedoc appartient à hedgedoc et que les chemins en écriture sont bien listés dans ReadWritePaths.