Un logo en forme de goutte bleue avec un motif en spirale à gauche et un logo en forme d'engrenage sombre rappelant les éléments emblématiques de BitTorrent à droite, tous deux sur un fond noir. La goutte présente un dégradé et des bords nets, tandis que l'engrenage présente huit encoches et un petit point vert au centre.

Créer une seedbox BitTorrent avec deluge

Depuis la dernière mise à jour d’Ubuntu Server, le daemon transmission ne fonctionne plus correctement : il ne démarre plus de manière stable et les téléchargements ne se lancent que pendant cette période où il tente de se lancer.

J’ai passé pas mal de temps à essayer de résoudre le problème mais les mises à jour de transmission sont vraiment très espacées et il est fort probable que le projet ne soit plus maintenu dans quelques temps.

Il est donc temps de passer à un nouveau daemon bittorrent, qui se veut léger, rapide et efficace : deluge. Voici donc un tutoriel pour installer deluge sur Ubuntu Server pour créer une seedbox bittorrent.

Qu’est-ce qu’une seedbox ?

Une seedbox est un serveur informatique privé dédié au stockage, au téléchargement et à l’émission de fichiers numériques. Généralement, les seedboxes utilisent le protocole BitTorrent pour émettre et recevoir des données. Ces serveurs sont connectés à des réseaux à très haut débit symétrique, allant de 100 Mbit/s à 1 Gbit/s ou plus, selon l’option choisie.

Les principaux avantages d’une seedbox sont :

  1. Vitesse : les seedboxes peuvent télécharger et partager des fichiers à des vitesses très élevées, bien supérieures à celles d’une connexion Internet domestique classique.
  2. Sécurité : l’utilisation d’une seedbox permet de masquer votre adresse IP personnelle, offrant ainsi une meilleure protection de votre vie privée.
  3. Disponibilité : une seedbox fonctionne 24h/24 et 7j/7, même lorsque votre ordinateur personnel est éteint.
  4. Gestion de l’espace : les fichiers sont stockés sur le serveur distant, libérant ainsi de l’espace sur votre propre machine.

Dans le cadre de notre tutoriel, nous allons utiliser Deluge, un client BitTorrent open-source populaire, pour configurer notre seedbox sur un serveur Ubuntu.

Lire la suite

Trois icônes sur fond vert : une base de données bleu foncé représentée par des cylindres empilés à gauche, symbolisant les options de base de données WordPress ; une loupe avec une poignée noire et une lentille bleu clair au centre ; et un engrenage gris avec un centre blanc à droite, faisant allusion à l'intégration polyvalente de plugins.

Identifiez les options de base de données liées à vos plugins WordPress

Découvrez quelles options de base de données WordPress appartiennent aux plugins

Cet article vous montrera comment identifier quelles options de plugins WordPress dans la table  wp_options  appartiennent à un plugin spécifique.

Normalement, les développeurs recherchent manuellement dans la table wp_options avec phpMyAdmin ou Adminer (version plugin WordPress), mais cela peut souvent être très fastidieux car vous devez paginer parfois des centaines de pages !

Lorsque nous disposons d’outils de ligne de commande Linux via SSH comme WP-CLI et grep, nous pouvons efficacement identifier quelles options dans la base de données WordPress appartiennent à un plugin spécifique et gagner un temps précieux !

Dans cet article, je vais montrer les techniques que j’utilise habituellement pour trouver ces options afin de pouvoir corriger les paramètres, les sauvegarder, etc. en faisant correspondre le option_name WordPress au plugin.Veuillez noter que ces deux approches nécessiteront un terminal et un accès SSH de quelque sorte à votre installation WordPress.

Je supposerai que WP-CLI et grep sont déjà installés sur le système Linux. Kinsta, WPEngine et FastNyx fournissent un accès SSH avec WP-CLI et grep disponibles.

Lire la suite

Graphique textuel comportant les mots « MyISAM » et « InnoDB » en grandes lettres, de style bleu et orange. Un symbole de flèche circulaire bleu foncé les relie, faisant allusion à une conversion ou une intégration dans les environnements WordPress.

Convertir des tables de base de données WordPress de MyISAM à InnoDB avec WP-CLI

Dans cet article, je vous montre comment convertir facilement vos tables de base de données WordPress du moteur MyISAM au moteur InnoDB avec WP-CLI.

Si vous vous demandez pourquoi vous voudriez effectuer cette conversion de base de données, je vous avais déjà parlé des améliorations d’InnoDB par rapport à MyISAM (tirer parti de plusieurs cœurs est assez impressionnant). On constate d’énormes améliorations du temps de réponse et une réduction de la charge du serveur après la conversion de MyISAM à InnoDB. Il existe également des différences d’index MySQL intéressantes entre les deux moteurs.

Commençons !

Conversion des tables WordPress de MyISAM à InnoDB avec WP-CLI

Vérifiez si certaines de vos tables utilisent MyISAM au lieu d’InnoDB:

wp db query "SHOW TABLE STATUS WHERE Engine = 'MyISAM'" --allow-rootCode language: JavaScript (javascript)

Si vous n’obtenez aucune sortie, il n’y a pas de tables MyISAM. Si vous obtenez une sortie, elle ressemblera à ceci :

+----------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+--------------------+----------+----------------+---------+
| Name     | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time         | Update_time         | Check_time          | Collation          | Checksum | Create_options | Comment |
+----------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+--------------------+----------+----------------+---------+
| wp_posts | MyISAM |      10 | Dynamic    | 2579 |           1916 |     443644 | 28147497610655 |      4224000 |         0 |          11861 | 2017-08-19 21:56:47 | 2017-09-07 03:55:17 | 2017-08-19 21:56:48 | utf8mb4_unicode_ci |     NULL |                |         |
+----------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+--------------------+----------+----------------+---------+Code language: PHP (php)
Faites une sauvegarde de votre base de données avant de commencer !

