J’ai arrêté de faire mes pg_dump à la main (et ma base de 77 Go me dit merci)

Rappelez-vous, il y a quelques années, j’avais parlé de la migration de la base de mon jeu AIM sur PostgreSQL. C’était une bonne idée, mais je n’avais rien automatisé au niveau des sauvegardes. Donc je faisais régulièrement mes sauvegardes à la main, je coupais le jeu et hop, un bon dump qui prenait trois heures.

Puis j’ai fait le calcul du nombre de jours de données que je perdrais si le disque lâchait maintenant. Et j’ai arrêté de trouver ça drôle. Parce que perdre 15 jours de jeu, ça peut faire pleurer.

Voilà donc le récit de comment je suis passée du pg_dump artisanal à une vraie automatisation avec pgBackRest, ce que ça m’a appris sur les enjeux réels d’une sauvegarde, et surtout ce que tout ça coûte (ou pas) aux performances du SGBD.


Le problème du dump manuel : ce n’est pas une sauvegarde, c’est un souvenir

Commençons par le mythe à démonter. Beaucoup de gens (moi la première) pensent avoir une sauvegarde parce qu’ils ont ça quelque part :

pg_dump -U postgres mabase > /backup/mabase.sql

C’est un fichier. Ce n’est pas une stratégie. Voici pourquoi.

1. Le RPO est catastrophique

Le RPO (Recovery Point Objective), c’est la quantité de données que tu acceptes de perdre. Avec un dump manuel fait « de temps en temps », ton RPO c’est : depuis la dernière fois que j’y ai pensé. Ça peut être trois semaines. Et tu ne le sauras qu’au moment où ça comptera vraiment.

2. Un dump de 77 Go, ce n’est pas un fichier, c’est un événement

Ma base de prod fait environ 77 Go. Un pg_dump là-dessus, ce n’est pas une commande qu’on lance négligemment en journée : c’est une longue lecture logique de toute la base, un CPU qui part en compression, et un fichier énorme à écrire. Je vais y revenir dans la partie perfs, mais retenez déjà ceci : plus la base grossit, moins tu as envie de lancer ta sauvegarde à la main. Et donc moins tu la lances. Le manuel se sabote tout seul.

3. Tu ne peux pas remonter à hier 14h37

Le dump est une photo. Si ta dernière photo date de dimanche et que la bêtise a eu lieu mardi à 14h37, tu reviens à dimanche. Point. Toutes les données de lundi et mardi : perdues. Alors que PostgreSQL sait faire infiniment mieux — il écrit en permanence un journal de toutes ses modifications, les WAL (Write-Ahead Logs). Si on archive ces journaux, on peut rejouer l’histoire jusqu’à la minute près. C’est le PITR (Point-In-Time Recovery). Le dump manuel jette cette possibilité à la poubelle.

4. Une sauvegarde jamais restaurée n’existe pas

C’est le point qui fait le plus mal. Un dump dans un coin, dont tu n’as jamais vérifié qu’il se restaure, c’est un pari, pas une garantie. L’automatisation force à structurer ça : un dépôt, un inventaire, une commande de vérification.


Ce que j’ai mis en place : pgBackRest + archivage des WAL

J’ai choisi pgBackRest. Pas par snobisme d’outil, mais parce qu’il fait nativement les trois choses que je voulais : sauvegarde physique, archivage WAL, et rétention automatique.

Étape 1 — Autoriser l’archivage côté PostgreSQL

Dans postgresql.conf :

wal_level = replica
archive_mode = on
archive_command = 'pgbackrest --stanza=mabase archive-push %p'
max_wal_senders = 3

Le point important ici : wal_level = replica est le minimum requis. Si vous laissez minimal, PostgreSQL refusera carrément de démarrer avec archive_mode = on. J’ai eu droit à ce joli message, un soir :

FATAL: WAL archival cannot be enabled when wal_level is "minimal"

Ça a le mérite d’être clair.

Étape 2 — Configurer la stanza

Une stanza, chez pgBackRest, c’est simplement le nom qu’on donne à un cluster sauvegardé. La mienne s’appelle mabase.

Dans /etc/pgbackrest.conf :

