Migration vers Hugo
Depuis un (long) moment, l’interface d’édition de Wordpress me déplait nettement. Mon utilisation plus qu’anecdotique de ce site n’était pas non plus vraiment compatible avec les mises à jours de sécurité régulières et nécessaires.
J’ai donc décidé de passer sur autre chose, en l’occurence Hugo. Ce post détaille la migration.
Pourquoi Hugo ?
Je souhaite que tout reste auto-hébergé, pas de recours à des services externes.
Après quelques recherches, je me suis tourné vers un générateur de site statique, ce qui implique à priori moins de failles de sécurité. Il y en a plusieurs, qui au vu de mon utilisation, auraient répondu au besoin. Les deux plus courants semblent être Hugo et Jekyll. J’ai choisi Hugo car il s’agit d’un unique binaire, tandis que Jekyll nécessite l’installation de Ruby.
On fournit les sources des pages au format Markdown et un thème, et Hugo génère le site au format HTML. Il ne reste plus qu’à déployer le site.
Précédemment, le site et le blog étaient sur des noms de domaines séparés. Ce n’est plus le cas, tout se retrouve maintenant sur le www. Cela implique quelques modifications au serveur web pour qu’il redirige les anciennes url du blog correctement.
Modifier le site
Je voulais que la publication sur le site reste simple. Le process est le suivant :
- Les sources du site sont dorénavant dans un dépôt git. Précédememnt, si le site était bien dans un dépôt git, le blog était sur Wordpress.
- Je modifie le site sur ma machine, par exemple j’ajoute un article de blog comme celui-ci.
- commit
- push
- C’est fini, le site est actualisé.
Migration
Récupérer les données de Wordpress
Cette étape était simple.
- Installation du plugin Wordpress to Hugo Exporter
- Execution du plugin et récupération d’un zip avec toutes les données. Je n’ai gardé que les posts.
- Cleanup des fichiers Markdown récupérés à la main, n’ayant que quelques posts.
- Renommage des fichiers, par défaut ils incluent la date et je n’en voulais pas. J’ai aussi renommé quelques aberration d’anciennes versions de Wordpress.
- Ajout d’un alias dans le header de chaque fichier pour pointer vers l’ancienne url de WordPress (Exemple, ancienne url: https://blog.moomoocamp.net/index.php/build-boost-on-windows-with-mingw/ , alias:
/index.php/build-boost-on-windows-with-mingw/
) - Vérification des catégories et tags.
- Supression de l’heure, je ne voulais que la date.
- On se trouve avec un dossier contenant un fichier .md par post.
Création du site sur Hugo
Le plus long, c’est de choisir un thème…
- Installation de Hugo en local.
hugo new site blog-hugo
cd blog-hugo
git init
git submodule add https://github.com/rhazdon/hugo-theme-hello-friend-ng.git themes/hello-friend-ng
- Création du fichier config.toml à partir du fichier inclu dans le thème et modification pour correspondre au site
- Très légères modifications du thème (le footer notamment)
- Copie des fichiers .md récupéré de Wordpress dans le dossier
content/posts/
- Création d’une page about, modification du menu, …
- Ajout du tout pour le prochain commit git
- commit
Déploiement
Architecture
Il y a deux serveurs impliqués.
- Le serveur web.
- Le serveur git.
Ce que j’ai mis en place sur le serveur git :
- Les sources du site sont dans un dépôt sur Gitea
- A chaque push, Gitea appelle un webhook sur le serveur web
Ce que j’ai mis en place sur le serveur web :
- Un service webhook qui peut lancer des scripts quand le hook est appelé.
- Un script qui construit le site et le met dans le bon dossier.
Gitea
Je ne vais pas détailler l’installation de Gitea, juste la configuration dont on a besoin ici :
- Dans le dépôt, ajouter un déclencheur web vers l’url du futur webhook, par exemple https://example.com:10123/hook/blog-deploy
- Créer une clé SSH sur le serveur web avec l’utilisateur qui fera tourner le script du hook.
- Dans le dépôt, ajouter cette clé dans les clés de déploiement. Comme ça, l’utilisateur du webhook aura accès à ce dépôt (et uniquement celui-ci) en lecture uniquement.
Webhook
Installation
Le serveur web tourne sur une Debian. L’installation n’est pas bien compliquée.
apt install webhook
adduser webhook
J’ai modifié le fichier de démarrage du service, par défaut il tourne en root sans SSL. Les certificats sont générés avec Let’s Encrypt je ne vais pas détailler ça ici, ce n’est pas le sujet.
[Unit]
Description=Small server for creating HTTP endpoints (hooks)
Documentation=https://github.com/adnanh/webhook/
ConditionPathExists=/etc/webhook/webhook.conf
[Service]
WorkingDirectory=/home/webhook/
User=webhook
Group=webhook
ExecStart=/usr/bin/webhook -secure -cert /etc/webhook/ssl/fullchain.pem -key /etc/webhook/ssl/privkey.pem -port 10123 -hotreload -nopanic -hooks /etc/webhook/webhook.conf
[Install]
WantedBy=multi-user.target
Configuration
Le script du hook contient simplement l’appel au script.
[
{
"id": "blog-deploy",
"execute-command": "/home/webhook/scripts/blog-deploy.sh",
"command-working-directory": "/home/webhook"
}
]
Script
Le script est très basique pour l’instant.
#!/bin/bash
GIT_REPO_NAME=blog-hugo
GIT_REPO_URL="ssh://gitea@git.example.com/blog/blog-hugo.git"
TMP_BASE_DIR=/home/webhook/tmp
TMP_REPO_DIR=$TMP_BASE_DIR/$GIT_REPO_NAME
FINAL_DIR=/home/webhook/done/$GIT_REPO_NAME
if [ -e $TMP_REPO_DIR ]; then
echo "Git repo already exists. Updating..."
cd $TMP_REPO_DIR
git pull
else
echo "Git repo does not exist locally. Cloning..."
cd $TMP_BASE_DIR
git clone $GIT_REPO_URL --recursive
fi
if [ -e $TMP_REPO_DIR ]; then
echo "Git repo exists. Building with Hugo."
cd $TMP_REPO_DIR
hugo -D
if [ $? -ne 0 ]; then
echo "Hugo build failed. Exiting."
exit 1
else
rm -r $FINAL_DIR
mv $TMP_REPO_DIR/public $FINAL_DIR
fi
else
echo "Git repo should exist at this point but does not. Exiting."
exit 1
fi
Serveur web
Dans mon cas, le serveur web est simplement configuré avec un symlink vers le FINAL_DIR du script.
Pour ce qui est des redirections, j’ai ajouté ces deux lignes dans le VirtualHost qui concerne le domaine blog.moomoocamp.net, en attendant de le supprimer un jour :
RedirectMatch permanent "^/index.php/(.*)" "https://www.moomoocamp.net/index.php/$1"
RedirectMatch permanent "^/(.*)" "https://www.moomoocamp.net/"