Lire la suite

Un fond vert présente « Jetpack » dans une police élégante et stylisée à gauche, associée à une icône de balai à droite pour une touche de fantaisie. Au dessus du texte, un logo WordPress circulaire arbore un éclair audacieux à l'intérieur, offrant une ambiance électrique à votre expérience de désinstallation.

WordPress : désinstaller Jetpack proprement avec WP-CLI

Des fonctionnalités de Jetpack maintenant payantes

J’ai utilisé Jetpack pour les statistiques de mes sites WordPress site depuis 2004, soit 20 ans… mais voilà que Jetpack demande maintenant de payer pour avoir accès aux statistiques mensuelles et annuelles. Cela ne va pas être possible.

Jetpack est une extension couteau suisse, mais qui utilise vraiment tous les outils du couteau suisse? J’ai donc fait le tour des fonctionnalités de Jetpack que j’utilisais réellement et elles sont somme toute peu nombreuses: Stats, Related Posts, Publicize, et Protect.

Au lieu de Stats, j’utilise depuis quelques semaines Koko Analytics : vos statistiques sont dans votre base de données WordPress, donc chez vous, et le plugin respecte le RGPD (pas de cookies, pas d’informations personnelles). J’utilise également Plausible Analytics qui tourne sous Docker et dont je vous avais parlé il y a quelques mois.

Publicize permet d’envoyer vos posts sur les réseaux sociaux, je trouverai bien une alternative plus tard. Protect, le module de sécurité, n’est pas vraiment essentiel puisque la sécurité est en grande partie gérée par le serveur et le WAF.

Pour Related Posts, j’ai modifié le plugin qui j’utilise depuis des années pour qu’il génère des miniatures à la mode Jetpack mais sans le tracking. Car oui, tous les services de Jetpack (comme WooCommerce d’ailleurs) téléphonent les informations du site et du serveur chez Automattic. Mettons-y un terme.

Je vous propose donc un tutoriel pour désinstaller Jetpack proprement et supprimer les enregistrements Jetpack de la base de données car ils ne sont pas retirés à la suppression du plugin. Ainsi, vous aurez une base de données plus propre et donc un site plus rapide.

Lire la suite

php 8.4 ubuntu

Installer PHP 8.4 sur le serveur

PHP 8.4 est tout beau, tout chaud: la nouvelle version est sortie le 21 novembre, comme prévue. Pas mal de nouveautés ont été intégrées. Si vous lisez ces lignes, sachez que le site tourne déjà dessus.

Faisons un petit tour d’horizon de PHP 8.4 avec ses changements, améliorations et nouveautés, avant de l’installer sur notre serveur Ubuntu.

Les nouveautés de PHP 8.4

PHP 8.4 ravira les utilisateurs avec de nombreuses fonctionnalités et améliorations impactantes. Par exemple, ils peuvent utiliser intelligemment de nouvelles fonctions de tableau, telles que :

  • array_find()
  • array_find_key()
  • array_any()
  • array_all()

De plus, il y a d’autres fonctionnalités incroyables de PHP 8.4 qui attireront l’attention des utilisateurs dès le départ, notamment :

  • Hooks de propriétés
  • Visibilité asymétrique
  • MyClass()->method() sans parenthèses
  • Changements JIT
  • Support HTML5
  • Autres fonctionnalités de PHP 8.4 à surveiller

Hooks de propriétés

Les propriétés dans les objets PHP ont offert divers avantages comme l’implémentation des validations de valeurs. Pour cette raison, les types de propriétés à partir de PHP 7 ont grandement aidé à cela.

Néanmoins, le fait que la validation doive, par nécessité, se faire via une méthode a conduit à beaucoup de code répétitif sous forme de getters et setters ou à l’abus des méthodes magiques __get et __set.

En réalité, les propriétés en lecture seule dans PHP 8 résolvent de nombreux problèmes pour les développeurs. Ils peuvent protéger les valeurs via le constructeur et offrir toujours des propriétés entièrement typées pour un accès direct.

Les Hooks de propriétés offrent également une fonctionnalité robuste pour travailler avec les propriétés de classe PHP. Les propriétés peuvent optionnellement expliquer un ou plusieurs hooks, actuellement limités à “get” et “set”, vous permettant d’intervenir dans le cycle de vie de la propriété. Voici un exemple tiré du RFC :

class User implements Named
{
    private bool $isModified = false;
    public function __construct(private string $first, private string $last) {}
    public string $fullName {
        // Override the "read" action with arbitrary logic.
        get => $this->first . " " . $this->last;
        // Override the "write" action with arbitrary logic.
        set {
            [$this->first, $this->last] = explode(' ', $value, 2);
            $this->isModified = true;
        }
    }
}Code language: PHP (php)

Visibilité asymétrique

La visibilité asymétrique est une fonctionnalité innovante qui aide les développeurs à expliquer une visibilité différente pour diverses opérations sur une propriété. Cela leur permet de contrôler intelligemment la visibilité des membres de classe, tels que les propriétés et les méthodes.

Par exemple, vous pouvez indiquer que vous souhaitez autoriser un accès public en lecture à une propriété, mais ne permettre les modifications qu’en interne :

public private(set) string $bar = 'baz';Code language: PHP (php)

La visibilité asymétrique fonctionne en parallèle avec les changements présentés avec les hooks de propriétés, y compris la possibilité de décrire la visibilité dans les interfaces.

MyClass()->method() sans parenthèses

Une pratique courante en PHP est d’instancier une classe et d’accéder immédiatement à une méthode ou une propriété. Voici un exemple ci-dessous :

