Extrait : Pour inaugurer ce blog, autant commencer par raconter sa propre construction : pourquoi j’ai choisi Ghost, comment je l’ai intégré à mon infrastructure et pourquoi une base de données presque vide consommait plus de 500 Mo de mémoire.


Ce premier article n’est pas vraiment un tutoriel.

C’est plutôt l’histoire du site que tu es en train de lire : pourquoi j’ai voulu créer un blog, comment je l’ai intégré à mon infrastructure et ce que j’ai appris au passage.

Avec, comme souvent, quelques choix techniques, deux ou trois erreurs et une base de données presque vide qui consommait beaucoup trop de mémoire.

Pourquoi créer un blog en 2026 ?

La question s’est posée assez simplement : pourquoi pas ?

J’aime parler de ce que je construis, mais un portfolio ne se prête pas toujours à l’exercice. Il montre le résultat final : un projet, quelques technologies, une capture d’écran et une description concise.

Il ne raconte pas forcément les hésitations, les essais, les erreurs ou les petites découvertes qui ont rendu ce résultat possible.

Je voulais donc un espace différent de mon portfolio. Un endroit où je pourrais prendre le temps de raconter une démarche, partager mes projets et écrire sur ce qui m’intéresse, sans devoir transformer chaque idée en étude de cas parfaitement présentée.

Une sorte de journal de bord public, en somme.

Pourquoi Ghost plutôt que WordPress ?

J’avais déjà utilisé WordPress par le passé. C’est un outil extrêmement complet, mais justement : pour ce projet, je n’avais pas besoin d’autant de choses.

Entre les extensions, les réglages et une interface assez chargée, j’avais parfois l’impression de devoir administrer une petite usine simplement pour publier du texte.

Je cherchais quelque chose de plus épuré, plus sobre et davantage centré sur l’écriture.

Ghost correspondait bien à cette idée : un éditeur agréable, une interface minimaliste et un moteur suffisamment léger pour rejoindre le reste de mon infrastructure dans un conteneur Docker.

Je ne voulais pas passer mon temps à bricoler mon outil de publication. Je voulais surtout pouvoir écrire avec.

Une place de plus dans mon infrastructure

Le blog suit la même organisation que mes autres services : un dossier dédié, son propre fichier docker-compose.yml et une connexion au réseau Docker partagé utilisé par mon reverse proxy.

C’est l’un des aspects que j’apprécie le plus avec Docker : chaque service peut rester dans sa bulle.

Si Ghost rencontre un problème, le portfolio continue de fonctionner. La base MySQL du blog dispose de son propre réseau interne et n’est accessible ni depuis Internet, ni directement par les autres services qui n’en ont pas besoin.

Cette séparation simplifie le déploiement, mais elle limite aussi les conséquences d’un éventuel incident.

Pour exposer le blog sur Internet, je passe par Traefik. Ce n’est pas encore l’outil que je maîtrise le mieux, mais je commence à vraiment apprécier sa logique.

Il centralise mes connexions HTTPS, gère le renouvellement automatique des certificats Let’s Encrypt et applique des règles de sécurité communes à mes différents sites : HSTS, protection contre le clickjacking, prévention du sniffing de type MIME ou encore politique de référent plus stricte.

Grâce à cette organisation, ajouter le blog a surtout consisté à lui fournir sa propre configuration. Le reste de la mécanique était déjà en place.

Ghost latest et MySQL

Avant le premier démarrage, il restait deux choix importants à faire : la version de Ghost et le moteur de base de données.

Pour Ghost, j’ai choisi l’image latest plutôt qu’une version entièrement figée.

Le blog étant publiquement accessible, je veux pouvoir récupérer rapidement les mises à jour, notamment lorsqu’elles corrigent une faille de sécurité. Utiliser latest ne met évidemment pas le conteneur à jour tout seul : il faut toujours récupérer la nouvelle image et redéployer le service. C’est donc un choix qui demande de rester attentif aux nouvelles versions.

Pour la base de données, j’ai préféré MySQL à SQLite.

Ce choix n’est pas lié à son exposition : la base reste confinée dans son réseau interne et n’est jamais directement accessible depuis l’extérieur.

La raison est beaucoup plus simple. J’ai appris à utiliser MySQL pendant ma formation et dans mon parcours professionnel. Je connais son fonctionnement, ses outils et ses méthodes de diagnostic. Autant capitaliser sur cette expérience.

SQLite aurait été plus rapide à mettre en place, mais je me sens plus à l’aise avec MySQL lorsqu’il faut comprendre ce qui ne va pas.

Et j’allais justement en avoir besoin.

Plus de 500 Mo de mémoire pour une base vide

Une fois Ghost et MySQL démarrés, j’ai vérifié l’état général de la machine.

