Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Lychee : détecter les liens cassés dans votre documentation

22 min de lecture
Améliorer cette page

Ce guide va vous permettre de détecter automatiquement tous les liens cassés dans votre documentation en moins de 5 minutes. Vous apprendrez à installer Lychee, vérifier vos fichiers Markdown/HTML, et l'intégrer dans votre pipeline CI/CD pour ne plus jamais publier de liens morts.

Ce que vous apprendrez :

  • à l'installer rapidement (Docker, cargo, gestionnaire de paquets)
  • à vérifier des fichiers, des dossiers et des pages web
  • à le configurer pour vos besoins spécifiques (cache, exclusions, formats de sortie)
  • à l'intégrer dans un pipeline CI/CD (GitHub Actions, GitLab CI, hook Git)
  • à diagnostiquer et corriger les liens cassés ou les faux positifs

Imaginez que vous maintenez une documentation technique de 200 pages. Chaque page contient 10 à 20 liens vers d'autres pages, des sites externes, des dépôts GitHub. Au fil des mois, les liens morts s'accumulent :

  • Des articles de blog changent d'URL
  • Des projets GitHub sont archivés ou renommés
  • Vos propres pages internes sont déplacées
  • Des APIs changent de domaine

Résultat : vos lecteurs tombent sur des erreurs 404. Ils perdent confiance, quittent votre site, et votre réputation en prend un coup.

Lychee résout ce problème en parcourant tous vos fichiers et en testant chaque lien (HTTP, HTTPS, mailto, ancres). Il est asynchrone (vérifie plusieurs liens en parallèle), rapide (écrit en Rust), et facile à intégrer dans un workflow CI/CD.

Lychee est un vérificateur de liens (link checker) ultra-rapide écrit en Rust. Il scanne vos fichiers Markdown, HTML, ou les pages web que vous lui indiquez, pour détecter les liens cassés ou invalides.

Liens officiels :

Voici les capacités qui distinguent Lychee des autres vérificateurs de liens. Ces fonctionnalités répondent aux besoins réels des équipes qui maintiennent de la documentation à grande échelle :

FonctionnalitéDescriptionExemple d'usage
Multi-formatsMarkdown, HTML, texte brutDocumentation, blog, site statique
AsynchroneVérifie plusieurs liens en parallèleBeaucoup de liens vérifiés en même temps
CacheÉvite de re-vérifier les mêmes URLsAccélère les scans répétés
JSON outputSortie structurée pour l'automatisationParsing dans un script CI/CD
ExclusionsIgnore certains domaines ou patternsExclure localhost, liens privés
AncresVérifie les #fragment dans les URLsS'assure que page.html#section existe
Email checkValide les adresses mailto:Détecte les emails invalides

Lychee a été créé par Matthias Endler pour maintenir le dépôt analysis-tools.dev, qui liste des centaines d'outils. Les liens cassaient régulièrement, et les solutions existantes présentaient des lacunes majeures qui rendaient leur utilisation difficile en production :

  • Trop lentes (vérifications synchrones)
  • Obsolètes (projets non maintenus)
  • Limitées (pas de support Markdown, pas de cache)

Résultat : Lychee combine un contrôle asynchrone, un cache et la lecture native du Markdown, ce qui lui permet de vérifier de gros volumes de liens sans ralentir un pipeline.

Avant de commencer, assurez-vous que votre environnement répond aux critères suivants. La bonne nouvelle : Lychee étant un binaire statique, les dépendances sont minimales.

Connaissances :

  • Utilisation basique du terminal (Linux/macOS/Windows)
  • Notions de Markdown ou HTML (optionnel mais utile)

Système :

  • Linux, macOS, ou Windows (WSL2 recommandé)
  • Docker ou Rust/Cargo ou gestionnaire de paquets

Outils (un seul suffit) :

Lychee est distribué comme un binaire statique : pas de dépendances système compliquées. Choisissez la méthode qui vous convient.

La façon la plus simple, sans rien installer sur votre système :

Fenêtre de terminal
docker run --init -it --rm \
-v "$(pwd)":/input \
lycheeverse/lychee:0.24.2@sha256:e2d19e57cf6ab037026f20b8e449a1f30d9d7f81eef4194763aab2eab20bd28d /input

Explication :

  • --init : Gère correctement les signaux (Ctrl+C)
  • -v $(pwd):/input : Monte le dossier courant dans le conteneur
  • /input : Chemin à scanner dans le conteneur

Vérification :

Fenêtre de terminal
docker run --rm lycheeverse/lychee:0.24.2@sha256:e2d19e57cf6ab037026f20b8e449a1f30d9d7f81eef4194763aab2eab20bd28d --version
# Affiche : lychee 0.24.2