$request = (new Request())->withMethod('GET')->withUri('/hello-world');Code language: PHP (php)

Nous devions entourer la classe de parenthèses lors de son instanciation, ce qui était une exigence du moteur PHP. Avec PHP 8.4, les utilisateurs peuvent omettre ces parenthèses, offrant une utilisation plus conviviale :

$request = new Request()->withMethod('GET')->withUri('/hello-world');Code language: PHP (php)

Changements JIT

PHP 8.4 a modifié la façon dont le JIT est activé. Auparavant, les utilisateurs devaient définir opcache.jit_buffer_size à 0 pour désactiver le JIT. Cependant, vous pouvez maintenant le désactiver comme décrit ci-dessous :

opcache.jit=disable
opcache.jit_buffer_size=64m

Ce changement affectera les utilisateurs s’ils avaient spécifié un opcache.jit_buffer_size mais n’avaient pas spécifié opcache.jit. Dans cette situation, les utilisateurs devront incorporer opcache.jit=tracing pour activer à nouveau le JIT. De plus, les utilisateurs constateront des améliorations du JIT, le rendant plus fluide et rapide.

Support HTML5

PHP 8.4 inclut une classe \Dom\HTMLDocument qui peut analyser efficacement le code HTML. L’ancienne classe \DOMDocument est toujours accessible pour la rétrocompatibilité.

$doc = \Dom\HTMLDocument::createFromString($contents);Code language: PHP (php)

Pour les développeurs qui analysent ou construisent du HTML en utilisant l’extension DOM, cette version fournira diverses fonctionnalités innovantes et orientées résultats, ainsi qu’un support robuste pour HTML5.

Lire la suite

Une couronne stylisée avec deux créatures héraldiques dos à dos, chacune ressemblant à un renard ou à un loup, est positionnée au centre sur un fond de formes géométriques violettes. En dessous, elle passe à un dégradé d'orange et de rouge rappelant les teintes vibrantes trouvées dans les versions Ubuntu Server 22.04 LTS et 24.04 LTS.

Mise à jour du serveur vers Ubuntu 24.04 LTS

L’heure est venue de mettre notre serveur Apollo à jour: jusqu’alors sous Ubuntu 22.04 (jammy jellyfish), nous passons à Ubuntu 24.04 LTS (noble numbat).

On installe l’outil de mise à jour Ubuntu:

apt install ubuntu-release-upgrader-core

On vérifie que l’outil est bien configuré pour récupérer la version LTS:

 grep 'lts' /etc/update-manager/release-upgrades

#  lts    - Check to see if a new LTS release is available.  The upgrader
Prompt=ltsCode language: PHP (php)

On ajoute une règle pour ufw pour ouvrir le port 1022 en cas de souci:

sudo ufw allow 1022/tcp comment 'Open port ssh TCP/1022 as failsafe for upgrades'
Rule added
Rule added (v6)Code language: JavaScript (javascript)

On lance la mise à jour:

sudo do-release-upgrade -d
Checking for a new Ubuntu release

= Welcome to Ubuntu 24.04 LTS 'Noble Numbat' =

The Ubuntu team is proud to announce Ubuntu 24.04 LTS 'Noble Numbat'.

Reading cache

Checking package manager

Continue running under SSH?

This session appears to be running under ssh. It is not recommended
to perform a upgrade over ssh currently because in case of failure it
is harder to recover.

If you continue, an additional ssh daemon will be started at port
'1022'.
Do you want to continue?

Continue [yN] y

Starting additional sshd

To make recovery in case of failure easier, an additional sshd will
be started on port '1022'. If anything goes wrong with the running
ssh you can still connect to the additional one.
If you run a firewall, you may need to temporarily open this port. As
this is potentially dangerous it's not done automatically. You can
open the port with e.g.:
'iptables -I INPUT -p tcp --dport 1022 -j ACCEPT'

To continue please press [ENTER]Code language: PHP (php)

Lire la suite

Plausible Analytics, une alternative respectueuse de la confidentialité à l'installation de Google Analytics pour Ubuntu Server.

Plausible Analytics au lieu de Google Analytics

Tout le monde connaît Google Analytics mais savez-vous qu’il existe une alternative simple, open source et qui ne nécessite pas de bannière de cookies ? Je vous présente Plausible Analytics.

Plausible Analytics est une plateforme d’analyse Web open source qui se concentre sur le respect de la vie privée et la simplicité. Contrairement à des solutions plus courantes comme Google Analytics, Plausible a été conçu avec une approche centrée sur la vie privée, ce qui signifie qu’il ne collecte pas de données personnelles des visiteurs.

Cela rend la plateforme conforme aux réglementations strictes en matière de protection des données, telles que le RGPD en Europe, donc idéal pour nous.

Caractéristiques clés

  1. Respect de la vie privée : pas de cookies, pas de suivi des adresses IP, ce qui signifie que vous n’avez généralement pas besoin de demander le consentement des utilisateurs pour suivre les statistiques.
  2. Open Source : le code source est disponible pour tout le monde, ce qui signifie que vous pouvez l’héberger vous-même et examiner le code pour vous assurer qu’il respecte ses promesses en matière de vie privée.
  3. Simple et facile à utiliser : l’interface utilisateur est simple, propre et facile à comprendre, même pour les personnes qui ne sont pas techniquement compétentes.
  4. Léger : le script de suivi est beaucoup plus léger que celui de solutions concurrentes, ce qui signifie qu’il a un impact minimal sur les performances du site Web.
  5. Rapports en temps réel : vous obtenez des rapports en temps réel sur les visiteurs, les pages vues, les taux de rebond, et plus encore.
  6. Intégration facile : Plausible Analytics peut être facilement intégré avec d’autres plates-formes et outils, grâce à des API et des webhooks.