Le blog n’avait encore aucun lecteur, aucun article publié et pratiquement aucune donnée. Pourtant, le VPS commençait déjà à utiliser son espace d’échange sur le disque.

Quelque chose n’allait pas.

En regardant la consommation de chaque conteneur, le principal responsable est rapidement apparu : MySQL utilisait à lui seul plus de 500 Mo de mémoire vive.

Pour une base quasiment vide, c’était légèrement excessif.

Une partie importante de cette consommation venait du performance_schema, activé par défaut. Cette fonctionnalité est utile pour analyser précisément le comportement d’un serveur MySQL, mais elle était complètement disproportionnée pour un blog personnel à faible trafic.

J’ai donc créé une configuration adaptée à mon usage : désactivation du performance_schema, réduction de l’InnoDB buffer pool à 64 Mo et quelques réglages plus raisonnables pour la taille réelle du projet.

Résultat : plus de 300 Mo de mémoire libérés, sans aucune différence visible dans le fonctionnement du blog.

C’est probablement la première vraie leçon de ce projet : avant d’ajouter des ressources à une machine, mieux vaut vérifier comment celles que l’on possède déjà sont utilisées.

Construire un thème plutôt qu’en adapter un

Installer Ghost ne suffisait évidemment pas. Je voulais que le blog ressemble à une extension naturelle de mon portfolio, pas à un site complètement différent simplement relié par un lien.

J’ai donc repris la même palette sombre, les mêmes typographies, les mêmes rayons, les mêmes ombres et la même logique de cartes.

Plutôt que de modifier progressivement un thème existant jusqu’à ce qu’il ne lui ressemble plus, j’ai préféré construire mon propre thème Ghost à partir de zéro.

Le header, les cartes d’articles, le footer et les différents composants reprennent ainsi le même langage visuel que florianutiel.fr.

Cela demande davantage de travail au départ, mais j’obtiens un thème que je comprends entièrement et que je pourrai faire évoluer sans devoir déconstruire les choix de quelqu’un d’autre.

Les petits pièges de Handlebars

Ghost utilise Handlebars pour générer les pages de ses thèmes. La prise en main est assez rapide, mais certains comportements manquent un peu d’explications lorsqu’on les rencontre pour la première fois.

Par exemple, le contenu d’un article doit être placé dans un bloc {{#post}}…{{/post}}. Sans ce contexte, {{content}} peut simplement renvoyer undefined, sans erreur particulièrement explicite.

J’ai rencontré le même genre de problème avec la navigation.

J’avais d’abord tenté de parcourir le menu avec une boucle {{#foreach navigation}}. En réalité, Ghost fournit un helper {{navigation}} chargé de générer directement le menu. Avec ma première approche, rien ne s’affichait — et, là encore, aucune erreur ne venait vraiment expliquer pourquoi.

Ce sont de petits détails, mais exactement le genre de détail qui peut faire perdre beaucoup de temps lorsqu’on découvre un nouvel écosystème.

Autant les noter ici. Ils serviront peut-être à quelqu’un — probablement à moi-même dans six mois.

Sécuriser sans tout casser

Chaque conteneur est lancé avec l’option no-new-privileges, afin d’empêcher un processus d’obtenir de nouveaux privilèges pendant son exécution.

Le portfolio, qui n’a pas besoin de modifier ses fichiers, utilise également un système de fichiers monté en lecture seule.

Côté HTTP, les principaux en-têtes de sécurité sont appliqués par Traefik à l’ensemble de mes sites : HSTS, protection contre le clickjacking, prévention du sniffing de contenu et politique de permissions restrictive.

Pour Ghost, j’ai toutefois choisi de ne pas rendre immédiatement la Content Security Policy trop stricte.

Le blog pourra plus tard accueillir des polices externes, des contenus intégrés ou éventuellement des services comme Stripe. Une CSP verrouillée trop tôt risquerait de casser ces fonctionnalités avant même que j’aie défini mes besoins.

Je préfère donc observer les ressources réellement utilisées, puis resserrer progressivement la politique. La sécurité n’est pas un interrupteur que l’on active une fois pour toutes : c’est un réglage continu entre réduction de la surface d’attaque et fonctionnement réel du service.

Et maintenant ?

Le résultat est désormais en ligne : un blog auto-hébergé, isolé du reste de mon infrastructure et visuellement cohérent avec mon portfolio.

J’ai également ajouté sur la page d’accueil de florianutiel.fr un petit widget capable d’afficher automatiquement mes derniers articles. Les deux sites restent indépendants, mais ils commencent à former un ensemble plus cohérent.

Il reste évidemment du travail.

Je dois encore améliorer le référencement, terminer certains détails du thème et mettre en place une véritable solution d’envoi d’e-mails pour le domaine.

Mais pour une fois, je vais éviter d’attendre que tout soit absolument parfait avant de publier.

Le blog existe. Le premier article aussi.

La suite peut commencer.