Une fois installé, Lychee s'utilise en ligne de commande. Voici les scénarios les plus courants.

  1. Vérifier un fichier Markdown

    Fenêtre de terminal
    lychee README.md

    Résultat attendu (aucune erreur) :

    🔍 10 Total (in 0s) ✅ 10 OK 🚫 0 Errors

    Si liens cassés :

    Issues found in 1 input. Find details below.
    [README.md]:
    [ERROR] https://old-blog.example.com/post | Network error: Connection failed
    🔍 11 Total (in 8s) ✅ 6 OK 🚫 3 Errors 👻 1 Excluded 🔀 1 Redirects
  2. Vérifier tous les fichiers d'un dossier

    Scanne récursivement tous les Markdown/HTML :

    Fenêtre de terminal
    lychee docs/

    Ou avec un pattern spécifique :

    Fenêtre de terminal
    lychee "docs/**/*.md"
  3. Vérifier les liens d'une page web

    Lychee télécharge la page indiquée et teste les liens qu'elle contient :

    Fenêtre de terminal
    lychee https://blog.stephane-robert.info

    Lychee ne suit pas les liens d'une page à l'autre pour explorer tout un site : il vérifie uniquement les liens trouvés dans la page indiquée. Il n'existe pas d'option de profondeur (--max-depth) dans la version 0.24.2. Pour contrôler un site entier, scannez plutôt son dossier de build (voir « Site statique (HTML) » plus bas) ou fournissez la liste de ses pages.

  4. Vérifier plusieurs sources en une fois

    Fenêtre de terminal
    lychee README.md docs/ https://example.com
  5. Lire les URLs depuis stdin

    Utile pour piper depuis un autre outil :

    Fenêtre de terminal
    echo "https://github.com" | lychee -

    Ou depuis un fichier :

    Fenêtre de terminal
    cat urls.txt | lychee -
  6. Utiliser un glob pattern avancé

    Fenêtre de terminal
    lychee "**/*.{md,html,txt}"

    Scanne tous les .md, .html, et .txt récursivement.

Voici ce que vous verrez lors d'un scan typique :

Fenêtre de terminal
$ lychee docs/
12/12 ━━━━━━━━━━━━━━━━━━━━ Finished extracting links
Issues found in 1 input. Find details below.
[README.md]:
[ERROR] https://old-blog.example.com/post | Network error: Connection failed
🔍 12 Total (in 8s) ✅ 7 OK 🚫 3 Errors 👻 1 Excluded 🔀 1 Redirects

Chaque indicateur de la ligne de résumé a une signification précise :

IndicateurSignification
TotalNombre total de liens trouvés
OKLiens valides (codes 200-299)
ErrorsLiens cassés ou inaccessibles
ExcludedLiens exclus par la configuration
RedirectsRedirections détectées (301, 302)
CachedRésultats provenant du cache

Certains liens sont volontairement cassés (exemples dans la doc) ou privés (localhost, intranets). Vous pouvez les exclure.

Option 1 : Ligne de commande

Fenêtre de terminal
lychee --exclude 'localhost|127\.0\.0\.1' docs/

