Vous allez livrer un site cette année. Un portfolio, un projet de groupe, le site d’une association. Vous allez le construire, le mettre en ligne, et ce sera très bien.
Puis vous allez vouloir changer une phrase. Et vous rouvrirez FileZilla, vous chercherez le bon dossier, vous glisserez le fichier, vous espérerez avoir mis le bon. Ça marchera. Vous le referez trois fois. La quatrième, vous ne le ferez pas.
Un site qu’il faut penser à redéployer est un site qui l’est une fois. C’est le vrai mode d’échec des sites d’étudiants, de freelances et d’associations : pas une panne, un abandon progressif que personne ne décide.
Cet article raconte comment j’ai réglé ça pour cinq sites en même temps, et surtout ce que j’ai décidé de ne pas automatiser.
Ce qu’est une chaîne de publication
Quatre étapes, toujours les mêmes.
sources → construction → vérifications → mise en ligne
Le contenu vit en Markdown dans un dépôt Git. Un générateur le transforme en HTML. Des contrôles refusent de continuer si quelque chose cloche. Le résultat part sur le serveur.
Ce qui change tout, c’est qui déclenche la chaîne. Si c’est vous, elle tourne quand vous y pensez. Si c’est un git push, elle tourne à chaque fois.
on:
push:
branches: [main]
Trois lignes de GitHub Actions. Vous écrivez, vous poussez, le site se met à jour. Vous pouvez corriger une faute depuis votre téléphone dans le train.
La contrainte qu’il faut lire avant de choisir
J’avais prévu un déploiement classique : SSH, rsync, deux lignes. rsync ne transfère que ce qui a changé, là où un envoi FTP repousse tous les fichiers à chaque fois. C’est la bonne solution.
Sauf que l’hébergeur bloque le port 22 par défaut, et ne l’ouvre qu’aux adresses IP déclarées à l’avance.
Le premier réflexe, c’est de déclarer l’IP. Le second, c’est de vérifier laquelle. Les serveurs de GitHub Actions tournent sur des milliers de plages d’adresses, révisées chaque semaine. Et l’hébergeur précise qu’aucune autorisation supplémentaire ne sera accordée en nombre.
La liste d’autorisation n’est donc pas fastidieuse. Elle est impossible.
Retenez le raisonnement plutôt que la conclusion : j’ai découvert ça au premier essai, en lisant un message d’erreur, après avoir écrit toute la configuration. Dix minutes de lecture de la documentation de l’hébergeur avant de coder m’auraient évité l’aller-retour.
La solution était ailleurs : le port 21 n’est pas restreint, et FTP existe en version chiffrée. lftp en FTPS explicite fait l’équivalent d’un rsync, en une commande.
lftp -u "$USER,$PASS" "ftp://$HOST" -e "
set ftp:ssl-force true;
mirror --reverse --delete public /;
"
Ce ssl-force true n’est pas décoratif. Sans lui, si le serveur ne répond pas en TLS, lftp bascule en clair sans rien dire — et vos identifiants traversent le réseau en clair. Un réglage par défaut permissif est un piège silencieux, et c’est un motif que vous retrouverez partout.
Les défauts qui ne font pas échouer la construction
C’est la partie que je veux vraiment vous transmettre.
En mettant ces sites en ligne, j’ai trouvé trois défauts. Aucun des trois ne faisait échouer quoi que ce soit.
Des liens /posts/… hérités d’une ancienne structure. Les fichiers s’appelaient autrement. Le générateur ne relit pas ce qu’on écrit à la main dans le corps d’un article : ça compile parfaitement, et ça donne un 404 en ligne.
Un bouton d’appel à l’action pointant une page qui n’existait pas sur deux des trois sites. Sur tous les articles.
Aucune image de partage. Chaque lien partagé sur LinkedIn se serait affiché en vignette nue. Rien ne le signalait, parce que rien ne cherchait.
Les trois ont le même profil : le système rendait compte d’un succès en étant cassé. C’est la catégorie de défaut la plus coûteuse, parce qu’on ne la découvre pas — on l’apprend par quelqu’un d’autre, ou jamais.
D’où deux scripts, une trentaine de lignes chacun, branchés dans la chaîne :
python3 tools/check-links.py public # tout lien interne aboutit-il ?
python3 tools/check-third-party.py public # rien n'est chargé depuis un tiers ?
S’ils échouent, le déploiement n’a pas lieu.
Et il faut les tester en les cassant volontairement. J’ai supprimé un fichier, retiré un lien, mis une police Google : les scripts ont refusé de passer. Un contrôle qu’on n’a jamais vu échouer n’est pas un contrôle, c’est une décoration — vous n’avez aucune preuve qu’il regarde quelque chose.
J’ai fait l’erreur au passage : le mode « essai à blanc » de mon déploiement sautait entièrement l’étape de connexion. Il ne testait donc ni les identifiants, ni le certificat, ni le chemin. Un essai à blanc qui ne peut rien révéler rassure sans informer, et c’est pire que pas d’essai du tout.
Le RGPD n’est pas un formulaire
Une ligne banale, présente sur des millions de sites :
<link href="https://fonts.googleapis.com/css2?family=Raleway" rel="stylesheet">
Elle transmet l’adresse IP de chaque visiteur à un tiers hors Union européenne, avant tout consentement. Ce n’est pas une zone grise : un tribunal allemand a condamné un éditeur de site pour exactement ça en 2022.
Le correctif prend dix minutes. On télécharge les fichiers de police, on les sert depuis son propre serveur, on écrit soi-même la règle @font-face. Les polices concernées sont sous licence libre, ça ne pose aucun problème.
Le contrôle automatique existe pour la même raison que les autres : personne ne réintroduit Google Fonts exprès. On copie un bout de code d’un tutoriel, et c’est reparti pour six mois.
Savoir où s’arrêter
Le dispositif compte cinq sites. Trois tournent sous un générateur, avec des articles, des tags, un calendrier de publication. Deux n’en ont pas.
Les deux derniers font trois pages chacun. Un générateur ne supprimerait pas le travail : il supprimerait la duplication de l’ossature, et elle est déjà écrite. Le coût réel serait de ne plus pouvoir ouvrir une page et la modifier.
Retenez la question, elle vous servira souvent : cet outil supprime-t-il un travail répété, ou ajoute-t-il une couche à comprendre ? Trois pages, c’est la seconde réponse. Soixante et un articles avec un calendrier, c’est la première.
Ce que je n’ai pas automatisé
Le blog publie tout seul. Les articles portent leur date, le générateur ne construit que ce qui est dû, et une exécution planifiée deux fois par semaine met le site à jour sans que j’intervienne.
La publication sur les réseaux sociaux, elle, est restée manuelle. Techniquement, c’était le plus facile de la chaîne.
La raison n’est pas technique. Ce qui fait la portée d’un post, c’est la première heure : les réponses aux commentaires, la présence, la conversation. Une tâche planifiée ne sait pas tenir ça. Un post qui part pendant que je suis en réunion perd exactement ce qui aurait pu le faire circuler.
La machine prépare donc tout — le texte, le lien, le rappel la veille — et je garde le moment.
« C’est faisable » n’est pas « il faut le faire ». Vous allez passer votre carrière à pouvoir automatiser des choses. La question utile n’est jamais de savoir si c’est possible, mais ce qui se perd quand plus personne n’est là au moment où ça compte.
Pour aller plus loin
- Documentation de Hugo — gohugo.io/documentation
- GitHub Actions, prise en main — docs.github.com/actions
lftp, le manuel —man lftp, sectionmirror- CNIL, Google Analytics et transferts de données — cnil.fr