Aller au contenu

Héberger et publier de la doc avec Zensical

Mise à jour : 2026-10-19 | Relu intégralement : 2026-10-19

Ce site est construit avec Zensical. Vous aussi, vous voulez prendre des notes et documenter vos projets ? Trop facile !

Définitions

Zensical

Zensical est un générateur de sites de documentation statiques. Il est développé par l'équipe qui a créé Material for MkDocs, passé en mode maintenance fin 2025 au profit de Zensical. Il transforme vos fichiers Markdown en un site web (HTML, CSS, JavaScript) que n'importe quel serveur web peut afficher, sans base de données ni langage serveur : la surface d'attaque est quasi nulle.

Compatibilité avec MkDocs

Zensical lit directement un fichier de configuration mkdocs.yml. Un projet MkDocs Material existant peut donc être construit avec Zensical sans réécrire sa configuration, à condition de ne pas dépendre de plugins non pris en charge.

Fonctionnalités principales

  • Simplicité : quelques commandes suffisent pour créer, prévisualiser et construire un site.
  • Markdown : le contenu s'écrit dans des fichiers .md, simples et lisibles.
  • Personnalisation : palettes de couleurs, icônes, mode clair et sombre.
  • Recherche : moteur de recherche intégré, qui fonctionne côté visiteur.
  • Navigation : sans section nav dans la configuration, le menu est généré à partir de vos fichiers et dossiers.
  • Extensions : coloration syntaxique, boîtes d'information, onglets, emojis, extraits de code.
Un projet encore jeune

Zensical est en version 0.x et évolue vite. Deux précautions :

  • Testez toujours une mise à jour sur une copie avant de publier (voir la section Maintenance).
  • Les plugins MkDocs ne sont pas tous pris en charge, et Zensical ignore sans message d'erreur les plugins qu'il ne connaît pas. Vérifiez la liste des plugins supportés dans sa documentation avant d'en dépendre.
theme: name: material : c'est bien le thème de Zensical

Ne confondez pas deux choses qui portent le même nom. theme: name: material, ci-dessous, désigne le thème natif de Zensical : l'équipe a délibérément gardé le nom material pour rester compatible avec les extensions de thème existantes. Ce n'est pas un appel à l'ancien paquet mkdocs-material, qui lui atteint sa fin de vie le 5 novembre 2026. Votre chaîne reposant sur zensical seul (et non sur mkdocs + mkdocs-material), cette échéance ne la concerne pas, et vous n'avez rien à changer dans votre configuration.

Deux options si besoin : theme: variant: classic retrouve l'apparence exacte de l'ancien Material ; des thèmes tiers packagés (Catppuccin, par exemple) s'installent par pip et se référencent par leur nom (theme: name: catppuccin).

Créer le site

1) Depuis votre machine, ouvrez un terminal et créez un environnement virtuel Python nommé zensical (ou ce que vous voulez) :

python3 -m venv zensical

2) Activez-le :

source zensical/bin/activate
Info

Ce n'est pas obligatoire, mais un environnement virtuel isole les dépendances de chaque projet et évite les conflits de versions avec le Python du système. Il garantit aussi que vous savez exactement quelle version de Zensical tourne. Attention : un environnement virtuel est lié à la version de Python qui l'a créé. Après une montée de version de votre distribution, il faudra le recréer (voir la section Maintenance).

3) Créez le dossier qui contiendra votre projet (fichiers Markdown et configuration) :

mkdir /chemin/vers/doc.mon_domaine.fr
Warning

Évitez de nommer ce dossier docs, qui est déjà le nom du sous-dossier des sources. Et choisissez un emplacement sauvegardé !

4) Installez Zensical dans l'environnement virtuel :

pip install zensical

5) Créez la structure du projet :

cd /chemin/vers/doc.mon_domaine.fr

zensical new .
Info

Cette commande crée le dossier docs avec deux pages d'exemple, un fichier de configuration zensical.toml et un dossier .github (un workflow de publication sur GitHub Pages). Elle n'écrase jamais un fichier existant.