Les valeurs de --exclude sont des expressions régulières, interprétées par le moteur de Rust : | sépare des alternatives, \. désigne un point littéral (un . seul accepte n'importe quel caractère) et \d+ un ou plusieurs chiffres. Cette syntaxe de base est la même que dans les autres langages : la leçon Expressions régulières en Python en détaille les symboles, et Expressions régulières de base sous Linux couvre celle de grep -E.

Option 2 : Fichier de configuration

Créez un fichier lychee.toml. Les guillemets simples y définissent des chaînes littérales : les antislashs des motifs restent intacts. La clé exclude ne peut apparaître qu'une fois : regroupez-y localhost, IPs privées et domaines à ignorer.

# Exclure localhost, les IPs privées et des domaines d'exemple
exclude = [
'localhost',
'127\.0\.0\.1',
'192\.168\.\d+\.\d+',
'10\.\d+\.\d+\.\d+',
'example\.com',
'placeholder\.org'
]
# Ignorer certains chemins de fichiers
exclude_path = [
'node_modules/',
'.git/',
'vendor/'
]

Utilisation :

Fenêtre de terminal
lychee --config lychee.toml docs/

Par défaut, Lychee re-vérifie tous les liens à chaque exécution. Avec le cache, il se souvient des liens déjà validés.

Fenêtre de terminal
lychee --cache docs/

Le cache est stocké dans un fichier .lycheecache, créé dans le répertoire où vous lancez la commande. Pensez à l'ajouter à votre .gitignore.

Au second run, les résultats mis en cache apparaissent :

[ERROR] https://broken-site.com | Error (cached)
🔍 11 Total (in 0s) ✅ 7 OK 🚫 1 Error 👻 4 Excluded

Vider le cache :

Fenêtre de terminal
rm .lycheecache

Lychee supporte plusieurs formats pour intégrer les résultats dans d'autres outils. Choisissez le format adapté à votre cas d'usage : lecture humaine en console, automatisation dans un script, ou rapport à inclure dans votre documentation.

FormatUsageCommande
TexteLecture humaine (défaut)lychee docs/
JSONParsing automatisélychee --format json docs/
MarkdownRapport à inclure dans un READMElychee --format markdown docs/
CSVImport dans Excel/Sheetslychee --format csv docs/

Exemple JSON :

{
"total": 11,
"successful": 6,
"unknown": 0,
"unsupported": 0,
"timeouts": 0,
"redirects": 1,
"excludes": 1,
"errors": 3,
"cached": 0,
"error_map": {
"README.md": [
{
"url": "https://old-blog.example.com/post",
"status": {
"text": "Network error: Connection failed",
"details": "Connection failed. Check network connectivity"
}
}
]
}
}

Redirection vers un fichier :

Fenêtre de terminal
lychee --format json docs/ > report.json

Par défaut, Lychee vérifie uniquement que https://example.com/page répond. Pour vérifier que https://example.com/page#section contient bien l'ancre #section :

Fenêtre de terminal
lychee --include-fragments docs/

Cas d'usage : Vous avez des liens vers des sections précises d'une page (#installation, #configuration). Si la section est renommée, le lien devient invalide.

Certains sites limitent le nombre de requêtes par seconde. Lychee peut être trop rapide et se faire bloquer.

Ralentir les requêtes :

Fenêtre de terminal
lychee --max-concurrency 5 docs/

Ajouter un délai entre les requêtes vers un même hôte, avec --host-request-interval (50 ms par défaut) :

Fenêtre de terminal
lychee --host-request-interval 1s docs/ # 1 seconde de pause

Headers personnalisés (pour contourner des blocages) :

Fenêtre de terminal
lychee --header "User-Agent: Mozilla/5.0" docs/

L'usage principal de Lychee est de vérifier les liens à chaque commit pour éviter de publier des liens cassés.

Lychee fournit une GitHub Action officielle qui simplifie l'intégration dans vos workflows.

Exemple de workflow (.github/workflows/links.yml) :

name: Vérification des liens
on:
push:
branches: [main]
pull_request:
jobs:
link-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Vérifier les liens avec Lychee
uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0
with:
args: --verbose --no-progress './**/*.md' './**/*.html'
fail: true # Échoue si liens cassés
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Avec cache pour accélérer les vérifications :

- name: Vérifier les liens
uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0
with:
args: --cache --verbose './**/*.md'
fail: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Ajouter un commentaire sur la PR en cas d'erreur :

- name: Commenter la PR
if: failure()
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: 'Des liens cassés ont été détectés. Voir les logs CI.'
})

Pour GitLab CI, la configuration est encore plus simple puisque Lychee fournit une image Docker officielle, épinglée ici par version et par digest. Voici un job minimal qui s'exécute à chaque push :

link-check:
image: lycheeverse/lychee:0.24.2@sha256:e2d19e57cf6ab037026f20b8e449a1f30d9d7f81eef4194763aab2eab20bd28d
script:
- lychee --cache --verbose --format json --output lychee-report.json './**/*.md'
artifacts:
when: on_failure
paths:
- lychee-report.json

Vérifiez les liens avant de commit avec un hook Git. L'option --offline ne teste que les liens vers des fichiers locaux, sans requête réseau : le hook reste instantané et évite de pousser des liens internes cassés, ce qui économise du temps CI. Les liens externes restent à la charge du pipeline.

Créez un fichier dans votre dépôt avec ce contenu :

.git/hooks/pre-commit :

#!/bin/bash
lychee --offline README.md docs/
if [ $? -ne 0 ]; then
echo "Liens cassés détectés. Corrigez avant de commit."
exit 1
fi

Rendre le hook exécutable :

Fenêtre de terminal
chmod +x .git/hooks/pre-commit

Symptôme :

[ERR] https://slow-site.com (Timeout after 20s)

Cause : Le site est lent ou votre connexion est instable.

Solution : Augmenter le timeout :

Fenêtre de terminal
lychee --timeout 60 docs/

Symptôme :

[429] https://api.github.com/repos/... (Too Many Requests)

Cause : Trop de requêtes en parallèle vers la même API.

Solution 1 : Réduire la concurrence et espacer les requêtes vers un même hôte :

Fenêtre de terminal
lychee --max-concurrency 2 --host-request-interval 1s docs/

Solution 2 : Ajouter un token GitHub (pour les URLs GitHub) :

Fenêtre de terminal
export GITHUB_TOKEN=ghp_your_token
lychee docs/

Problème : Faux positifs (liens valides marqués cassés)

