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/

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' EXIT

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.

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

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 GMT

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
    

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

Lire la suite

wordpress rocketstack

WordPress Rocket Stack : envoyez WordPress sur orbite !

Sur Orion, j’ai installé ma WordPress Rocket Stack qui est configurée avec la stack suivante:

  • Ubuntu Server 22.04 LTS
  • MySQL 8+
  • NginX 1.25+
  • PHP 8.0
  • Redis
  • Nginx FastCGI Cache
  • Fail2ban
  • Letsencrypt avec acme.sh

Hébergement

L’hébergement est la base de votre site, c’est tout simplement la fondation sur laquelle va reposer votre code.

Vous avez tout intérêt à avoir un très bon hébergeur : il doit être rapide dès le départ et offrir de bonnes garanties en termes de performance et de sécurité.

Si vous avez un site WordPress ou WooCommerce, je ne peux que vous recommander Kinsta, WPEngine ou Nexcess. Tous trois sont de très bons hébergeurs, particulièrement orientés vers la performance avec des ressources garanties et un support technique réactif et efficace en cas de besoin.

Personnellement, j’utilise un serveur dédié chez OVH parce que j’héberge pas mal de sites et j’ai besoin d’avoir un contrôle fin sur la configuration de chacun des services.

Ubuntu Server

J’étais auparavant sous Debian mais j’ai finalement opté pour Ubuntu Server 22.04 LTS pour ce nouveau serveur.

L’avantage d’Ubuntu est de pouvoir disposer des mises à jour plus rapidement que sous Debian.

Installation de la WordPress Rocket Stack

# MySQL
# Latest link is always on the apt page: https://dev.mysql.com/downloads/repo/apt/
wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.23-1_all.deb
dpkg -i mysql-apt-config_0.8.23-1_all.deb

# Packages
apt install software-properties-common tmux curl wget zip unzip git
add-apt-repository ppa:ondrej/php
add-apt-repository ppa:ondrej/nginx-mainline
apt update -y
apt upgrade -y
apt install mysql-server -y # accept all defaults

# PHP 8.0
# Note: the json module is now part of PHP core
apt install php8.0 php8.0-bcmath php8.0-curl php8.0-gmp php8.0-imap php8.0-mbstring php8.0-readline php8.0-xml php8.0-apcu php8.0-cli php8.0-fpm php8.0-igbinary php8.0-intl php8.0-mysql php8.0-redis php8.0-zip php8.0-common php8.0-gd php8.0-imagick php8.0-opcache php8.0-soap -y

# Run installs
apt install nginx -y
apt install fail2ban -y
apt install redis -y