Dans ce tutoriel, j'utilise le format mkdocs.yml, déjà très répandu. Si les deux fichiers existent, zensical.toml est prioritaire : il faut donc le supprimer, ainsi que le dossier .github si vous ne publiez pas sur GitHub Pages.

rm zensical.toml
rm -r .github
Info

L'architecture de votre dossier devrait ressembler à ceci :

doc.mon_domaine.fr
├─ docs/
│  ├─ index.md
│  ├─ Windows_Server.md
│  ├─ Windows_Client.md
│  └─ Mes_notes_techniques.md
└─ mkdocs.yml
  • docs contient vos fichiers Markdown, qui forment le contenu du site.
  • index.md est la page d'accueil.
  • mkdocs.yml est le fichier de configuration à créer à l'étape suivante.

6) Créez le fichier mkdocs.yml pour personnaliser votre site. Voici celui que j'utilise, commenté :

Info

Référez-vous à la documentation officielle : https://zensical.org

mkdocs.yml
site_name: De la doc comme elle vient !  # Nom du site
site_url: https://doc.mon_domaine.fr  # URL du site

# Métadonnées de description (moins de 300 caractères) et d'auteur
site_description: Des cours, des ateliers et des notes techniques informatiques.
site_author: "Votre nom"

theme:
  name: material  # Nom du thème utilisé
  font: false  # Polices système : aucune requête vers Google (RGPD)
  language: fr  # Langue du site (français)
  palette:
    # Mode automatique
    - media: "(prefers-color-scheme)"
      toggle:
        icon: material/brightness-auto
        name: Passer en mode clair

    # Mode clair
    - media: "(prefers-color-scheme: light)"
      scheme: default
      toggle:
        icon: material/brightness-7
        name: Passer en mode sombre

    # Mode sombre
    - media: "(prefers-color-scheme: dark)"
      scheme: slate
      toggle:
        icon: material/brightness-4
        name: Utiliser le réglage du système
  features:
    - content.code.select  # Permet de sélectionner du code
    - content.code.copy  # Ajoute un bouton pour copier le code
    - navigation.top  # Bouton pour revenir en haut de la page
    - search.suggest  # Suggestions de recherche
    - search.highlight  # Surligne les termes recherchés dans la page

markdown_extensions:
  - abbr  # Abréviations
  - attr_list  # Listes d'attributs
  - meta  # Métadonnées
  - def_list  # Listes de définitions
  - pymdownx.emoji:  # Emojis en Unicode : aucune requête vers un CDN (RGPD)
      emoji_index: !!python/name:zensical.extensions.emoji.twemoji
      emoji_generator: !!python/name:pymdownx.emoji.to_alt
  - pymdownx.highlight:  # Coloration syntaxique
      anchor_linenums: true  # Ancres pour les numéros de ligne
      line_spans: __span  # Utilise des spans pour les lignes
      pygments_lang_class: true  # Classes de langage pour la coloration
  - pymdownx.inlinehilite  # Coloration syntaxique en ligne
  - pymdownx.snippets  # Extraits de code
  - pymdownx.superfences  # Blocs de code avancés
  - admonition  # Boîtes d'infos (syntaxe : !!! info "Titre")
  - pymdownx.details  # Boîtes dépliables (syntaxe : ??? info "Titre")

plugins:
  - search  # Recherche intégrée

# Licence affichée dans le pied de page
copyright: >
    Contenus sous licence <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.fr" target="_blank">CC BY-NC-SA 4.0</a>

# Liens sociaux
extra:
  social:
    - icon: fontawesome/brands/linkedin
      link: https://linkedin.com/in/votre-profil
Pourquoi pas de plugin privacy ?

Avec MkDocs Material, le plugin privacy téléchargeait les polices et les emojis pour les héberger sur votre serveur (conformité RGPD). Zensical ne le propose pas, et ignorerait sa configuration sans prévenir : le navigateur de vos visiteurs irait alors chercher ces ressources chez Google et sur un CDN.

La solution est de ne rien charger d'extérieur : font: false utilise les polices du système du visiteur, et le générateur to_alt affiche les emojis en caractères Unicode. Le contrôle de la section suivante permet de le vérifier.

Prévisualiser le site

Une fois le contenu prêt et configuré, vous pouvez le prévisualiser.

1) Servez le site en local :

cd /chemin/vers/doc.mon_domaine.fr

zensical serve

2) Copiez dans votre navigateur l'adresse affichée dans le terminal (en général http://localhost:8000/). Votre site s'affiche.

Info

Les modifications, ajouts et suppressions de fichiers sont détectés automatiquement : il n'est pas nécessaire de relancer le serveur.

3) Appuyez sur Ctrl + C pour arrêter le serveur.

Construire le site

1) Générez le site statique :

cd /chemin/vers/doc.mon_domaine.fr

zensical build --clean --strict
Info

Zensical traite vos fichiers Markdown et votre configuration, puis génère un site complet (HTML, CSS, JavaScript) dans le dossier site. L'option --clean vide le cache, et --strict arrête la construction au moindre avertissement (lien cassé, option erronée), ce qui évite de publier un site défectueux.

2) Vérifiez qu'aucune ressource externe n'est appelée par vos pages :

grep -rlE "fonts\.googleapis|fonts\.gstatic|cdn\.jsdelivr" site --include='*.html' --include='*.css'

Si la commande n'affiche aucun fichier, votre site ne dépend d'aucun service tiers pour s'afficher.

Publier le site en ligne

  • Vous pouvez publier gratuitement le contenu du dossier site sur GitHub Pages. Zensical génère même le workflow nécessaire avec zensical new : https://zensical.org/docs/publish-your-site/

  • Ou, plus simplement, copier le contenu de site vers votre propre serveur web Nginx, c'est ce que je fais !

Durcir Nginx (optionnel)

Un site statique n'a besoin que de peu de choses, autant le protéger correctement :

# Dans le bloc http de nginx.conf : ne plus annoncer la version de Nginx
server_tokens off;

# Dans le bloc server (HTTPS) du site
add_header Strict-Transport-Security "max-age=86400" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "no-referrer" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
  • Commencez HSTS avec une durée courte (ici un jour), puis augmentez-la une fois que tout fonctionne.
  • Un add_header placé dans un bloc location annule ceux du bloc parent : il faut alors les y répéter.
  • Comme votre site n'appelle aucune ressource externe, vous pouvez mettre en place une politique Content-Security-Policy très stricte. Testez-la d'abord avec l'en-tête Content-Security-Policy-Report-Only, qui ne bloque rien mais signale dans la console du navigateur ce qui serait refusé.
  • Vérifiez toujours avant de recharger : sudo nginx -t && sudo systemctl reload nginx.

Mon processus

Maintenant que mon site est en ligne et correctement configuré, voici comment je procède.

Rédaction

J'écris systématiquement mes notes en Markdown. Elles sont stockées dans un répertoire local et synchronisées dans mon cloud privé Nextcloud : j'y ai accès partout, tout le temps.

J'utilise Visual Studio Code pour la rédaction, mais n'importe quel éditeur convient (Obsidian, Notion, HackMD...) tant que vous respectez la syntaxe Markdown et enregistrez vos fichiers en .md.

Automatisation

Ce script, exécuté par crontab, fait quatre choses :

1) Il copie les fichiers dont le nom commence par 1 vers le dossier docs du projet. 2) Il construit le site avec Zensical. 3) Il vérifie qu'aucune ressource externe n'est présente (sinon il annule tout). 4) Il synchronise le dossier site vers mon serveur web avec rclone.

Cela me permet de ne plus me soucier de la mise à jour du site : j'ai juste à penser à mettre un 1 devant le nom du fichier .md si je veux qu'il soit en ligne.

#!/bin/bash
#
# Publication de la doc Zensical vers le serveur web
#

set -euo pipefail

# --- Configuration ---
readonly NOTES_SRC="/chemin/vers/Notes/"
readonly PROJET="/chemin/vers/doc.mon_domaine.fr"
readonly DOCS_DIR="${PROJET}/docs"
readonly SITE_DIR="${PROJET}/site"
readonly VENV="/chemin/vers/zensical"
readonly REMOTE="serveur_web_remote:/var/www/doc.mon_domaine.fr/"
readonly LOCKFILE="${XDG_RUNTIME_DIR:-/tmp}/publish-doc.lock"