En résumé, Plausible Analytics est une alternative solide et respectueuse de la vie privée aux solutions d’analyse Web traditionnelles. Il est particulièrement utile pour ceux qui valorisent la simplicité, l’open source, et le respect des données des utilisateurs.

Ce tutoriel aborde l’installation sous Ubuntu Server mais comme c’est une image docker, c’est totalement adaptable pour votre distribution linux préférée.

Lire la suite

avif logo rgb

Recréer les fichiers AVIF corrompus

Cela fait une paire de fois que les images au format AVIF ne s’affichent pas sur SkyMinds et aujourd’hui, on règle le problème une bonne fois pour toute.

Concrètement, à chaque fois que j’uploade une image dans la bibliothèque de média de WordPress, plusieurs images sont créés: les miniatures bien sûr mais aussi un jeu d’images au format WEBP et au format AVIF. Tout se fait de manière automatique avec ShortPixel lors de l’upload.

Or, dernièrement certaines images ne s’affichent plus. Si on retire la source AVIF du DOM du document, le WEBP s’affiche bien, tout comme l’image originale en PNG ou JPG. C’est donc au niveau de la compression AVIF que cela coince.

Procédure de debug

Configuration NginX

Si vous vous souvenez bien, j’ai dans ma configuration NginX des directives pour donner la précédence aux formats AVIF et WEBP sur toutes mes images. Cela permet de servir en priorité les fichiers images aux formats les plus récents, avec un fallback sur les formats plus anciens (JPG, PNG notamment).

J’ai passé la configuration au peigne fin et il n’y a pas de problème à ce niveau. Les fichiers AVIF sont bien servis, le problème se trouve plus au niveau de l’encodage des fichiers.

Tester les images affectées

Lorsque je visionne un article avec une image affectée par le bug, elle ne saffiche pas mais apparait comme une image cassée. Lorsque l’on ouvre l’image dans un nouvel onglet, on obtient l’erreur suivante: “the image cannot be displayed because it contains errors“.

Je ne connais pas le nom des images affectées ni leur nombre (cela inclut aussi les miniatures) donc le plus simple est de dresser la liste des fichiers AVIF sur le site. Ensuite, je veux inspecter chaque image pour vérifier qu’elles possèdent bien les entêtes et bits nécessaires à leur bon affichage.

Commençons par installer les outils nécessaires pour examiner les fichiers AVIF:

apt install libavif-bin libavif13

On lance un test sur un fichier problématique:

avifdec /home/www/example/wp-content/uploads/2021/05/the-handmaids-tale-june-nick.avif /dev/null Code language: JavaScript (javascript)

et voici le résultat:

Decoding with AV1 codec 'dav1d' (1 worker thread), please wait... 
ERROR: Failed to parse image: BMFF parsing failed 
Diagnostics: * Box[meta] does not have a Box[hdlr] as its first child boxCode language: JavaScript (javascript)

L’erreur (“ERROR: Failed to parse image: BMFF parsing failed”), suggère que le fichier est en effet soit corrompu, soit incompatible donc nous allons le recréer.

Un script bash pour recréer tous les fichiers AVIF corrompus

Il est évident que nous n’allons pas tester tous les fichiers un par un. Maintenant que nous avons pu tester un fichier, nous allons créer une boucle pour tester tous les fichiers qui ont été uploadés sur le site : si le fichier est corrompu, nous allons le recréer, sinon on passe au suivant.

Lire la suite

An image of a computer screen with a green and purple background displaying the Message Of The Day (MOTD) on Ubuntu Server.

Changer le Message Of The Day (MOTD) sous Ubuntu Server

Le Message Of The Day (communément appelé MOTD) est un message d’accueil ou des notifications importantes que les administrateurs de serveurs peuvent configurer pour s’afficher lorsqu’un utilisateur se connecte au serveur via SSH.

Ce tutoriel vous montre comment mettre à jour et personnaliser le MOTD sur un serveur Ubuntu 22.04.

Prérequis

  • Serveur Ubuntu 22.04 avec accès root ou un utilisateur avec des privilèges sudo.
  • Accès SSH au serveur.

Étape 1 : connexion au Serveur

Connectez-vous à votre serveur Ubuntu via SSH:

ssh USER@SERVER_IP -pPORTCode language: CSS (css)

Étape 2 : vérifier le MOTD existant

Pour voir le MOTD actuel, utilisez la commande suivante :

cat /run/motd.dynamic

Étape 3 : modifier le MOTD dynamique

Ubuntu 22.04 utilise des scripts dans le répertoire /etc/update-motd.d/ pour générer une partie du MOTD dynamiquement. Vous pouvez ajouter, supprimer ou modifier les scripts dans ce répertoire pour personnaliser davantage le MOTD.

Entête MOTD

Nous allons créer un entête qui contient le nom de notre serveur en ASCII art, ce qui nous permettra de bien l’identifier lors de nos sessions SSH:

sudo nano /etc/update-motd.d/00-custom

Et on y ajoute notre script bash:

#!/bin/sh

# Reset
Color_Off='\033[0m'       # Text Reset

# Bold
BBlack='\033[1;30m'       # Black
BRed='\033[1;31m'         # Red
BGreen='\033[1;32m'       # Green
BYellow='\033[1;33m'      # Yellow
BBlue='\033[1;34m'        # Blue
BPurple='\033[1;35m'      # Purple / Magenta
BCyan='\033[1;36m'        # Cyan
BWhite='\033[1;37m'       # White

# Set the text color to green
printf "$BGreen"

# https://patorjk.com/software/taag/#p=display&f=Doom&t=APOLLO%20.%20SKYMINDS%20.%20NET
cat << "EOF"
  ___  ______ _____ _      _     _____       _____ _   ____   ____  ________ _   _______  _____       _   _  _____ _____
 / _ \ | ___ \  _  | |    | |   |  _  |     /  ___| | / /\ \ / /  \/  |_   _| \ | |  _  \/  ___|     | \ | ||  ___|_   _|