[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=2
compress-type=lz4
process-max=4
 
[mabase]
pg1-path=/var/lib/postgresql/16/main

Trois choix à souligner :

  • compress-type=lz4 : nettement plus rapide que gzip pour un taux de compression très honnête. Sur 77 Go, la différence n’est pas cosmétique.
  • process-max=4 : pgBackRest parallélise. C’est un de ses gros avantages sur pg_dump, qui reste largement mono-thread sur ce type de travail.
  • repo1-retention-full=2 : je garde deux sauvegardes complètes, les vieilles s’effacent toutes seules. La rétention automatique, c’est la moitié de l’intérêt de l’automatisation. Sans elle, on remplace « oublier de sauvegarder » par « saturer le disque de sauvegardes ». J’ai vu des serveurs mourir de ça.

Étape 3 — Initialiser et vérifier

sudo -u postgres pgbackrest --stanza=mabase stanza-create
sudo -u postgres pgbackrest --stanza=mabase check

Le check est votre ami : il valide que l’archivage WAL fonctionne réellement de bout en bout. Ne sautez pas cette étape.

Étape 4 — Le cron (le cœur du sujet)

crontab -u postgres -e
0 2 * * 2 nice -n 10 pgbackrest --stanza=mabase --type=full backup

Traduction : tous les mardis à 2h du matin, sauvegarde complète, en priorité CPU basse.

Deux détails qui comptent :

  • Le cron appartient à l’utilisateur postgres, pas à root. C’est le bon niveau de privilège pour ce travail — inutile de faire tourner en root quelque chose qui n’en a pas besoin.
  • nice -n 10 : la sauvegarde s’exécute en priorité réduite. Si le serveur a autre chose à faire à 2h du matin, la sauvegarde s’efface poliment. On y revient tout de suite.

Et pour vérifier au réveil que tout s’est bien passé :

sudo -u postgres pgbackrest --stanza=mabase info

Et les performances du SGBD dans tout ça ?

C’est LA question qui m’a fait traîner des mois. « Si j’automatise, est-ce que je vais plomber ma base ? »

Réponse courte : le manuel coûte plus cher que l’automatique. Voici pourquoi.

pg_dump est une lecture logique, pgBackRest une copie physique

pg_dump ne copie pas des fichiers : il reconstruit la base en la relisant intégralement et en générant du SQL. Ça veut dire un parcours complet, du CPU en pagaille, et surtout une transaction très longue ouverte pendant toute l’opération. Or une transaction longue empêche l’autovacuum de nettoyer les lignes mortes derrière elle. Sur une base à fortes écritures, un dump interminable en pleine journée, c’est du bloat qui s’accumule et des perfs qui se dégradent — bien après la fin du dump.

pgBackRest, lui, copie les fichiers du cluster. C’est plus proche du disque, ça se parallélise, et ça n’a pas ce coût transactionnel.

Le vrai chiffre

Ma première sauvegarde complète des 77 Go, avec lz4 et nice -n 10, a pris 22 minutes. Vingt-deux minutes, à 2h du matin, en priorité basse, sans que personne ne s’en aperçoive. À comparer avec un dump équivalent lancé un mardi à 15h « parce que j’y ai pensé ».

Le coût continu de l’archivage WAL

L’archivage n’est pas gratuit : chaque segment WAL rempli déclenche un archive-push. Le coût unitaire est faible, mais il y a un piège à connaître : si l’archive_command est plus lente que le rythme de production des WAL, les segments s’accumulent dans pg_wal/ et le disque se remplit. Surveillez cet espace disque. C’est le principal effet de bord d’une config PITR, et il est silencieux jusqu’au moment où il ne l’est plus.

Un mot sur synchronous_commit

Sur des charges à écritures très fréquentes, synchronous_commit = off donne un gain net : PostgreSQL n’attend plus la confirmation d’écriture du WAL sur disque pour valider la transaction. Mais soyons précises sur ce qu’on échange : en cas de crash brutal, vous perdez les quelques dernières centaines de millisecondes de transactions validées. La base reste cohérente (ce n’est pas fsync = off, qui lui est un vrai danger en prod), mais elle n’est pas complète.

C’est un arbitrage à faire en conscience, selon la valeur de vos dernières millisecondes.


Le jour où ça plante : restaurer à mardi 14h37

Tout ce qui précède ne sert à rien si on ne sait pas s’en servir le jour J. Alors imaginons le scénario. Mardi, 14h37, quelqu’un lance un DELETE sans WHERE sur une table centrale. À 14h50, on s’en aperçoit. Objectif : remettre la base exactement dans l’état de 14h36.

0. Ne rien faire de brutal

Le premier réflexe est le plus important : on ne redémarre pas PostgreSQL, on ne bricole rien. Si la base tourne encore, on l’arrête proprement et on réfléchit. Les WAL déjà archivés sont votre matière première : ne les touchez pas.

1. Regarder ce dont on dispose

sudo -u postgres pgbackrest --stanza=mabase info

Vous obtenez la liste des sauvegardes complètes avec leurs dates de début et de fin. Le point à vérifier absolument : votre cible (mardi 14h36) doit être postérieure à la fin d’une sauvegarde complète, et tous les WAL entre cette sauvegarde et la cible doivent être présents dans l’archive. Dans mon cas, avec un full le mardi à 2h, une cible à 14h36 le même mardi est parfaitement atteignable : pgBackRest repart du backup de 2h et rejoue ~12h de WAL.

2. Arrêter PostgreSQL

sudo systemctl stop postgresql

3. Restaurer avec une cible temporelle

C’est ici que le PITR prend tout son sens :

sudo -u postgres pgbackrest \
  --stanza=mabase \
  --delta \
  --type=time \
  --target="2026-07-14 14:36:00+02" \
  --target-action=promote \
  restore

Décortiquons, parce que chaque option compte :

  • –type=time + –target : la date et l’heure exactes où l’on veut atterrir. Précisez le fuseau horaire (+02 ici) — sans lui, PostgreSQL interprète selon le timezone du serveur, et se tromper d’une heure sur un rollback, c’est ballot.
  • –delta : pgBackRest compare les fichiers existants et ne réécrit que ce qui diffère. C’est plus rapide, et surtout ça vous évite d’avoir à vider le répertoire de données à la main. Parce que oui, la méthode « officielle » sans –delta exige un data directory vide, et ça veut dire taper un rm -rf /var/lib/postgresql/16/main/* en tremblant à 15h un mardi. Utilisez –delta.
  • –target-action=promote : une fois la cible atteinte, PostgreSQL sort du mode recovery et redevient ouvert en écriture. L’alternative, –target-action=pause, arrête la relecture et attend : la base est lisible mais figée, ce qui permet de vérifier qu’on est bien au bon endroit avant de valider. Sur une restauration où j’ai un doute sur l’heure exacte, je commence par pause.

pgBackRest choisit tout seul la bonne sauvegarde complète à utiliser en fonction de la cible. Il écrit également le recovery.signal et le restore_command dans postgresql.auto.conf — inutile de les créer à la main.

4. Redémarrer et regarder la base rejouer l’histoire

sudo systemctl start postgresql
sudo journalctl -u postgresql -f

C’est le moment le plus étrange de l’opération : PostgreSQL rejoue les WAL un par un, et vous voyez défiler dans les logs les heures de votre journée à l’envers. Vous cherchez la ligne qui confirme que le point de recovery a été atteint (recovery stopping before commit of transaction…, puis database system is ready to accept connections).

Tant que le recovery tourne, la base est en lecture seule. C’est normal, laissez-la finir.

5. Vérifier avant de crier victoire

La donnée la plus récente doit dater de ~14h36. Si oui : c’est gagné, et vous venez de récupérer 12h de travail qu’un pg_dump du dimanche vous aurait fait perdre.

SELECT COUNT(*) FROM ma_table_massacree;
SELECT MAX(created_at) FROM ma_table_massacree;

Pour conclure

Voilà tout tourne en tâche de fond, et les joueurs et moi on n’a plus à s’en soucier et au lieu de se préoccuper des dumps on peut ainsi écouter Radio Chirac, un son qui déchire pas mal.

De la cybersécurité (I’m back. Stronger.)

Enfin j’ai trouvé un peu de temps pour réparer tout mon bourbier.

En effet, depuis 2024, quand on accédait à mes sites wordpress, vous aviez ce message d’accueil fort charmant qui mentionnait un « incident technique ». J’avais dû fermer mes trois sites wordpress …

Pas des moindres. J’avais été piratée de partout ! Mon site d’urbex par exemple redirigeait vers une boutique en ligne. Et paf la cascade, mon site vitrine, mon blog et même un temps mon wiki sur mon jeu Minerland ! Un peu comme un jeu de dominos qu’on fait tomber petit à petit … de quoi être parano.

Il aura fallu attendre 2024 pour que ça se produise, en sachant que mes premiers sites perso remontent à 2000. Depuis, je me disais, tranquille, que je n’avais pas de raisons de me méfier ni de consolider mes iptables bien comme il le faut … voire faire l’impasse sur les mises à jour. L’erreur fatale. La cybersécurité est devenue lame de plus du développeur web qui doit apprendre de ses erreurs.

Intro sur la cybersécurité

En 2026, les petits sites web sont plus que jamais en première ligne.

Les attaques les plus courantes contre les petits sites sont silencieuses, opportunistes et automatisées. Elles défigurent un site, volent des données clients, ou utilisent le serveur pour héberger des contenus illicites, le tout à l’insu du propriétaire.

La grande nouveauté de 2026, c’est l’utilisation de l’IA par les attaquants. Les agents IA autonomes deviennent des outils courants de la cybercriminalité, capables de cartographier une attaque en quelques minutes et de générer des campagnes de phishing ciblées à grande échelle. Les campagnes de phishing générées par IA sont désormais quasiment indétectables — fini les fautes d’orthographe et les formulations bancales.

Plus de 90 % des piratages de sites WordPress exploitent des failles déjà corrigées dans une mise à jour que l’administrateur n’a pas appliquée. Le message est clair : mettre à jour, sécuriser ses accès, surveiller ses logs — ce n’est plus optionnel, même pour un petit blog perso.

Acte I — La découverte

Tout a commencé par un constat simple : mes sites WordPress ne répondaient plus correctement. En fouillant, j’ai découvert l’ampleur des dégâts. Les attaquants avaient réussi à s’introduire dans mes trois sites WordPress et ils s’étaient fait plaisir.

Leur spécialité : injecter du contenu. Des pages de spam, du phishing, et le pompon — un site de commerce en ligne complet, hébergé à mes frais sur mon propre serveur. Sympa.

En analysant les bases de données, j’ai retrouvé leurs traces partout. Dans la base d’amelieonline.net, un webshell — un script PHP qui permet de prendre le contrôle d’un serveur à distance — était planqué dans le fichier functions.php du thème. Du code obfusqué en base64 qui se connectait à des serveurs distants pour exécuter des commandes. Le plugin de sécurité All-In-One Security l’avait détecté et mis en quarantaine, mais le mal était fait.

Dans les fichiers du serveur, les bots avaient déposé des scripts PHP aux noms discrets : x.php, ha.php, gg.php… Des portes dérobées qui leur permettaient de revenir à volonté, même après un changement de mot de passe.

Acte II — Comment ils sont rentrés

La réponse est aussi simple que gênante : mon mot de passe wordpress était devenu trop faible. Ou alors ils se sont fait une joie de l’absence de certificat ssl …

Les bots qui parcourent internet 24h/24 testent des millions de combinaisons sur /wp-login.php et xmlrpc.php (une porte d’entrée WordPress souvent oubliée). Avec un mot de passe simple, il leur faut parfois quelques heures pour entrer.

Mais ce n’est pas tout. Mon serveur cumulait les facteurs aggravants. Ubuntu 18.04 en fin de vie depuis avril 2023, donc plus aucun correctif de sécurité. PHP 7.x, qui n’est plus maintenu depuis fin 2022. Pas de HTTPS — ce qui signifie que chaque fois que je me connectais à l’admin WordPress, mon identifiant et mon mot de passe transitaient en clair sur le réseau. Dans un café, à la gare, à l’hôtel, n’importe qui sur le même Wi-Fi pouvait les intercepter avec un simple outil comme Wireshark.

Et mon certificat SSL ? Expiré depuis des mois. J’avais payé cher pour un certificat classique, il avait expiré, et je n’avais jamais pris le temps de le renouveler. J’étais persuadée qu’il fallait racheter un certificat pour chaque nom de domaine. Trois domaines, trois certificats, une facture qui pique. En fait, non — mais j’y reviendrai.

Acte III — Le grand nettoyage

Le ménage a été méthodique. D’abord, les bases de données : analyser chaque dump SQL à la recherche de contenu injecté — du spam en chinois, en japonais, en cyrillique, des liens vers des boutiques frauduleuses, des webshells en quarantaine. Chaque site a été passé au peigne fin, table par table, grâce à l’aide de mon ami Claude, devenu mon nouveau formateur/secrétaire/IA couteau suisse.

Ensuite, les fichiers du serveur : traquer les scripts PHP malveillants dans les répertoires d’uploads (il ne devrait jamais y avoir de fichier PHP dans wp-content/uploads/), vérifier chaque thème, chaque plugin, identifier les fichiers modifiés récemment.

Et puis la grosse opération : migrer le serveur d’Ubuntu 18.04 vers une version maintenue. Trois sauts successifs — 18.04 vers 20.04, puis 22.04 — chacun avec son lot de surprises. PHP 7 vers PHP 8 a cassé plusieurs choses : des fonctions dépréciées, des syntaxes devenues invalides, des conflits de configuration entre l’ancien PHP-FPM et le nouveau module. À chaque étape, un site qui tombe, un diagnostic, une correction, on repart.

Acte IV — L’horreur des logs

C’est une fois le serveur remis d’aplomb que j’ai vraiment mesuré l’ampleur du problème. En regardant les logs d’authentification SSH :

Failed password for root from 179.111.150.107
Failed password for invalid user adurbex from 172.188.89.41
Failed password for invalid user amelayesbiophp from 59.51.98.254
Failed password for invalid user urbexmarseille from 187.191.48.4
Failed password for invalid user tonwebautableau from 121.78.158.30

Des dizaines de tentatives par heure. Et le plus flippant : les bots n’essayaient pas que des noms génériques comme « admin » ou « root ». Ils testaient adurbex, urbexmarseille, amelayesbiophp etc … — des identifiants dérivés de mes noms de domaines, de mon pseudo, de mes projets.

Quelqu’un — ou plutôt quelque chose — avait scanné mes sites, relevé tous les indices disponibles. Les noms d’auteur WordPress sont exposés par défaut via /?author=1 ou l’API REST (/wp-json/wp/v2/users). Les pages « à propos », les footers, les noms de domaine eux-mêmes : tout est découpé, recombiné, et testé automatiquement.

Les logs Apache racontaient la même histoire côté web : des scans massifs de wlwmanifest.xml (un fichier WordPress utilisé pour détecter les installations), des rafales de requêtes cherchant des webshells PHP à des noms comme x.php, ha.php, gg.php… Un bot a généré des dizaines de 404 en quelques millisecondes, balayant méthodiquement tous les noms de fichiers suspects.

En analysant les adresses IP, un inventaire géographique impressionnant : Brésil, Bulgarie, Chine, Corée du Sud, Russie, Vietnam, Pays-Bas, Ukraine, Singapour, Afrique du Sud… La plupart provenaient de datacenters ou de services cloud comme Microsoft Azure ou Alibaba Cloud. Et l’ironie : l’une des IP attaquantes appartenait à un serveur Kimsufi OVH — un serveur dédié comme le mien, probablement compromis et utilisé comme relais.

Ce ne sont pas de vrais humains derrière un écran. Ce sont des botnets — des réseaux de milliers de machines compromises qui scannent automatiquement toutes les IP du monde, 24 heures sur 24.

Acte V — Pourquoi mon petit serveur ?

C’est la question que je me suis posée. Mes sites ne contiennent rien de sensible. Mais ce n’est pas mes données qui intéressent les attaquants. C’est mon serveur lui-même : sa bande passante pour lancer des attaques vers d’autres cibles ou participer à des attaques DDoS, son processeur pour miner de la cryptomonnaie, son adresse IP pour héberger du phishing ou envoyer des millions de spams, et le fait qu’il tourne 24h/24 en faisant office d’outil gratuit.

Un serveur dédié compromis devient un soldat anonyme dans une armée de machines zombies. Et quand quelqu’un remonte la piste d’une attaque, c’est sur mon Kimsufi qu’il tombe — pas sur le vrai attaquant.

Acte VI — La fortification

La reconstruction s’est faite couche par couche.

Fail2ban, valeur sûre. J’avais fail2ban d’installé, mais sa configuration par défaut était une passoire : 10 minutes de bannissement après 5 échecs. Les bots attendaient tranquillement et revenaient. 4681 tentatives échouées au compteur, 491 IP bannies au total, mais zéro bannie à l’instant T. J’ai durci la config : 3 échecs en une heure, et c’est 24 heures de ban.

Mais le SSH n’était pas le seul front. J’ai ajouté des jails fail2ban pour chaque type d’attaque : les scans WordPress (wlwmanifest), les floods de 404 génériques, les tentatives de brute force sur DokuWiki, les scans de fichiers sensibles. Six jails au total, chacune avec ses propres seuils. Le port 22 quant à lui, exit !

Iptables pour les récidivistes. Pour les IP les plus agressives — celles avec 60, 80, 90 tentatives au compteur — j’ai écrit un script qui les bloque définitivement dans iptables. Ces adresses ne peuvent plus du tout communiquer avec mon serveur, sur aucun port, par aucun protocole.

CrowdSec, la défense collaborative. En plus de fail2ban, j’ai installé CrowdSec — un outil communautaire où les serveurs partagent les IP malveillantes. Quand une IP attaque un serveur du réseau, elle est signalée et bloquée sur tous les autres.

HTTPS avec Let’s Encrypt. Fini les certificats payants. Certbot et Let’s Encrypt m’ont permis de sécuriser mes trois domaines en une seule commande, gratuitement, avec renouvellement automatique tous les 90 jours. Plus jamais de certificat expiré oublié dans un coin. Un timer systemd vérifie deux fois par jour si un renouvellement est nécessaire.

Le blocage de xmlrpc.php. Ce fichier WordPress est un vecteur classique de brute force. Bloqué.

Les permissions qui vont bien. 644 pour les fichiers, 755 pour wp-content.

La mise à jour de tout. Ubuntu à jour, PHP à jour, WordPress core à jour, plugins à jour, thèmes à jour. Chaque composant obsolète est une porte ouverte.

Ce que j’ai appris

Cette aventure m’a enseigné des leçons que j’aurais aimé connaître plus tôt.

Un mot de passe faible est une porte ouverte. C’est banal à dire, mais c’est la cause numéro un des compromissions WordPress. Aujourd’hui, 20 caractères minimum, générés aléatoirement, et uniques pour chaque site.

Le HTTPS n’est pas optionnel. Même pour un blog perso, chaque page de connexion sans HTTPS est une invitation au vol d’identifiants. Et avec Let’s Encrypt, il n’y a plus aucune excuse financière.

La sécurité par défaut n’existe pas. Fail2ban installé avec sa config d’usine, c’est presque comme s’il n’était pas là. Il faut prendre le temps de configurer chaque outil correctement.

Tout serveur exposé sur internet est une cible. Ce n’est pas une question de « si », mais de « quand ». Les bots ne dorment jamais, et ils sont plus malins qu’on ne le croit — ils analysent vos sites pour en extraire des identifiants potentiels. Les premières tentatives de brute force arrivent dans les minutes qui suivent la mise en ligne d’un serveur.

Un système non maintenu est un système compromis. Ubuntu 18.04 en fin de vie + PHP 7 abandonné = zéro correctif de sécurité depuis des mois. Autant laisser la porte grande ouverte.

Vérifiez vos logs régulièrement. Sans cette habitude, je n’aurais jamais su que mon serveur subissait des milliers de tentatives d’intrusion quotidiennes.

Migration du serveur Minetest (en PostgreSQL !)

Le moment était venu. Le serveur qui hébergeait jusqu’alors mon jeu Minetest « Amelaye in Minerland » commençait à souffrir, tant la base de données tendait à être énorme (33 Go, vous voyez un peu …). Difficile de dire aux joueurs d’arrêter d’explorer, de creuser, bref de tirer la plus-value du monde qu’ils aimaient modifier. D’autant plus que j’avais bien envie d’installer de nouveaux mods. Et puis surtout, le serveur qui héberge le jeu est une machine perso, qui sert également pour pas mal de choses.

Alors j’ai décidé d’une part de louer un nouveau serveur Kimsufi, une machine assez robuste pour cet usage exclusif, et d’autre part, de migrer la base de données Minetest, à l’origine en SQLite vers PostgreSQL. Pourquoi ? Parce que si on regarde bien, c’est plutôt vivement recommandé.

Documentation des backends Minetest

Tout est dit, ne plus rester sous SQLite implique de limiter les lags, et également de réduire les risques de corruption de la base de données (ma plus grande crainte !). Et ça, c’est tout bénéf’ !

Allons-y. Ma nouvelle machine arrive toute fraiche avec la dernière version d’Ubuntu. Déjà, je m’enlève de la tête qu’on n’installe pas Minetest avec un simple apt-get dans mon cas de figure, ce serait trop simple. Car la version déjà compilée ne supporte pas PostgreSQL. Il va falloir compiler les sources. Je relève le défi.

On prépare le terrain

J’installe la matière première, les librairies qui me seront utiles …

sudo apt install wget postgresql 
postgresql-contrib g++ make libc6-dev libirrlicht-dev cmake 
libbz2-dev libpng-dev libjpeg-dev libxxf86vm-dev libgl1-mesa-dev 
libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev 
libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev 
libjsoncpp-dev libpq-dev libpqtypes-dev doxygen 
libluajit-5.1-dev libspatialindex-dev libncurses-dev

Comme ça, c’est fait. Je me crée un utilisateur minetest :

sudo useradd -mU minetest

Et je me logue sur le compte, comme ça :

sudo -i -u minetest

Puis je télécharge les sources de Minetest. Important : téléchargez la DERNIERE VERSION stable qui correspond à celle que vous utilisiez, sinon ça peut engendrer des bugs. Dans mon cas, c’est la 5.5.1 :

git clone https://github.com/minetest/minetest.git
git checkout 5.5.1
cd minetest/games/
git clone https://github.com/minetest/minetest_game.git
git checkout 5.5.1
cd ..

Ok, c’est facile. Maintenant, je passe à la pré-compilation (et je croise les doigts) :

cmake . -DRUN_IN_PLACE=TRUE 
-DBUILD_CLIENT=FALSE 
-DBUILD_SERVER=TRUE 
-DCMAKE_BUILD_TYPE=Release 
-DBUILD_UNITTESTS=FALSE 
-DENABLE_POSTGRESQL=TRUE 
-DVERSION_EXTRA=postgresql 
-DPostgreSQL_INCLUDE_DIR=/usr/include/postgresql 
-DPostgreSQL_TYPE_INCLUDE_DIR=/usr/include/postgresql 
-DPostgreSQL_LIBRARY=/usr/lib/x86_64-linux-gnu/libpq.so

Et là … ça plante.

CMake Error at CMakeLists.txt:110 (message):
IrrlichtMt headers are required to build the server, but none found.
The Minetest team has forked Irrlicht to make their own customizations.
It can be found here: https://github.com/minetest/irrlicht
For example use: 
git clone --depth=1 https://github.com/minetest/irrlicht lib/irrlichtmt

On sent bien les origines allemandes du jeu, tiens. Il a besoin d’une librairie « Irrlicht » pour pouvoir compiler. Mais pourtant, je l’ai apt-getté, celui-là … bon, on va là aussi compiler les sources avec l’adresse GIT qui est fournie alors.

Installation d’Irrlicht

Donc, on récupère Irrlicht dans le répertoire minetest pour pouvoir faire en sorte que l’include dans les sources trouve ses petits. Il est très important d’installer Irrlicht dans lib/irrlichtmt

git clone --depth=1 https://github.com/minetest/irrlicht lib/irrlichtmt

On va dans le répertoire et on compile :

cd lib/irrlichtmt
cmake . -DBUILD_SHARED_LIBS=OFF
make -j$(nproc)

Normalement on s’en sort avec juste quelques warnings.

Compilation réussie !

Je reviens deux répertoires en arrière, relance la pré-compilation de Minetest, et … mince encore des erreurs.

CMake Error at /usr/share/cmake-3.22/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
Could NOT find Zstd (missing: ZSTD_LIBRARY ZSTD_INCLUDE_DIR)
Call Stack (most recent call first):
/usr/share/cmake-3.22/Modules/FindPackageHandleStandardArgs.cmake:594 (_FPHSA_FAILURE_MESSAGE)
cmake/Modules/FindZstd.cmake:24 (find_package_handle_standard_args)
src/CMakeLists.txt:228 (find_package)

Bon, certainement une lib qui manque, ce ne sera pas la mer à boire. Je reviens dans mon compte utilisateur et je fais un petit :

sudo apt install -y libzstd-dev

Je reviens dans mon compte minetest et mon répertoire minetest, je relance la pré-compilation. Cool, ça a marché. Maintenant je lance la compilation :

make -j$(nproc)

Okay, le terminal m’indique que minetestserver a été compilé avec succès.

Je lance le binaire :

cd ..
./minetest/bin/minetestserver

Et je lance mon jeu depuis Minetest en spécifiant l’adresse IP du serveur. Tout se lance, génial. J’éteins le serveur, le plus complexe reste à venir.

Configuration du serveur PostgreSQL

Je relance par sécurité le service :

sudo systemctl restart postgresql.service

Et puis je lance mon interface PostgreSQL

sudo -u postgres psql 
CREATE USER monuser WITH PASSWORD '*****';
CREATE DATABASE adventure OWNER monuser;
GRANT ALL PRIVILEGES ON DATABASE adventure TO monuser;

Je vérifie avec /l que tout est ok et je sors

La migration de l’ancien serveur

Là, je suis obligée de dire à mes joueurs que le serveur doit être fermé pour la migration. J’éteins mon ancien serveur et je fais une copie de mon monde vers le nouveau. Je ne cache pas que ça prend du temps, vu le nombre de gigaoctets de mon map.sqlite.

Pour vous situer, il faut copier deux répertoires :
– celui des mods : .minetest/mods vers minetest/mods
– celui du monde, dans mon cas : .minetest/worlds/adventure vers minetest/worlds/adventure

Je tremble un peu durant ce transfert et prie pour que tout se passe bien. Je relance après cette étape en spécifiant mon monde et … ça se lance ! Tout va bien, je souffle un peu ! Maintenant passons aux choses sérieuses !

J’édite mon fichier world.mt du monde adventure pour y ajouter mes identifiants de connexion PostgreSQL. On ne touche à rien d’autre, notamment la configuration des backends en SQLite. Ce sera fait automatiquement.

pgsql_connection = host=127.0.0.1 port=5432 user=monuser password=***** dbname=adventure
pgsql_auth_connection = host=127.0.0.1 port=5432 user=monuser password=***** dbname=adventure
pgsql_player_connection = host=127.0.0.1 port=5432 user=monuser password=***** dbname=adventure

Et je lance ma première migration, celle du monde, et j’attends. Ce qui est sympa, c’est que l’avancée de la migration s’affiche :

./minetest/bin/minetestserver --migrate postgresql --world minetest/worlds/adventure

Si vous avez comme moi une base de données énorme, ne faites pas l’erreur que j’ai faite, de lancer le script dans un terminal et le laisser juste agir comme ça (sincèrement, je ne pensais pas que ça prendrait tant de temps !). Je suis partie me coucher, le lendemain mon ordi avait rebooté tout seul, interrompant le process (que j’avais lancé la veille à 15h30), et que j’ai dû relancer cette fois dans un screen (ou faites un nohup … &, bref, permettez au script de le laisser exécuté même si il y a une coupure.). Bref, une bonne vingtaine d’heures plus tard (oui, une VINGTAINE d’heures !!!) après le deuxième lancement, la base des blocs est migrée !

Regardons le fichier world.mt. Il a changé automatiquement le backend correspondant à la base des blocs. Nickel. Faisons la suite. Les autres bases de données migrent très vite.

./minetest/bin/minetestserver --migrate-auth postgresql --world minetest/worlds/adventure
./minetest/bin/minetestserver --migrate-players postgresql --world minetest/worlds/adventure

L’heure de vérité à sonné. Je vérifie que mes backends ont bien été modifiés et que tout pointe sur ma base PostgreSQL. Mieux que ça, je convertis mes fichiers map.sqlite, auth.sqlite et players.sqlite en map.old, auth.old et players.old. Je lance le jeu, et super, tout marche et je retrouve mon monde tel que je l’avais laissé …

Reste à remettre dans mon minetest.conf les paramètres de l’ancien serveur, sauf l’adresse, qui change.

Pour terminer, augmentez la mémoire allouée pour les requêtes PostgreSQL, sinon vous allez vous retrouver avec des plantages core dumped. Donc dans /etc/postgresql/potgresql.conf, changez la valeur du paramètre shared_buffer pour qu’il ait au moins une valeur supérieure à 512Mo. Chez moi, j’ai affecté 1024Mo.

Il ne reste plus qu’à profiter du jeu maintenant !

Comment monter un serveur d’archives PHP sans pleurer …

Mine de rien, concernant mon métier j’ai fait mes premiers pas en commençant mes études, ce qui commence à faire … un petit paquet d’années. Du coup en fait j’ai gardé (presque) toutes mes archives … ce qui n’est pas problématique quand on est en « full HTML » mais quand on passe en PHP, là c’est plus touchy. Parce que mes premiers sites sont en PHP4, en sachant qu’on se dirige vers la version 8, il y a eu pas mal de chemin depuis : renforcement de la rigueur, changements dans la conception objet, méthodes deprecated et j’en passe.

Essayez de faire marcher un site crée en 2003 sur un PHP 7 … ça m’étonnerait que vous puissiez faire quelque chose de concret. Du coup, pour faire comme moi, trouver des trucs de geek à faire en étant confiné (même si j’ai la chance de pouvoir continuer à travailler, il faut s’occuper le soir 😉 ) et faire tourner un serveur d’archives sur une Ubuntu récente, que faire ?

PHP 5.6 avec FPM

Il y a une solution pour les sites les plus récents : PHP-FPM, qui permet de faire tourner PHP en service indépendamment d’Apache (oui désolée je suis Apache-addict, question d’habitude), ce qui vous permet de pouvoir faire tourner un PHP5.6. C’est assez simple …

En premier lieu, on prépare le terrain, on se base déjà sur le fait que vous avec déjà Apache installé dans votre système.

Quelques librairies de base

Puis il vous faut ajouter le fameux repository d’Ondřej Surý, qui a fait un travail remarquable à ce sujet :

Et hop, magie !

N’oubliez pas d’ajouter les librairies MySQL au besoin. Une fois les installations bien terminées, faites un petit service status, histoire de bien vérifier que les services tournent :

Donc si vous avez un message de ce style, c’est que tout va bien 🙂

Donc là, vous pouvez faire tourner non seulement des sites tout neufs, mais également des sites que vous avez conçu il y a au moins trois-quatre ans. Il suffit après de configurer votre vhost comme suit pour switcher de version :

Vérifiez bien que les services suivants soient activés :
actions proxy_fcgi alias
Et les librairies suivantes installées pour PHP 5.6 au risque de voir une belle page blanche qui ne logge rien de pertinent :
php5.6-xml php5.6-gd php5.6-mcrypt php5.6-mysql php5.6-pdo

Et pour les versions antérieures à PHP 5.6 ?

Après, les choses se compliquent. Ne cherchez pas à installer ne serait-ce que PHP 5.2 à la mano, rien n’est compatible avec les versions actuelles d’OpenSSL et vous risquez de casser pas mal de trucs comme ça m’est arrivé. Et ainsi d’avoir à vous repalucher les installs d’Apache et OpenSSL, les joies de l’admin sys et de l’expérimentation, en somme 🙂 … – note : ce serveur n’est pas celui que j’utilise pour mes sites importants mais pour mon « bac à sable » 😉 …

Du coup j’ai opté pour un bel outil bien tendance qui a le vent en poupe chez les devOps, et qui est vraiment pratique, j’ai nommé : Docker ! J’ai finallement consenti à créer donc un conteneur qui ne servira qu’à mes plus anciens sites, et la bonne nouvelle, c’est qu’il n’y a pas tant de différences entre les dernières versions de PHP 4 et PHP 5.2 (au niveau du fait de pouvoir faire fonctionner un site en PHP 4 sur un serveur PHP 5.2, l’inverse ne sera pas forcément possible – et même fortement impossible), ce qui signifie que mes plus vieux sites tournent avec sans souci, et que je n’ai donc pas à créer de conteneurs supplémentaires (du moins, pour ma part ! ) !

Comme je suis une nana sympa, j’ai mis sur GitHub l’image que j’utilise, que vous pouvez déployer avec docker-compose, vous pouvez même définir un répertoire mysqldump pour alimenter la base directement en ligne de commande. Il y a également un PhpMyAdmin pour se simplifier la vie. Il faut juste modifier les vhosts pour que ça pointe sur vos sites à vous, qui seront accessible par défaut sur le port 8052 (80 port par défaut d’Apache et 52 comme PHP 5.2 😉 )

N’oubliez pas de préciser au besoin comme dans mon exemple, si vos extensions sont .php3, je sais ça fait super bizarre de retrouver ce genre d’extension …

Pour le plaisir, je vous montre une petite capture d’écran de ma page de garde, où je peux naviguer de site en site … c’est amusant de replonger dans le passé, comme ça :

Après, c’est un projet qui donne plein d’idées : par exemple vous voyez les petits screenshots ? Ils sont en réalité bien moches quand on passe en responsive, car dimensionnés assez petits (je pensais qu’à l’époque, ça suffisait). Bien là j’ai mis en place un process sous Puppeteer qui permet de faire des captures d’écran automatiquement ! Je pense que je vais pas mal trouver d’idées inspirantes que je vous partagerai par la suite 😉