log()  { printf '[%(%F %T)T] %s\n' -1 "$*"; }
fail() { printf '[%(%F %T)T] ERREUR - %s\n' -1 "$*" >&2; exit 1; }

# --- Verrou anti double exécution ---
exec 9>"$LOCKFILE"
flock -n 9 || fail "Une publication est déjà en cours."

# --- Vérifications préalables ---
[[ -d "$NOTES_SRC" ]] || fail "Source introuvable : ${NOTES_SRC}"
[[ -d "$DOCS_DIR"  ]] || fail "Dossier docs introuvable : ${DOCS_DIR}"
[[ -x "${VENV}/bin/zensical" ]] || fail "Zensical introuvable dans ${VENV}"
[[ "$SITE_DIR" == */site ]] || fail "SITE_DIR inattendu : ${SITE_DIR}"
rclone lsd "$REMOTE" >/dev/null 2>&1 || fail "Serveur injoignable."

# --- 1. Notes vers les sources du site (fichiers 1*, index.md et images) ---
log "Synchronisation des notes"
rsync -a --delete \
    --include='*/' \
    --include='1*' \
    --include='index.md' \
    --include='*.jpg' --include='*.jpeg' \
    --include='*.png' --include='*.gif' \
    --include='*.bmp' \
    --exclude='*' \
    "$NOTES_SRC" "$DOCS_DIR/"

# --- 2. Construction du site ---
log "Construction Zensical"
cd "$PROJET"
rm -rf -- "$SITE_DIR"
"${VENV}/bin/zensical" build --clean --strict

# --- 3. Contrôles avant publication ---
[[ -f "${SITE_DIR}/index.html" ]] || fail "Build incomplet, index.html absent."

if grep -rqE "fonts\.googleapis|fonts\.gstatic|cdn\.jsdelivr" "$SITE_DIR" \
        --include='*.html' --include='*.css'; then
    fail "Ressource externe détectée, publication annulée."
fi

# --- 4. Publication ---
log "Publication vers le serveur"
rclone sync "${SITE_DIR}/" "$REMOTE" --checksum --transfers 8

log "Terminé."
Exemple crontab : exécution tous les jours à 10h, avec un journal
0 10 * * * /chemin/vers/doc-to-web.sh >> /chemin/vers/publish-doc.log 2>&1

Le journal permet de repérer un échec silencieux. Pensez aussi qu'un cron ne s'exécute pas si la machine est éteinte, et qu'il n'a pas accès à votre agent SSH : si votre clé est protégée par une phrase de passe, la publication automatique échouera.

Tester sans rien envoyer

Ajoutez temporairement --dry-run à la commande rclone sync : elle affichera ce qui serait copié ou supprimé sans toucher au serveur.

Maintenance

Mettre à jour Zensical

Testez toujours sur une copie avant de toucher à l'environnement de production :

python3 -m venv /tmp/zensical-test
/tmp/zensical-test/bin/pip install -U zensical

rsync -a --exclude=site /chemin/vers/doc.mon_domaine.fr/ /tmp/test-doc/
cd /tmp/test-doc
/tmp/zensical-test/bin/zensical build --clean --strict
grep -rlE "fonts\.googleapis|fonts\.gstatic|cdn\.jsdelivr" site --include='*.html' --include='*.css'

Si la construction réussit, que le grep n'affiche rien et que le rendu est correct, mettez à jour l'environnement réel et figez les versions :

/chemin/vers/zensical/bin/pip install -U zensical
/chemin/vers/zensical/bin/pip freeze > /chemin/vers/doc.mon_domaine.fr/requirements.txt

Après une montée de version de votre distribution

L'environnement virtuel est lié à l'ancienne version de Python : il faut le recréer. Le fichier requirements.txt rend l'opération immédiate :

mv /chemin/vers/zensical /chemin/vers/zensical.old
python3 -m venv /chemin/vers/zensical
/chemin/vers/zensical/bin/pip install -r /chemin/vers/doc.mon_domaine.fr/requirements.txt

Sauvegarder le site en ligne

rclone copy serveur_web_remote:/var/www/doc.mon_domaine.fr/ ~/backup-doc-$(date +%F)