# Get NginX config files
git clone https://github.com/skyminds/wordpress-rocketstack
cp wordpress-rocketstack/nginx/* /etc/nginx/ -R
rm wordpress-rocketstack

DNS : ajout du site sur le serveur

Mon serveur est hébergé chez OVH donc il faut ajouter le domaine aux DNS secondaires du serveur.

Sur l’interface Kimsufi, cela se fait très simplement:

Ajouter le domaine au serveur (dns secondaire)
Ajouter le domaine au serveur (dns secondaire)

Configurer Cloudflare

Si vous utilisez Cloudflare – ce que je vous recommande fortement – et que vous obtenez une erreur 403 ou alors une page “Welcome to NginX” en lieu et place de votre nouveau site, veillez bien à sélectionner la bonne option SSL dans Cloudflare > Example.com > SSL/TLS > Overview : il faut sélectionner Full ou Full (Strict) mais surtout pas “Flexible“:

Choisissez toujours l'option SSL/TLS Full (Strict) chez Cloudflare
Choisissez toujours l’option SSL/TLS Full (Strict) chez Cloudflare

Ensuite, il ne nous reste qu’à faire pointer le CNAME vers l’adresse IP du serveur et d’ajouter le champs TXT qui a été indiqué par OVH dans l’étape précédente:

Ajout de l'enregistrement DNS au format TXT pour valider le DNS secondaire chez OVH
Ajout de l’enregistrement DNS au format TXT pour valider le DNS secondaire chez OVH

Ajout du server block NginX

DOMAIN="example.com"
DOMAINDIR="example"

mkdir -p /home/www/$DOMAINDIR
chown www-data:www-data /home/www/$DOMAINDIR

mkdir -p /home/nginx-cache/$DOMAINDIR
chown -R www-data:www-data /home/nginx-cache/

cp /etc/nginx/sites-available/wprocketstack.conf /etc/nginx/sites-available/$DOMAINDIR.conf

rm /etc/nginx/sites-enabled/default
rm /etc/nginx/sites-available/default

On édite ensuite la configuration:

nano /etc/nginx/sites-available/$DOMAINDIR.conf

Mettez l’adresse du site dans la directive server_name:

server_name example.com

Lire la suite

ssh secure shell laptop

SSH : Host key verification failed

Voici la solution pour le problème “authenticity of host ‘example.com can’t be established” ou “Host key verification failed” lors d’une session SSH sous Linux, MacOS ou Windows.

J’ai récemment travaillé sur un site WordPress multisite hébergé sur WPEngine. Lorsque j’ai voulu me connecter au site en SSH, j’ai reçu une drôle d’erreur:

The authenticity of host 'example.ssh.wpengine.net (xxx.xxx.xxx.xxx)' can't be established.
RSA key fingerprint is SHA256:T8IoIg6/q7i3pVfZipYtxow4.
This host key is known by the following other names/addresses:
    ~/.ssh/known_hosts:38: 1.ssh.wpengine.net
    ~/.ssh/known_hosts:42: 2.ssh.wpengine.net
    ~/.ssh/known_hosts:47: 3.ssh.wpengine.net
    ~/.ssh/known_hosts:52: 4.ssh.wpengine.net
    ~/.ssh/known_hosts:54: 5.ssh.wpengine.net
    ~/.ssh/known_hosts:56: 6.ssh.wpengine.net
    ~/.ssh/known_hosts:76: 7.ssh.wpengine.net
    (2 additional names omitted)
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Host key verification failed.

Comme vous pouvez le voir, il y a déjà pas mal de domaines connus dans mon trousseau SSH, qui appartiennent à ssh.wpengine.net.

Pour une raison obscure toutefois, le nouveau sous-domaine n’est pas admis, contrairement aux sous-domaines précédents qui n’avaient posé aucun problème.

Solution: ajouter la clé au trousseau manuellement

Si la clé ne peut être ajoutée automatiquement, ajoutons-la manuellement et tentons de nous connecter.

Concrétement, il faut donc insérer la clé RSA du serveur dans le fichier /home/user/.ssh/known_hosts de la machine qui se connecte en SSH au serveur distant.

Nous pouvons faire cela en une seule commande:

ssh-keyscan -t rsa example.ssh.wpengine.net >>  ~/.ssh/known_hosts
# example.ssh.wpengine.net:22 SSH-2.0-Go

Voici ce que fait la commande:

  • ssh-keyscan -t rsa SSH.EXAMPLE.COM : cela récupère la clé RSA de l’hôte SSH.EXAMPLE.COM
  • >> ~/.ssh/known_hosts : cela copie la clé et l’insère dans le répertoire .ssh du dossier personnel de notre utilisateur, à la fin du fichier known_hosts qui contient tous les hôtes et clés RSA pour SSH.

Lire la suite

lastfm scrobbler for icecast

Soumettre à Last.fm les chansons d’un flux Icecast

Voici le script python que j’ai écrit pour soumettre automatiquement à Last.fm les chansons qui sont diffusées sur ma radio Icecast.

Au fil du temps, j’ai publié dans ces colonnes différents tutoriels pour gérer une radio avec Icecast, à l’aide de Winamp, VirtualDJ, et SAM Broadcaster dont on pouvait créer un fichier texte qui pouvait ensuite être filtré puis utilisé avec un script PHP pour soumettre les chansons à Last.fm.

Il y a quelques semaines, Stéphan m’a contacté pour m’informer que le script PHP que j’utilisais jusqu’alors pour scrobbler les titres était maintenant incompatible avec PHP8, et qu’il lui fallait installer PHP7.4 spécifiquement pour le faire tourner.

Le script n’utilisait pas les dernières API de Last.fm non plus, donc c’était le bon moment de moderniser tout cela. J’en ai d’ailleurs profité pour servir le serveur Icecast en HTTPS.

Le choix de Python

Après de multiples essais, je me suis vite rendu compte que PHP n’était pas du tout adapté au scrobbling : la plupart des librairies PHP sont maintenant obsolètes (PHP8) ou ne sont plus maintenues car Last.fm est en perte de vitesse (par rapport à ce que c’était il y a quelques années).

Python, au contraire, est très simple à utiliser et il existe une librairie spécifique dédiée à l’API Last.fm qui nous permet de soumettre les titres simplement: pylast.

Enfin, l’avantage de python est qu’il est installé et mis à jour sur toutes les distributions Linux et MacOS nativement et donc cela rend le code portable et facile à transporter.

Outre Python 3, vous avez besoin du gestionnaire de paquets pip :

apt install python3-pip

Vous avez également besoin de quelques modules supplémentaires, que l’on installe avec pip :

python3 -m pip install --upgrade pip
pip3 install pylast
pip3 install requests

C’est tout ce qu’il vous faut au niveau des dépendances. Plus besoin de PHP ni de ses librairies, plus besoin de stocker le nom des titres dans un fichier texte, tout va se faire en direct depuis le serveur Icecast.

Last.FM Scrobbler for Icecast

Le script Last.FM Scrobbler for Icecast vérifie le statut du server Icecast toutes les 30 secondes. Si le serveur est démarré et que la radio joue, il récupère les informations de la chanson et les soumet à Last.fm, tout en vérifiant bien que la chanson n’est pas la même que la précédente. Cela évite tout doublon, ce qui fausserait les soumissions du compte.

Si le serveur Icecast n’est pas démarré, le script vous avertit et attend 5 minutes.

Si le serveur Icecast est démarré mais que le fichier status-json.xsl ne contient pas les informations nécessaires, le script vous avertit et vous recommande de redémarrer votre webradio car la connexion avec Icecast est perdue.

On crée notre script:

nano /home/scripts/lastfm-scrobbler-icecast.py

Et on y ajoute:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#-----------------------------------------------------------------------
# Script name : Last.FM Scrobbler for Icecast
# Created By  : Matt Biscay
# Created Date: 2023/01/24
# Author URI  : https://www.skyminds.net
# Version     : 1.0.0
# Copyright   : 2023 SkyMinds.Net
# ---------------------------------------------------------------------- 
"""
This script will check the status of the icecast server every 30 sec and if the server is running, it will check for the currently playing track and scrobble it to LastFM if it's different from the last scrobbled track.
If the server is not running, the script will wait for 5 minutes before retrying.
It uses the pylast library to interact with the LastFM API.

@param API_KEY: the LastFM API key
@param API_SECRET: the LastFM API secret
@param username: the LastFM username
@param password: the LastFM password
@param icecast_url: the URL of the icecast server status page
"""

import pylast
import time
import requests
import json
# --------------------------------------------------
# --------- EDIT CONFIGURATION HERE ----------------
# --------------------------------------------------
# Your LastFM API key and secret
API_KEY = "LASTFM_API_KEY"
API_SECRET = "LASTFM_API_SECRET"

# The username and password of the user you want to authenticate 
# and scrobble the track for
username = "LASTFM_USER"
password = "LASTFM_PWD"

# The URL of the Icecast server's status-json.xsl page
icecast_url = "http://icecast.example.com:8000/status-json.xsl"

# ------------------------------------------------
# ---------- END OF CONFIGURATION  ---------------
# ------------------------------------------------

# Create a new LastFM network object
network = pylast.LastFMNetwork(api_key=API_KEY, api_secret=API_SECRET,
                               username=username, password_hash=pylast.md5(password))

# The previously scrobbled track name
previous_track = ""

print("# ------------------------------------------ #")
print("#  Script: Last.FM Scrobbler for Icecast     #")
print("#  Author: Matt Biscay                       #")
print("#  URL   : https://www.skyminds.net          #")
print("# ------------------------------------------ #")
print("")

while True:

    try:
        # Make a GET request to the status-json.xsl page
        response = requests.get(icecast_url)
    except requests.exceptions.ConnectionError as e:
        print("Error: Icecast server is down.")
        # Wait for 5 minutes before retrying
        time.sleep(5*60)
        continue

    if response.status_code != 200:
        print("Error: Icecast server is not running or there is some other error")
        # Wait for 5 minutes before retrying
        time.sleep(5*60)
        continue

    # Parse the JSON response
    data = json.loads(response.text)

    # Get the currently playing track information
    if "icestats" in data and "source" in data["icestats"] and "artist" in data["icestats"]["source"] and "title" in data["icestats"]["source"]:
        artist = data["icestats"]["source"]["artist"]
        track = data["icestats"]["source"]["title"]
        current_track = f'{artist} - {track}'
        if current_track != previous_track:
            # Scrobble the track
            try:
                timestamp = int(time.time())
                network.scrobble(artist=artist, title=track, timestamp=timestamp)
                print(f"Track scrobbled successfully: {current_track}")
                previous_track = current_track
            except pylast.WSError as e:
                print("Error:", e)
        # Wait for 30 seconds before checking for new tracks
        time.sleep(30)
    else:
        print("Error: Icecast XML does not contain the required information. Restart your webradio.")
        # Wait for 1 minutes before retrying
        time.sleep(60)
        continue

Editez les variables dans la partie EDIT YOUR CONFIGURATION: vous avez besoin de votre clé API last.fm ainsi que la clé API secret, de votre nom d’utilisateur et mot de passe last.fm, et enfin l’adresse complète du fichier XML d’Icecast, status-json.xsl.

Lire la suite

linux ubuntu server unattended upgrade

Ubuntu : activer les mises à jour automatiques avec unattended-upgrade

La mise à niveau de votre serveur Ubuntu est une étape importante pour garantir que votre système est toujours à jour et sécurisé. Avec le paquet unattended-upgrade, vous pouvez facilement activer les mises à niveau sans avoir à vous soucier du redémarrage manuel ou des temps d’arrêt.

Comme son nom l’indique, le paquet unattended-upgrade permet de lancer les mises à jour automatiquement à intervalles réguliers, sans action de la part de l’administrateur. Vous pouvez donc planifier les mises à jour lorsque le trafic est faible, et l’outil est même capable de redémarrer le serveur si besoin.

Dans ce tutoriel, nous allons vous montrer comment installer et utiliser unattended-upgrade sous Ubuntu Server 22.04. Nous aborderons également les avantages de l’utilisation de cet outil et la manière dont il peut contribuer à garantir que votre système est toujours à jour.

Cela peut être également un très bon complément si vous avez déjà installé Ubuntu Pro avec le support étendu des mises à jour.

Installer unattended-upgrade

Pour commencer, vous devez d’abord installer unattended-upgrade sur votre serveur Ubuntu – ouvrez une fenêtre de terminal et entrez la commande suivante :

apt install unattended-upgrade

Une fois que unattended-upgrade est installé, on le paramètre:

dpkg-reconfigure -plow unattended-upgrades

Répondez “Yes” pour installer les mises à jour stable automatiquement.

Activez ensuite l’outil:

unattended-upgrade enable

Paramètrage d’unattended-upgrade

Le paquet est bien plus puissant qu’il n’y paraît. Personnellement, j’aime bien être informé des mises à jour et des changements sur le serveur, activons donc les notifications.

On édite notre fichier de configuration local (à créer si besoin). C’est le fichier qui ne sera pas écrasé si le paquet est mis à jour:

nano /etc/apt/apt.conf.d/52unattended-upgrades-local

Et en suivant la documentation, on demande la notification récapitulative des mises à jour, le redémarrage automatique si besoin, vers deux heures du matin pour ne pas gêner nos visiteurs:

// email to send notifications
Unattended-Upgrade::Mail "skyminds@example.com";
// automatic reboot at 2:00 AM
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";	

Lire la suite

ubuntu pro free

Ubuntu Pro : des mises à jour pour 10 ans

Canonical change son offre Ubuntu Pro. Désormais, tout le monde peut profiter gratuitement du support étendu dans la limite de 5 machines.

La distribution Linux Ubuntu est maintenue et développée par l’entreprise Canonical. La distribution en elle-même est disponible gratuitement, mais en parallèle Canonical propose des services payants, notamment Ubuntu Pro, un abonnement qui permet d’avoir une maintenance étendue pour la sécurité et la conformité. En temps normal, Ubuntu Pro est facturé 25 dollars par an et par machine, ainsi que 500 dollars par an et par serveur.

Canonical fait évoluer son offre Ubuntu Pro, ce qui permet aux utilisateurs d’en bénéficier gratuitement dans la limite de 5 machines, que ce soit des ordinateurs ou des serveurs, et que ce soit pour un usage personnel ou commercial.

Ubuntu Pro permet d’avoir des correctifs de sécurité plus rapidement lorsqu’une faille de sécurité est découverte, notamment pour avoir une meilleure protection. Ceci s’applique aux failles critiques, élevées ou moyennes, avec un niveau de réactivité qui peut varier. Des milliers d’applications sont prises en charge dans le cadre du programme Ubuntu Pro : Ansible, Apache Tomcat, Apache Zookeeper, Docker, Drupal, Nagios, Node.js, phpMyAdmin, Puppet, PowerDNS, Python 2, Redis, Rust, WordPress, etc.

Support à long terme de niveau « entreprise »

La proposition s’applique uniquement aux versions avec support à long terme (LTS) du système d’exploitation basé sur le noyau GNU/Linux. Et ce à partir de Ubuntu LTS 16.04.

Il s’agit de versions de niveau « entreprise » de l’OS. Les LTS sont aussi les plus utilisées par l’écosystème et représentent 95% des déploiements, selon Canonical.

Les utilisateurs peuvent obtenir leur abonnement gratuit à Ubuntu Pro sur la page dédiée au programme. Ubuntu One étant le compte unique dont l’utilisateur a besoin pour en bénéficier et se connecter à l’ensemble des services et sites liés à l’OS.

Lorsque l’on connecte les machines à Ubuntu Pro, elles bénéficient donc d’une couverture de maintenance de sécurité étendue, soit 10 ans au total.

Aussi, l’offre gratuite inclut le service Ubuntu Livepatch, celui-ci permet d’installer des mises à jour critiques du noyau sans redémarrer la machine.

Pour les serveurs, lorsque le système hôte physique exécute Ubuntu, l’ensemble des machines virtuelles Ubuntu sur ce serveur sont couvertes. Ubuntu Pro s’étend également à Google Cloud et AWS.

Configurez Ubuntu Pro sur votre serveur

Avec autant d’avantages, il ne nous reste plus qu’à configurer Ubuntu Pro sur le serveur.

Si votre serveur tourne sous Ubuntu Server, le paquet pro est normalement déjà installé. Vous pouvez vérifier cela avec la commande:

pro --version

Résultat de la commande:

27.11.2~22.04.1

La version minimale que vous devez posséder est la 27.11.2.

Lire la suite

PHP8

WordPress : tester la compatibilité avec PHP 8

Aujourd’hui, nous allons tester la compatibilité avec PHP 8 de tous les sites WordPress du serveur, en ligne de commande et de manière automatisée.

Fin du support pour PHP 7.4 pour novembre 2022

Le cycle de vie de PHP 7.4 est atteint et il n’y aura plus de mises à jour ni de support à la fin du mois de novembre 2022. Cela signifie qu’il est désormais temps de passer sous PHP 8 pour bénéficier des dernières améliorations techniques de PHP et des mises à jour de sécurité.

Et mieux vaut s’y prendre un peu plus tôt, notamment si vous possédez une boutique WooCommerce pour ne pas être pris au dépourvu en pleine période de fêtes (Black Friday, Noël…).

Tester votre code avec php-parallel-lint

Nous allons créer un nouveau projet composer avec php-parallel-lint qui se chargera de scanner notre code et de remonter toutes les incompatibilités, fonctions obsolètes ou problématiques susceptibles de donner des avertissements ou des erreurs lors du basculement vers PHP 8.

Commençons par installer php-parallel-lint:

composer create-project php-parallel-lint/php-parallel-lint php-parallel-lint --no-dev

# ou avec un user :
# sudo su -l www-data -s /bin/bash -c "composer create-project php-parallel-lint/php-parallel-lint php-parallel-lint --no-dev"

Résultat de la commande:

Creating a "php-parallel-lint/php-parallel-lint" project at "./php-parallel-lint"
Installing php-parallel-lint/php-parallel-lint (v1.3.2)
  - Installing php-parallel-lint/php-parallel-lint (v1.3.2): Extracting archive
Created project in /Users/matt/Downloads/project-ACTAGIS-php8-202208/php-parallel-lint
Loading composer repositories with package information
Updating dependencies
Lock file operations: 4 installs, 0 updates, 0 removals
  - Locking nette/tester (v2.4.2)
  - Locking php-parallel-lint/php-console-color (v1.0.1)
  - Locking php-parallel-lint/php-console-highlighter (v1.0.0)
  - Locking squizlabs/php_codesniffer (3.7.1)
Writing lock file
Installing dependencies from lock file
Nothing to install, update or remove
2 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files

Installons maintenant l’outil qui permet de coloriser le code dans notre console:

composer require --dev php-parallel-lint/php-console-highlighter

Résultat:

Info from https://repo.packagist.org: #StandWithUkraine
Using version ^1.0 for php-parallel-lint/php-console-highlighter
./composer.json has been created
Running composer update php-parallel-lint/php-console-highlighter
Loading composer repositories with package information
Updating dependencies
Lock file operations: 2 installs, 0 updates, 0 removals
  - Locking php-parallel-lint/php-console-color (v1.0.1)
  - Locking php-parallel-lint/php-console-highlighter (v1.0.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
  - Downloading php-parallel-lint/php-console-color (v1.0.1)
  - Downloading php-parallel-lint/php-console-highlighter (v1.0.0)
  - Installing php-parallel-lint/php-console-color (v1.0.1): Extracting archive
  - Installing php-parallel-lint/php-console-highlighter (v1.0.0): Extracting archive
Generating autoload files

Scanner le code avec php-parallel-lint

Voici la syntaxe pour scanner votre code:

 ./php-parallel-lint/parallel-lint FOLDER_TO_SCAN -p PHP_VERSION

Lire la suite

PHP Composer Banner

PHP : installer Composer sous Ubuntu Server

Voici comment installer Composer, le gestionnaire de paquets PHP qui va grandement vous simplifier la vie en installant toutes les dépendances dont vous avez besoin en une seule commande, sous Ubuntu Server.

Composer est installé sur ma machine mais j’ai besoin en ce moment de vérifier si le code des sites hébergés par le serveur est compatible avec PHP 8. Je peux tout rapatrier sur ma machine et tester tout cela localement mais cela me semble quand même beaucoup plus simple de le faire depuis le serveur, sans transfert de fichiers.

Composer est un outil populaire de gestion des dépendances pour PHP, créé principalement pour faciliter l’installation et les mises à jour des dépendances des projets. Il vérifiera de quels autres paquets un projet spécifique dépend et les installera pour vous en utilisant les versions appropriées selon les exigences du projet. Composer est également couramment utilisé pour lancer de nouveaux projets basés sur des cadres PHP populaires tels que Symfony et Laravel.

Paquets pré-requis

On commence par vérifier que tout est à jour:

apt update && apt upgrade

Ensuite, on vérifie que les paquets pré-requis sont bien installés:

apt install curl unzip php-cli

Installer composer sur le serveur

On télécharge le fichier d’installation, soit avec php, soit avec curl :

# avec php 

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" 

# ou alors avec curl

curl -sS https://getcomposer.org/installer -o composer-setup.php

On installe ensuite composer très simplement avec PHP. On installe :

php composer-setup.php --install-dir=/usr/local/bin --filename=composer

Voici le résultat de la commande:

All settings correct for using Composer
Downloading...

Composer (version 2.4.1) successfully installed to: /usr/local/bin/composer
Use it: php /usr/local/bin/composer

Cela l’installe sous /usr/local/bin/composer de manière globale.

Mettre à jour composer

Pour mettre à jour composer, il suffit d’un simple:

composer update

Et voilà, composerest maintenant installé sur le serveur. Cela nous simplifiera grandement le travail dans quelques jours. Stay tuned!

WordPress Using WP CLI

wp-cli : importer et exporter les utilisateurs WP

Voici une méthode simple pour exporter tous les utilisateurs d’une base de données WordPress, pour les réimporter sur un autre site, à l’aide de l’excellent wp-cli.

Nous ferons référence à la base de données source en tant que source-db et à la base de données cible en tant que target-db et je supposerai que vous avez accès aux deux instances WordPress via wp-cli.

Étape 1 : exporter les utilisateurs WordPress

Cette étape fonctionnera avec la base de données source-db:

wp db export --tables = $(wp db tables 'wp_*_users') users.sql
  • notez l’astérisque dans le nom de la table – utilisez-le pour éviter de taper le nom exact de la table pour votre base de données WordPress spécifique
  • notez le nom du fichier exporté, users.sql – cela permet d’identifier clairement le contenu de ce fichier.

Étape 2 : exporter la méta utilisateur WordPress

Cette étape fonctionnera avec la base source-db. Comme ci-dessus, notez le caractère générique et le nom de fichier:

wp db export --tables = $(wp db tables 'wp_*_usermeta') usermeta.sql

Étape 3 : sauvegarde facultative des utilisateurs et usermeta

Cette étape fonctionnera avec la base target-db. Il s’agit d’une sauvegarde facultative des utilisateurs et des tables usermeta avant d’importer les nouvelles données:

  • répétez l’étape 1 (mais en travaillant avec target-db)
  • nommez le fichier backup-users.sql
  • répétez l’étape 2 (mais en travaillant avec target-db)
  • nommez le fichier backup-usermeta.sql

Cela nous donne donc:

wp db export --tables = $(wp db tables 'wp_*_users') backup-users.sql
wp db export --tables = $(wp db tables 'wp_*_usermeta') backup-usermeta.sql

Lire la suite

linux apt packages

APT : the following packages have been kept back

Après la mise à jour d’Ubuntu Server sur le serveur, j’ai eu cette erreur récurrente après chaque mise à jour apt :

The following packages have been kept back:
  mysql-client mysql-server

Il m’était donc impossible de mettre à jour le serveur et client mysql , ce qui n’est évidemment pas idéal.

Et si l’on essaie de les installer directement avec:

apt install mysql-client mysql-server

On obtient alors ce message:

Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 mysql-common : Conflicts: mysql-client-8.0 but 8.0.29-0ubuntu0.22.04.2 is to be installed
                Conflicts: mysql-client-core-8.0 but 8.0.29-0ubuntu0.22.04.2 is to be installed
 mysql-server : Depends: mysql-server-8.0 but it is not installable
E: Unable to correct problems, you have held broken packages.

Réinstaller mysql-apt-config

On commence donc par réinstaller le package mysql-apt-config :

wget https://dev.mysql.com/get/mysql-apt-config_0.8.22-1_all.deb

Et on installe le paquet:

dpkg -i mysql-apt-config_0.8.22-1_all.deb

On relance donc la mise à jour:

apt update && apt upgrade

Les nouvelles versions des paquets sont désormais installables:

9 packages can be upgraded. Run 'apt list --upgradable' to see them.
W: http://repo.mysql.com/apt/ubuntu/dists/bionic/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
Listing... Done
libmysqlclient21/unknown 8.0.29-1ubuntu18.04 amd64 [upgradable from: 8.0.29-0ubuntu0.22.04.2]
mysql-client/unknown 8.0.29-1ubuntu18.04 amd64 [upgradable from: 8.0.28-1ubuntu18.04]
mysql-common/unknown 8.0.29-1ubuntu18.04 amd64 [upgradable from: 8.0.28-1ubuntu18.04]
mysql-community-client-core/unknown 8.0.29-1ubuntu18.04 amd64 [upgradable from: 8.0.28-1ubuntu18.04]
mysql-community-client-plugins/unknown 8.0.29-1ubuntu18.04 amd64 [upgradable from: 8.0.28-1ubuntu18.04]
mysql-community-client/unknown 8.0.29-1ubuntu18.04 amd64 [upgradable from: 8.0.28-1ubuntu18.04]
mysql-community-server-core/unknown 8.0.29-1ubuntu18.04 amd64 [upgradable from: 8.0.28-1ubuntu18.04]
mysql-community-server/unknown 8.0.29-1ubuntu18.04 amd64 [upgradable from: 8.0.28-1ubuntu18.04]
mysql-server/unknown 8.0.29-1ubuntu18.04 amd64 [upgradable from: 8.0.28-1ubuntu18.04]
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
The following packages were automatically installed and are no longer required:
  linux-headers-5.15.0-25 linux-headers-5.15.0-25-generic linux-image-5.15.0-25-generic linux-modules-5.15.0-25-generic
  linux-modules-extra-5.15.0-25-generic
Use 'apt autoremove' to remove them.
The following packages will be upgraded:
  libmysqlclient21 mysql-client mysql-common mysql-community-client mysql-community-client-core mysql-community-client-plugins
  mysql-community-server mysql-community-server-core mysql-server
9 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

J’ai également écrit un script bash qui automatise tout cela:

Résoudre le message “Key is stored in legacy trusted.gpg keyring”

Dans le message précédent, nous pouvons trouvez ce message d’avertissement:

W: http://repo.mysql.com/apt/ubuntu/dists/bionic/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.

Je l’ai résolu en déplaçant le fichier dans le répertoire trusted.gpg.d :

mv trusted.gpg trusted.gpg.d/

Et voilà, plus d’erreur avec apt et notre système met bien tous ses paquets à jour.

ubuntu 2204 jammy jellyfish

Serveur: migration d’Ubuntu 20.04 à 22.04 LTS

Aujourd’hui, nous mettons le serveur à jour et passons d’Ubuntu Server 20.04 (Focal Fossa) à la version 22.04 LTS (Jammy Jellyfish).

Chaque nouvelle mise à jour d’Ubuntu en version LTS (Long Time Support) permet de bénéficier des mises à jour de sécurité et de maintenance pendant 5 ans, c’est à dire jusqu’en 2027 pour la version Jammy Jellyfish.

Lecture des changements apportés

Je vous conseille fortement de lire le changelog de la version 22.04 pour avoir un aperçu des changements apportés au niveau du kernel, openSSL, certains services.

Sont maintenant disponibles:

  • Apache 2.4.52
  • BIND 9.18
  • Linux kernel v5.15.0-25
  • MySQL 8.0.28
  • NetworkManager 1.36
  • nftables est le backend par défaut pour le parefeu
  • Perl v5.34.0
  • PHP 8.1.2
  • PostgreSQL 14.2
  • Python 3.10.4
  • Ruby 3.0
  • ssh-rsa est maintenant désactivé par défaut dans OpenSSH.

Cela donne aussi une idée des potentielles complications qui pourraient subvenir à la suite de la mise à jour, ainsi que leur remédiation.

Sauvegarde des données du serveur

Je ne vous apprends rien : il va falloir sauvegarder les données importantes du serveur avant de commencer la mise à jour de l’OS.

Pensez-donc au dossier /home et /var/www mais aussi aux fichiers de configuration dans /etc et /root.

Vérification des pré-requis

Vérification de la version actuelle

On vérifie notre noyau actuel:

uname -mrs

> Linux 5.4.0-109-generic x86_64

On vérifie notre version actuelle:

lsb_release -a


No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.4 LTS
Release:	20.04
Codename:	focal

Mise à jour des paquets de la version actuelle

On met à jour la version actuelle avec les derniers paquets et les derniers noyaux:

apt update && apt upgrade

Redémarrage du serveur

On redémarre le serveur pour appliquer les changements et partir sur une base propre:

shutdown -r now

Lire la suite