/ /_\ \| |_/ / | | | |    | |   | | | |     \ `--.| |/ /  \ V /| .  . | | | |  \| | | | |\ `--.      |  \| || |__   | |
|  _  ||  __/| | | | |    | |   | | | |      `--. \    \   \ / | |\/| | | | | . ` | | | | `--. \     | . ` ||  __|  | |
| | | || |   \ \_/ / |____| |___\ \_/ /  _  /\__/ / |\  \  | | | |  | |_| |_| |\  | |/ / /\__/ /  _  | |\  || |___  | |
\_| |_/\_|    \___/\_____/\_____/\___/  (_) \____/\_| \_/  \_/ \_|  |_/\___/\_| \_/___/  \____/  (_) \_| \_/\____/  \_/
EOF

# Set the text color to magenta
printf "$BPurple"

# Left image lines
left1="                                   88 88  "
left2="                                   88 88  "
left3="                                   88 88  "
left4=",adPPYYba, 8b,dPPYba,   ,adPPYba,  88 88  ,adPPYba,"
left5="\"\"     \`Y8 88P'    \"8a a8\"     \"8a 88 88 a8\"     \"8a"
left6=",adPPPPP88 88       d8 8b       d8 88 88 8b       d8"
left7="88,    ,88 88b,   ,a8\" \"8a,   ,a8\" 88 88 \"8a,   ,a8\""
left8="\"8bbdP\"Y8 88\`YbbdP\"'   \"\"YbbdP\"'  88 88  \"\"YbbdP\"'"
left9="           88                                          "
left10="           88                                         "

# Right image lines
right1=" .              +   .                .   . .     .  ."
right2="                   .                    .       .     *"
right3="  .       *                        . . . .  .   .  + ."
right4="            \"You Are Here\"            .   .  +  . . ."
right5=".                 |             .  .   .    .    . ."
right6="                  |           .     .     . +.    +  ."
right7="                 \\|/            .       .   . ."
right8="         . .        V          .    * . . .  .  +   ."
right9="               +      .           .   .      +"
right10="                               .       . +  .+. ."

# Combine and print
echo "$left1 $right1"
echo "$left2 $right2"
echo "$left3 $right3"
echo "$left4 $right4"
echo "$left5 $right5"
echo "$left6 $right6"
echo "$left7 $right7"
echo "$left8 $right8"
echo "$left9 $right9"
echo "$left10 $right10"

# STATS
upSeconds="$(/usr/bin/cut -d. -f1 /proc/uptime)"
secs=$((${upSeconds}%60))
mins=$((${upSeconds}/60%60))
hours=$((${upSeconds}/3600%24))
days=$((${upSeconds}/86400))
UPTIME=$(printf "%d days, %02dh%02dm%02ds" "$days" "$hours" "$mins" "$secs")

# get the load averages
read one five fifteen rest < /proc/loadavg

# text in yellow
printf "$BYellow"

echo "
   .~~.   .~~.    `date +"%A, %e %B %Y, %r"`
  '. \ ' ' / .'   `uname -srmo`
   .~ .~~~..~.
  : .~.'~'.~. :   Uptime.............: ${UPTIME}
 ~ (   ) (   ) ~  Memory.............: `cat /proc/meminfo | grep MemFree | awk {'print $2'}`kB (Free) / `cat /proc/meminfo | grep MemTotal | awk {'print $2'}`kB (Total)
( : '~'.~.'~' : ) Load Averages......: ${one}, ${five}, ${fifteen} (1, 5, 15 min)
 ~ .~ (   ) ~. ~  Running Processes..: `ps ax | wc -l | tr -d " "`
  (  : '~' :  )   IP Addresses.......: `ip a | grep glo | awk '{print $2}' | head -1 | cut -f1 -d/` and `wget -q -O - https://icanhazip.com/ | tail`
   '~ .~~~. ~'    Weather............: `curl -s "https://rss.accuweather.com/rss/liveweather_rss.asp?metric=1&locCode=EUR|FR|FR|NANTES|" | sed -n '/Currently:/ s/.*: \(.*\): \([0-9]*\)\([CF]\).*/\2°\3, \1/p'`
       '~'
"

# text default colour
printf "$Color_Off"Code language: PHP (php)

Cela affiche le nom du serveur (apollo.skyminds.net) puis une petite frise, et enfin les statistiques ainsi que la météo pour Nantes. Vous pouvez modifier la ville dans l’avant-dernière ligne.

Notez que j’ai compilé deux images pour qu’elles s’affichent sur les mêmes lignes: le mot “apollo” en ASCII art et une version de l’univers avec le texte “You are here!”. Il faut jouer avec l’indentation mais au bout de quelques essais, cela rend plutôt pas mal je trouve.

Rendez le script exécutable :

sudo chmod +x  /etc/update-motd.d/00-custom

Lancez la compilation de tous les modules dynamiques pour obtenir le MOTD final qui sera affiché à chaque connexion SSH:

run-parts /etc/update-motd.d/ > /run/motd.dynamicCode language: JavaScript (javascript)

Lire la suite

A black and white photo of the statue of Apollo.

Nouveau serveur dédié OVH : Apollo

J’ai craqué pour un nouveau serveur chez OVH. C’est mon premier serveur OVH, si l’on considère que je n’ai jamais utilisé que des Kimsufi auparavant, depuis mars 2010.

Voyons voir ce qu’il a dans le ventre.

Processeur

On obtient les spécifications du processeur:

lscpu

Ce qui nous donne:

lscpu

Architecture:            x86_64
  CPU op-mode(s):        32-bit, 64-bit
  Address sizes:         39 bits physical, 48 bits virtual
  Byte Order:            Little Endian
CPU(s):                  16
  On-line CPU(s) list:   0-15
Vendor ID:               GenuineIntel
  Model name:            Intel(R) Xeon(R) E-2288G CPU @ 3.70GHz
    CPU family:          6
    Model:               158
    Thread(s) per core:  2
    Core(s) per socket:  8
    Socket(s):           1
    Stepping:            13
    CPU max MHz:         5000.0000
    CPU min MHz:         800.0000
    BogoMIPS:            7399.70
    Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts a
                         cpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch
                         _perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq
                         dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_
                         2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowp
                         refetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow
                         vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpci
                         d mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida a
                         rat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilitie
                         s
Virtualization features:
  Virtualization:        VT-x
Caches (sum of all):
  L1d:                   256 KiB (8 instances)
  L1i:                   256 KiB (8 instances)
  L2:                    2 MiB (8 instances)
  L3:                    16 MiB (1 instance)
NUMA:
  NUMA node(s):          1
  NUMA node0 CPU(s):     0-15
Vulnerabilities:
  Gather data sampling:  Mitigation; Microcode
  Itlb multihit:         KVM: Mitigation: VMX disabled
  L1tf:                  Not affected
  Mds:                   Not affected
  Meltdown:              Not affected
  Mmio stale data:       Mitigation; Clear CPU buffers; SMT vulnerable
  Retbleed:              Mitigation; Enhanced IBRS
  Spec store bypass:     Mitigation; Speculative Store Bypass disabled via prctl and seccomp
  Spectre v1:            Mitigation; usercopy/swapgs barriers and __user pointer sanitization
  Spectre v2:            Mitigation; Enhanced IBRS, IBPB conditional, RSB filling, PBRSB-eIBRS SW sequence
  Srbds:                 Mitigation; Microcode
  Tsx async abort:       Mitigation; TSX disabledCode language: JavaScript (javascript)

Nous avons donc un Intel(R) Xeon(R) E-2288G CPU @ 3.70GHz (8c/16t), avec toutes les corrections appliquées pour corriger les vulnérabilités.

C’est une belle mise à jour par rapport à l’ancien serveur, qui était un Intel(R) Xeon(R) CPU W3530 @ 2.80GHz (4c/8t), qui n’était pas aussi sécurisé.

Bande passante

On passe sur une bande passante à 500Mbit/s et non plus en 100Mbit/s, toujours en illimité (unmetered).

Mémoire et disques

On reste sur 32GB de RAM mais on double sa vitesse: on passe de la DDR3 @ 1333 MHz à de la DDR4 ECC @ 2666 MHz:

sudo dmidecode -t memory | grep -i speed

Résultat:

Speed: 2666 MT/s
Configured Memory Speed: 2666 MT/s

Au niveau des disques, changement également: nous avions 2 × 2TB Soft RAID avec des disques durs classiques et maintenant on passe sur 2 × 960GB SSD NVMe Soft RAID.

Système d’exploitation

On reste sous Ubuntu Server, qui est vraiment agréable à utiliser et configurer. J’ai été surpris de voir que lorsqu’on installe Ubuntu Server 22.04 de rien, il crée un utilisateur par défaut, qui n’est pas root. C’est plutôt bien, mais ce n’était pas le cas avec Ubuntu Server 18.04 (root était alors le seul utilisateur créé lors de l’installation).

C’est bien au quotidien, pour la migration, il a fallu pas mal changer les commandes rsync toutefois.

Migration d’Orion à Apollo

La migration s’est bien déroulée. D’ailleurs, si vous pouvez lire cet article, c’est que le site est bien servi par Apollo.

Outre les fichiers et les bases de données, c’est aussi tout le serveur email qui a été entièrement recréé.

La bonne nouvelle, c’est que c’est plus simple que ce j’avais fait la première fois avec Postfix et Courier. La moins bonne nouvelle, c’est que cela prend un temps fou parce qu’il y a environ une quinzaine de fichiers à éditer constamment pour que tout soit parfait.

Bonus du serveur email: il est mieux configuré que le précédent, avec une configuration plus simple mais mieux sécurisée, et toujours avec DNSSEC et DANE.

J’ai écrit pas mal de scripts bash pour automatiser certaines installations dans le cadre d’une future migration. On en reparle bientôt!

Update MySQL client and server versions using apt config.

Mettre à jour MySQL client, server et apt-config

Un an après mon article sur l’erreur APT : the following packages have been kept back, voici que cela recommence : impossible d’installer les mises à jour de mysql-client et mysql-server parce que mysql-apt-config n’est plus à jour.

J’ai tendance à oublier la solution parce que je n’y suis confronté que depuis peu donc j’ai écris un petit script bash que je pourrai lancer la prochaine fois, histoire de gagner du temps.

Pré-requis: installation de pup

pup est un outil en ligne de commande pour traiter le HTML. Il lit à partir de stdin, imprime vers stdout, et permet à l’utilisateur de filtrer des parties de la page en utilisant des sélecteurs CSS.

Nous téléchargeons pup depuis son repo sur Github, on extraie le binaire et on le déplace dans /usr/local/bin/ :

wget https://github.com/ericchiang/pup/releases/download/v0.4.0/pup_v0.4.0_linux_amd64.zip

unzip pup_v0.4.0_linux_amd64.zip

sudo mv pup /usr/local/bin/Code language: JavaScript (javascript)

Script bash pour mettre à jour MySQL avec mysql-apt-config

Nous créons notre nouveau script, et nous le rendons exécutable:

cd /home/scripts

nano install-latest-mysql-apt.sh

chmod +x install-latest-mysql-apt.sh

Et voici le contenu du script:

#!/bin/bash
# ----------------------------------------- #
# Script Name: install-latest-mysql-apt.sh  #
# Author: Matt Biscay                       #
# URL: https://www.skyminds.net/?p=613967   #
# ----------------------------------------- #

# Color codes
RED=$(tput bold; tput setaf 1)
GREEN=$(tput bold; tput setaf 2)
YELLOW=$(tput bold; tput setaf 3)
MAGENTA=$(tput bold; tput setaf 5)
NC=$(tput sgr0) # No Color

# Function to print the header
function print_header() {
  echo -e "${YELLOW}# ----------------------------------------- #${NC}"
  echo -e "${YELLOW}# Script Name: install-latest-mysql-apt.sh  #${NC}"
  echo -e "${YELLOW}# Author: Matt Biscay                       #${NC}"
  echo -e "${YELLOW}# URL: https://www.skyminds.net/?p=613967   #${NC}"
  echo -e "${YELLOW}# ----------------------------------------- #${NC}"
}

# Print the header
print_header

# Function to check if the command exists
function check_command() {
  command -v "$1" &> /dev/null || {
    echo -e "${RED}$1 is not installed. Please install it and try again.${NC}"
    exit 1
  }
}

# Check if wget, unzip are installed
check_command wget
check_command unzip

# Check if pup is installed
if ! command -v pup &> /dev/null; then
  read -p $"${MAGENTA}The \"pup\" tool is not installed, would you like to install it now? (Y/N) ${NC}" INSTALL_PUP
  case ${INSTALL_PUP:0:1} in
    [Yy]* )
      TMP_DIR=$(mktemp -d)
      wget https://github.com/ericchiang/pup/releases/download/v0.4.0/pup_v0.4.0_linux_amd64.zip -O "$TMP_DIR/pup.zip"
      unzip "$TMP_DIR/pup.zip" -d "$TMP_DIR"
      mv "$TMP_DIR/pup" /usr/local/bin/
      rm -r "$TMP_DIR"
      echo -e "${GREEN}Package pup has been installed.${NC}"
      ;;
    [Nn]* )
      echo "Exiting since pup is not installed."
      exit 1
      ;;
    * )
      echo -e "${RED}Invalid input. Please enter Y or N.${NC}"
      exit 1
      ;;
  esac
fi

BASE_URL="https://dev.mysql.com"
INITIAL_URL="${BASE_URL}/downloads/repo/apt/"

# Create temporary files
TMP_INITIAL=$(mktemp)
TMP_SECONDARY=$(mktemp)

echo "Fetching initial page... $INITIAL_URL"
wget -qO- "$INITIAL_URL" > "$TMP_INITIAL"

# Extract the secondary download page URL from the main page
echo "Extracting secondary page URL..."
SECONDARY_URL=$(cat "$TMP_INITIAL" | pup 'div.button03 a attr{href}')
echo "Secondary URL: ${BASE_URL}${SECONDARY_URL}"

# Fetch the secondary page and store its content for debugging
echo "Fetching secondary page..."
wget -qO- "${BASE_URL}${SECONDARY_URL}" > "$TMP_SECONDARY"

# Extract the download link from the secondary page
echo "Extracting download link..."
DOWNLOAD_URL=$(cat "$TMP_SECONDARY" | pup 'a:contains("No thanks, just start my download.") attr{href}')
echo "Download URL: ${BASE_URL}${DOWNLOAD_URL}"

# Ask user if they want to install mysql-apt-config
read -p $"${MAGENTA}Do you want to download and install the package? (Y/N) ${NC}" DOWNLOAD_MYSQL_APT_CONFIG
case ${DOWNLOAD_MYSQL_APT_CONFIG:0:1} in
    [Yy]* )
        wget "${BASE_URL}${DOWNLOAD_URL}" -O mysql-apt-config.deb
        dpkg -i mysql-apt-config.deb

        echo -e "${GREEN}Package mysql-apt-config has been updated.${NC}"

        read -p $"${MAGENTA}Are you ready to install updates with \"apt update && apt upgrade\"? (Y/N) ${NC}" UPDATE_UPGRADE
        case ${UPDATE_UPGRADE:0:1} in
            [Yy]* )
                apt update && apt upgrade
                ;;
            [Nn]* )
                echo "Exiting without installing updates."
                ;;
            * )
                echo -e "${RED}Invalid input. Please enter Y or N.${NC}"
                ;;
        esac
        ;;
    [Nn]* )
        echo "Exiting without installing."
        ;;
    * )
        echo -e "${RED}Invalid input. Please enter Y or N.${NC}"
        ;;
esac

# Trap to clean up temporary files
trap 'rm -f "$TMP_INITIAL" "$TMP_SECONDARY" mysql-apt-config.deb' EXITCode language: PHP (php)

Fonctionnement du script

Le script commence par vérifier que pup est installé. S’il ne l’est pas, on prompte l’utilisateur pour l’installer:

The "pup" tool is not installed, would you like to install it now? (Y/N) y

Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1718186 (1.6M) [application/octet-stream]
Saving to: ‘/tmp/tmp.4buPXeejfo/pup.zip’

Archive:  /tmp/tmp.4buPXeejfo/pup.zip
  inflating: /tmp/tmp.4buPXeejfo/pup
Package pup has been installed.Code language: JavaScript (javascript)

Le script effectue deux requêtes sur le site de MySQL: lors de la première requête, il identifie le lien du bouton “Download”.

Lire la suite

Resolve error 526 with Cloudflare and NginX.

Résoudre l’erreur 526 entre Cloudflare et NginX

Dernièrement, je me suis apercu qu’une requête curl sur le domaine skyminds.net (sans www donc), donnait une erreur 526 sous Cloudflare (avec le proxy activé, mais aussi sans):

curl -Ik https://skyminds.net


HTTP/2 526
date: Fri, 18 Aug 2023 23:50:35 GMT
content-type: text/html; charset=UTF-8
content-length: 7111
cf-ray: 7f8e0f5538300636-CDG
cf-cache-status: BYPASS
cache-control: private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
expires: Thu, 01 Jan 1970 00:00:01 GMT
set-cookie: cf_ob_info=526:7f8e0f55430d0636:CDG; path=/; expires=Fri, 18-Aug-23 23:51:05 GMT
vary: Accept-Encoding
cf-apo-via: origin,resnok
referrer-policy: same-origin
set-cookie: cf_use_ob=443; path=/; expires=Fri, 18-Aug-23 23:51:05 GMT
x-frame-options: SAMEORIGIN
report-to: {"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v3?s=KQ7z1CYzwZD3r%2FzoJ2QLzFRmcgQzql1Oz3KwXyVnHVWHH5mUgxKqwU8p2%2F0C9rn%2FJUOSQG%2BWZl9%2B%2FDdQSPXznmFKKeiqFdqXzpuGFK5xgZbHAohOVxY4Vk6%2F1bM73jNRhrjfYZ42r6FMJ6c%3D"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
server: cloudflare
alt-svc: h3=":443"; ma=86400
Code language: JavaScript (javascript)

Sous tous les navigateurs par contre, une brève page d’erreur s’affiche (quelques millisecondes) avant que finalement la redirection vers le sous-domaine www ne s’effectue. Je me suis dis que c’était bizarre et que je réglerais le problème plus tard.

Quelques semaines mois passent et j’effectue une petite visite de routine sur mes sous-domaines, notamment celui de postfixadmin. Et là, patatras : erreur 526 avec le proxy Cloudflare actif, mais aussi une ribambelle d’erreurs selon les navigateurs utilisés:

Échec de la connexion sécurisée Une erreur est survenue pendant une connexion à demo.skyminds.net.

Le pair SSL a rejeté un message d’établissement de liaison à cause d’un contenu inacceptable. Code d’erreur : SSL_ERROR_ILLEGAL_PARAMETER_ALERT

La page que vous essayez de consulter ne peut pas être affichée car l’authenticité des données reçues ne peut être vérifiée. Veuillez contacter les propriétaires du site web pour les informer de ce problème.

Firefox

Ce site est inaccessibleIl se peut que la page Web à l’adresse https://demo.skyminds.net soit temporairement inaccessible ou qu’elle ait été déplacée de façon permanente à une autre adresse Web. ERR_QUIC_PROTOCOL_ERROR

Brave

Bon, il va falloir s’atteler à comprendre ce qui se passe vraiment ici!

Vérification du certificat TLS

On vérifie que le certificat est valide:

echo | openssl s_client -connect skyminds.net:443 -servername skyminds.net 2>/dev/null | openssl x509 -noout -dates

notBefore=Aug  6 12:15:26 2023 GMT
notAfter=Nov  4 12:15:25 2023 GMTCode language: JavaScript (javascript)

Tout est bon, le certificat est toujours valide.

On vérifie ensuite que les sous-domaines sont bien inclus (au cas où, mais je crée toujours des certificats wildcard par défaut):

echo | openssl s_client -connect skyminds.net:4echo | openssl s_client -connect skyminds.net:443 -servername skyminds.net 2>/dev/null | openssl x509 -noout -text


Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            03:cc:a2:48:39:97:ea:6c:d0:5d:86:5a:e3:f8:e3:d3:b2:1a
        Signature Algorithm: ecdsa-with-SHA384
        Issuer: C = US, O = Let's Encrypt, CN = E1
        Validity
            Not Before: Aug  6 12:15:26 2023 GMT
            Not After : Nov  4 12:15:25 2023 GMT
        Subject: CN = skyminds.net
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:69:84:99:0b:ea:1b:6f:38:ac:ee:fa:76:7d:4f:
                    59:01:02:bd:6e:d8:25:83:a7:8a:c5:d5:a4:b9:c5:
                    64:65:2d:49:20:3d:bc:4c:06:38:7d:73:d0:c0:55:
                    0b:90:cf:44:f7:5a:8c:37:8f:f9:da:51:eb:c3:f0:
                    5b:87:ce:00:ba
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Key Identifier:
                E7:3A:09:C3:D5:75:02:65:A6:D7:7D:12:D4:F3:5D:42:72:11:75:B4
            X509v3 Authority Key Identifier:
                5A:F3:ED:2B:FC:36:C2:37:79:B9:52:30:EA:54:6F:CF:55:CB:2E:AC
            Authority Information Access:
                OCSP - URI:http://e1.o.lencr.org
                CA Issuers - URI:http://e1.i.lencr.org/
            X509v3 Subject Alternative Name:
                DNS:*.skyminds.net, DNS:skyminds.net
            X509v3 Certificate Policies:
                Policy: 2.23.140.1.2.1
            CT Precertificate SCTs:
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 7A:32:8C:54:D8:B7:2D:B6:20:EA:38:E0:52:1E:E9:84:
                                16:70:32:13:85:4D:3B:D2:2B:C1:3A:57:A3:52:EB:52
                    Timestamp : Aug  6 13:15:26.501 2023 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : B7:3E:FB:24:DF:9C:4D:BA:75:F2:39:C5:BA:58:F4:6C:
                                5D:FC:42:CF:7A:9F:35:C4:9E:1D:09:81:25:ED:B4:99
                    Timestamp : Aug  6 13:15:26.502 2023 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
    Signature Algorithm: ecdsa-with-SHA384
    Code language: PHP (php)

Le certificat couvre bien skyminds.net et *.skyminds.net, donc tous les sous-domaines.

Lire la suite