Section intitulée « Problème : Faux positifs (liens valides marqués cassés) »

Symptôme : Un lien fonctionne dans le navigateur mais échoue dans Lychee.

Cause : Le site bloque les requêtes sans User-Agent ou cookies.

Solution : Ajouter des headers :

Fenêtre de terminal
lychee --header "User-Agent: Mozilla/5.0" \
--header "Accept: text/html" \
docs/

Ou exclure le domaine si c'est un cas isolé :

Fenêtre de terminal
lychee --exclude 'problematic-site\.com' docs/

Symptôme : #section marquée comme invalide alors qu'elle existe.

Cause : Par défaut, Lychee ne vérifie pas les fragments.

Solution :

Fenêtre de terminal
lychee --include-fragments docs/

Symptôme :

[ERR] ./assets/image.png (File not found)

Cause : Chemin relatif incorrect ou fichier réellement absent.

Solution 1 : Vérifier que le fichier existe :

Fenêtre de terminal
ls -la ./assets/image.png

Solution 2 : Utiliser --base-url si votre site n'est pas servi depuis la racine :

Fenêtre de terminal
lychee --base-url https://example.com/blog/ docs/

Les sections précédentes vous ont montré les options une à une. Voici maintenant trois configurations complètes, prêtes à l'emploi, pour des cas d'usage fréquents. Copiez celle qui correspond à votre projet et ajustez-la.

Cas d'usage : Dépôt GitHub avec des guides en Markdown.

Cette configuration est optimisée pour un dépôt de documentation classique. Elle active le cache pour accélérer les scans répétés, exclut les répertoires de build, et vérifie les ancres pour détecter les liens internes cassés.

lychee.toml :

# Exclure les exemples et localhost
exclude = [
'localhost',
'example\.(com|org|net)',
'127\.0\.0\.1'
]
# Vérifier les ancres
include_fragments = true
# Cache activé
cache = true
# Timeout augmenté (certains sites de docs sont lents)
timeout = 30
# Format JSON pour parsing
format = "json"
# Ignorer node_modules et .git
exclude_path = [
'node_modules/',
'.git/',
'vendor/',
'dist/'
]

Commande :

Fenêtre de terminal
lychee --config lychee.toml .

Cas d'usage : Site généré par Hugo/Jekyll/Astro.

Pour un site web généré, cette configuration se concentre sur le dossier de build final (public/ ou dist/). Elle exclut les domaines tiers (analytics, CDN) qui peuvent causer des faux positifs.

# Vérifier uniquement le build final
base_url = "https://blog.stephane-robert.info"
# Exclure les domaines analytics et CDNs
exclude = [
'google-analytics\.com',
'googletagmanager\.com',
'cdn\.jsdelivr\.net'
]
# Vérifier les fragments (ancres de navigation)
include_fragments = true
# Format Markdown pour rapport
format = "markdown"
# Ignorer les répertoires de build
exclude_path = [
'node_modules/',
'.cache/',
'dist/',
'public/'
]

Commande :

Fenêtre de terminal
lychee --config lychee.toml public/

Cas d'usage : Blog avec des liens externes vers des articles de référence.

Cette configuration est adaptée aux blogs qui citent beaucoup de sources externes. Elle augmente le timeout pour gérer les sites lents, ajoute des tentatives (max_retries) pour la résilience, et ralentit les requêtes pour éviter les rate limits.

# Timeout augmenté (certains blogs sont lents)
timeout = 45
# Exclure les liens sponsorisés
exclude = [
'bit\.ly',
'goo\.gl',
't\.co'
]
# Cache activé
cache = true
# Réessayer 3 fois en cas d'échec
max_retries = 3
# Délai minimal entre requêtes vers un même hôte (rate limits)
host_request_interval = "500ms"
  • Lychee détecte automatiquement les liens cassés dans Markdown, HTML, et sites web.
  • Installation simple : Docker, cargo, ou gestionnaire de paquets.
  • Usage basique : lychee README.md pour un fichier, lychee docs/ pour un dossier.
  • Pas d'exploration de site : Lychee teste les liens de la page ou du dossier indiqués et ne suit pas les liens d'une page à l'autre (pas de --max-depth).
  • Cache et exclusions : Accélérez les scans et ignorez les faux positifs ; --exclude prend des expressions régulières.
  • Rate limits : --max-concurrency et --host-request-interval espacent les requêtes vers un même hôte.
  • Intégration CI/CD : GitHub Actions, GitLab CI, ou hooks Git pour vérifications automatiques.
  • Configuration TOML : Centralisez vos règles dans lychee.toml pour éviter les longues commandes.
  • Formats de sortie : JSON, Markdown, CSV pour automatisation ou rapports.
  • Vérification des ancres : Utilisez --include-fragments pour valider les #section.

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn