Serveur dédié : configurer Webmin en TLS avec un certificat SSL photo 1

Solution pour Webmin qui ne veut pas démarrer sous systemd

Je suis tombé sur une drôle d’erreur ce matin sur un VPS de mes clients : après mise à jour du système et redémarrage du serveur, webmin est injoignable et son service ne veut plus démarrer.

Les messages d’erreurs

On commence par lancer un curl distant depuis un autre serveur, histoire de voir si c’est bien injoignable de manière globale, et non propre à notre machine:

curl -I https://example.com:10000/

Résultat:
curl: (7) Failed to connect to example.com port 10000: Connection refusedCode language: JavaScript (javascript)

Pas de doute, cela touche tout le monde. On vérifie donc l’état du service:

systemctl status webmin.serviceCode language: CSS (css)

Résultat:

webmin.service - LSB: web-based administration interface for Unix systems
   Loaded: loaded (/etc/init.d/webmin; generated)
   Active: failed (Result: exit-code) since Sat 2020-09-12 17:35:13 CST; 20s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 1803 ExecStart=/etc/init.d/webmin start (code=exited, status=25)

Sep 12 17:35:13 systemd[1]: Starting LSB: web-based administration interface for Unix systems...
Sep 12 17:35:13 systemd[1]: webmin.service: Control process exited, code=exited status=25
Sep 12 17:35:13 systemd[1]: webmin.service: Failed with result 'exit-code'.
Sep 12 17:35:13 systemd[1]: Failed to start LSB: web-based administration interface for Unix systems.Code language: JavaScript (javascript)

Ce n’est pas très loquace! journalctl est plus détaillé:

journalctl -xe

Résultat :

-- All system services necessary queued for starting at boot have been
-- started. Note that this does not mean that the machine is now idle as services
-- might still be busy with completing start-up.
--
-- Kernel start-up required 1709722 microseconds.
--
-- Initial RAM disk start-up required INITRD_USEC microseconds.
--
-- Userspace start-up required 152146335 microseconds.
Sep 12 17:35:13 systemd[1]: Starting LSB: web-based administration interface for Unix systems...
-- Subject: Unit webmin.service has begun start-up
-- Defined-By: systemd
-- Support: http://www.ubuntu.com/support
--
-- Unit webmin.service has begun starting up.
Sep 12 17:35:13 systemd[1]: webmin.service: Control process exited, code=exited status=25
Sep 12 17:35:13 systemd[1]: webmin.service: Failed with result 'exit-code'.
Sep 12 17:35:13 systemd[1]: Failed to start LSB: web-based administration interface for Unix systems.
-- Subject: Unit webmin.service has failed
-- Defined-By: systemd
-- Support: http://www.ubuntu.com/support
--
-- Unit webmin.service has failed.
--
-- The result is RESULT.Code language: JavaScript (javascript)

Mais nous n’obtenons toujours aucune information exploitable. Redémarrer le service avec service ne permet pas de le redémarrer.

La solution

Le seul moyen de redémarrer le service webmin sur ce VPS a été de la manière suivante:

/etc/init.d/webmin stop
systemctl start webmin

Et là, plus de problème, webmin démarre comme il faut.

Générateur de clés WPA sécurisées photo 1

WiFi : générateur de clés WPA sécurisées

Le principe du chiffrement WPA-PSK

Il y a peu d’intérêt à utiliser les derniers systèmes d’authentification WiFi comme le WPA-PSK si vous utilisez un mot de passe trop facile à deviner et qui pourra être cracké en quelques minutes à peine sans trop d’effort.

Le chiffrement WPA-PSK, censé pallier les failles de son prédécesseur – WEP – est une version moins sécurisée que le WPA puisqu’il n’y a pas de serveur d’identification Radius.

Le protocole repose sur une clé partagée (Pre-Shared Key ou PSK) qui initialise le processus d’authentification.

Votre clé partagée est créée à l’aide d’un mot de passe de votre choix. Il est souhaitable et recommandé que le mot de passe ne contienne aucun mot figurant dans le dictionnaire, même sous une forme leet speak, les logiciels de crack type brute-force ou dictionnaire connaissent cette astuce depuis quelques années déjà.

La combinaison doit donc être illisible, le genre de clé qui est impossible à donner à un correspondant par téléphone.

Autrement dit, si votre mot de passe est un mot courant qui fait partie d’un dictionnaire, il pourra être cracké à l’aide d’une attaque type brute-force ou dictionnaire en moins d’une minute.

Ensuite, il faut augmenter le nombre de caractères de la clé partagée : il est plus facile de trouver un mot de passe de 4 caractères plutôt que de 63 caractères.

D’où l’intérêt d’utiliser un mot de passe de taille conséquente, composé de signes et caractères spéciaux. Cracker une clé de 63 caractères prend quelques années avec la puissance de calcul actuelle.

Générateur de clés WPA sécurisées

J’ai à cet effet créé un générateur de clés WPA sécurisées : il vous suffit de choisir le type de clé qui convient le mieux à votre usage.

Je vous recommande bien évidemment la clé de 63 caractères mais vous avez aussi la possibilité de choisir le nombre de caractères qui vous plait.

Lire la suite

Ajouter un lien avec le nombre d'articles et le total du panier WooCommerce photo

Ajouter un lien avec le nombre d’articles et le total du panier WooCommerce

Rares sont désormais les thèmes WordPress qui n’offrent pas le support de WooCommerce tant l’extension qui propulse aujourd’hui des millions de boutiques en ligne est populaire.

Toutefois, le code de WooCommerce évolue en permanence et certaines fonctions changent de nom ou sont appelées différemment.

Un thème compatible avec WooCommerce 2.6 ne l’était plus avec WooCommerce 3.3 par exemple, lorsque toutes les fonctions relatives au panier sont passées à des fonctions objets.

Montrer le nombre d’articles dans le panier dans le thème

Un client Codeable m’a récemment demandé de mettre à jour son thème, qui n’est plus supporté par son auteur, pour afficher le nombre d’articles dans le panier.

Voici le code à insérer, soit dans un des fichiers de votre thème (header.php est le plus indiqué dans notre cas) ou alors dans un widget HTML:

<a class="cart-custom" href="<?php echo wc_get_cart_url(); ?>" title="<?php _e( 'View your shopping cart' ); ?>"><?php echo sprintf ( _n( '%d item', '%d items', WC()->cart->get_cart_contents_count() ), WC()->cart->get_cart_contents_count() ); ?> - <?php echo WC()->cart->get_cart_total(); ?></a>Code language: HTML, XML (xml)

Lire la suite

Dovecot : solution pour les erreurs SASL, stats-writer, SSL et Diffie-Hellman photo

Dovecot : solution pour les erreurs SASL, stats-writer, SSL et Diffie-Hellman

La dernière version du serveur mail Dovecot nécessite quelques petits changements par rapport à la version antérieure.

Erreurs SASL

Voici ce que l’on peut lire dans les logs:

postfix/smtps/smtpd: warning: SASL: Connect to private/auth failed: Connection refused
postfix/smtps/smtpd: fatal: no SASL authentication mechanisms
postfix/master: warning: process /usr/lib/postfix/sbin/smtpd pid 635413 exit status 1
postfix/master: warning: /usr/lib/postfix/sbin/smtpd: bad command startup -- throttlingCode language: HTTP (http)

Solution: il faut éditer /etc/dovecot/conf.d/10-master.conf:

nano /etc/dovecot/conf.d/10-master.conf

et ajouter ce bloc de directives à la fin du bloc service auth:

service auth {
  # ... Previous config blocks
 
  # auth-master
  unix_listener auth-master {
    mode = 0660
    user = vmail
    group = vmail
  }

}Code language: PHP (php)

Stats writer

Dovecot inclut maintenant un module de statistiques et donne une erreur si jamais il n’est pas défini dans la configuration. Voici le message d’erreur:

Error: net_connect_unix(/var/run/dovecot/stats-writer) failed: Permission denied))Code language: JavaScript (javascript)

Il faut donc le rajouter:

nano /etc/dovecot/conf.d/10-master.conf

et ajouter ce bloc à la toute fin du fichier:

# fix Error: net_connect_unix(/var/run/dovecot/stats-writer) failed: Permission denied))
service stats {
    unix_listener stats-reader {
        user = vmail
        group = vmail
        mode = 0660
    }

    unix_listener stats-writer {
        user = vmail
        group = vmail
        mode = 0660
    }
}Code language: PHP (php)

Lire la suite

Créer un fichier sitemap à partir d'une liste d'articles pour le soumettre sur Google Search Console photo 4

Créer un fichier sitemap à partir d’une liste d’articles pour le soumettre sur Google Search Console

Ces derniers jours, en me rendant dans la Google Search Console, je me suis rendu compte que j’avais quelques milliers d’articles qui étaient indexés par Google mais sans être présents dans aucune sitemap.

Il s’agit en fait des articles de tablatures de guitare: au lieu de publier un article pour chaque tablatures, le site crée à la volée un article WordPress qui contient la tablature en question. C’est très efficace mais cela ne permet évidemment pas de les ajouter au fichier sitemap par défaut.

Si vous avez ce genre de configuration – ou si vous avez d’autres liens à soumettre à Google, voici ce que j’ai utilisé cette semaine.

État des lieux

On commence par se connecter à la Search Console pour se rendre dans Coverage > Valid > Indexed, not submitted in sitemap.

Voici un petit graphique qui montre les 1658 pages au 26 juillet et après soumission de la première sitemap – 1000 liens, car cela semble être la limite de l’export de la Search console, un premier résultat positif:

google search console coverage indexed not submitted in sitemap 1280x746

Export de la liste des articles

Tout en haut de la page, cliquez sur le bouton Export et sélectionnez Download CSV:

google search console coverage indexed not submitted in sitemap export 1280x447

Cela lance le téléchargement d’un fichier zip. Décompressez l’archive et ouvrez le fichier Table.csv dans votre tableur préféré.

Lire la suite

MacOS : changer les serveurs DNS pour éviter les DNS menteurs de votre box photo 1

MacOS : changer les serveurs DNS pour éviter les DNS menteurs de votre box

Il m’arrive très souvent d’utiliser une connexion Orange (depuis une Livebox 4) lorsque je suis chez mes parents.

Le problème est que la Livebox possède ses propres serveurs DNS intégrés et qu’ils sont menteurs, c’est-à-dire qu’ils obéissent à des règles de filtrage et de blocage décidés par l’opérateur (ou par des décisions de justice qui concernent tous les opérateurs).

Dans le cas d’Orange, les requêtes sont automatiquement redirigées vers votre machine locale, sur localhost. Comme j’utilise mon serveur Local tourne en quasi-permanence sur ma machine, cela me donne une belle erreur 502, comme vous pouvez le voir sur cette image:

MacOS : changer les serveurs DNS pour éviter les DNS menteurs de votre box photo
Lorsque votre les DNS intégrés à votre box vous mentent, il est temps de changer!

Nous avions déjà abordé le changement des serveurs DNS de notre Freebox mais il est un peu plus délicat de demander à vos hôtes de pouvoir changer les réglages de leur box…

Il y a une solution bien plus simple que de trifouiller au fond des entrailles du routeur fruitier : il suffit d’ajouter de nouveaux serveurs de noms sur votre machine, directement dans les options de votre connexion réseau.

Modification des serveurs de noms sous MacOS

Sous MacOS, il suffit de se rendre dans Préférences Systèmes > Réseau > Avancé :

macos reseau wifi 1280x925

Lire la suite

An Hour with Pink Floyd: KQED photo

An Hour with Pink Floyd: KQED

‘An Hour with Pink Floyd: KQED’ sees the band filmed performing live in April 1970 by San Francisco cable TV station KQED:

Taken from the version featured on 2016 ‘The Early Years 1965-1972’ box set, the film includes performances of Atom Heart Mother, Cymbaline, Grantchester Meadows, Green is the Colour and Careful with that Axe Eugene.

Appearing as part of the @YouTube Film Festival until May 17th.

Auto Draft photo 1

Mise à jour du serveur vers Ubuntu Focal Fossa (20.04 LTS)

Ce soir, on lance la mise à jour du serveur: nous passons notre version d’Ubuntu Server de Bionic Beaver (18.04 LTS) à Focal Fossa (20.04 LTS).

On commence par les précautions d’usage: faire ses sauvegardes et vérifier qu’elles sont bien intègres avant de commencer la mise à jour. C’est votre bouée en cas de soucis!

Étape 1: avoir l’installation d’Ubuntu actuelle à jour

Assurez-vous d’avoir une installation à jour avant de commencer:

apt update && apt dist-upgrade

On reboot ensuite pour appliquer les changements:

shutdown -r now

Étape 2: installation de screen et ouverture du port 1022 pour SSH

Comme nous allons lancer la mise à jour via un terminal SSH, il est possible que pour une raison ou un autre la connexion soit coupée. Cela arrive et cela peut être vraiment tendu à certaines étapes de la mise à jour (kernel anyone?).

Pour prévenir cela, on vérifie que screen est bien installé:

apt install screen

On peut lancer une session screen avec:

screen

et si la connexion SSH est interrompue lors de la mise à jour, on peut se raccrocher à la session de mise à jour avec la commande:

screen -Dr

Ensuite, au niveau du pare-feu, on ouvre le port 1022. C’est via ce port que l’on pourra reprendre la MAJ en cas de pépin. Suivant la configuration du serveur, on peut utiliser iptables:

iptables -I INPUT -p tcp --dport 1022 -j ACCEPT

ou alors ufw:

ufw allow 1022

Lire la suite

Solution pour l'erreur cURL error 7: Failed to connect to XXX port 443: Connection refused photo 1

Solution pour l’erreur cURL error 7: Failed to connect to XXX port 443: Connection refused

Sur un serveur hébergé en Chine continentale, j’ai eu la surprise de ne pas être en mesure de mettre à jour wp-cli:

wp cli update

Error: Failed to get url 'https://api.github.com/repos/wp-cli/wp-cli/releases?per_page=100': cURL error 7: Failed to connect to api.github.com port 443: Connection refused.Code language: JavaScript (javascript)

Visiblement, certaines adresses sont injoignables, notamment lorsqu’elles utilisent le port 443 (https).

Evidemment, on peut télécharger wp-cli manuellement et le réinstaller mais si vous souhaitez une solution plus rapide, voilà comment j’ai procédé.

Première solution: édition de /etc/hosts

1. On récupère l’adresse IP de l’adresse api.github.com:

curl --ipv4 -v https://api.github.com

Résultat: 13.250.94.254 port 443Code language: JavaScript (javascript)

2. On édite le fichier /etc/hosts du serveur:

nano /etc/hosts

3. On y ajoute l’adresse IP correspondante à api.github.com:

13.250.94.254 api.github.comCode language: CSS (css)

Et voilà, le téléchargement depuis github est de nouveau accessible.

Lire la suite

PHP: résoudre l'erreur "file_get_contents(): SSL operation failed with code 1" photo

PHP: résoudre l’erreur “file_get_contents(): SSL operation failed with code 1”

J’ai récemment joué avec l’API de YouTube pour pouvoir récupérer diverses informations sur les vidéos afin d’ajouter au site les données structurées idoines.

Il se trouve qu’en local, lorsque l’on utilise file_get_contents(), on peut obtenir une erreur de ce type lorsque le serveur n’est pas configuré avec le bundle de certificats OpenSSL:

Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in ...php on line 2

Warning: file_get_contents(): Failed to enable crypto in ...php on line 2

Warning: file_get_contents(https://........f=json): failed to open stream: operation failed in ...php on line 2
Code language: JavaScript (javascript)

Si cela vous arrive, plusieurs solutions s’offrent à vous.

Méthode 1: configuration de PHP côté machine/serveur

1. Vérifiez qu’OpenSSL est bien installé sur votre machine (il devrait l’être sur le serveur!).

2. Ajoutez cette ligne à la configuration de PHP, dans votre php.ini:

openssl.cafile=/usr/local/etc/openssl/cert.pemCode language: JavaScript (javascript)

3. Redémarrez le service PHP.

Méthode 2 : une fonction qui utilise curl au lieu de file_get_contents()

Au lieu de m’embêter à configurer OpenSSL ou à toucher à PHP dans un conteneur docker (Local), il se trouve que l’on peut réécrire la fonction file_get_contents() avec une fonction maison qui utilise curl.

Voici la fonction en question:

/*
Custom CURL function that mimicks file_get_contents()
@returns false if no content is fetched
Matt Biscay (https://mattbiscay.com)
*/
function sky_curl_get_file_contents( $URL ){
	$c = curl_init();
	curl_setopt( $c, CURLOPT_RETURNTRANSFER, 1 );
	curl_setopt( $c, CURLOPT_URL, $URL );
	$contents = curl_exec( $c );
	curl_close( $c );
	if( $contents ) :
		return $contents;
	else:
		return false;
	endif;
}Code language: PHP (php)

La fonction retourne false si la requête échoue, ce qui est très utile pour éviter de faire des appels à des valeurs d’un tableau qui n’existe pas.

On peut alors réfléchir à un autre moyen de peupler les champs de données structurées (mais c’est un sujet à aborder une autre fois).

Redémarrer la machine virtuelle de Local by Flywheel photo

Local : résoudre les problèmes d’importation de la base de données

Aujourd’hui, on importe la base de données d’un site existant dans la nouvelle version de Local Lightning, estampillée 5.4.1.

D’habitude, je lance Adminer > Import, je sélectionne mon fichier de base de données et boom, la base est importée. Mais aujourd’hui, rien ne se passe comme prévu: Adminer mouline, mouline, perd la moitié du design de sa page et n’importe pas la base.

SSH à la rescousse

Je me dis qu’on aura peut-être plus de chance depuis la console SSH. Dans Local, faites un clic droit sur le site > Open Site Shell. Une fenêtre de terminal apparaît alors.

Utilisation de WP-CLI

On commence d’abord par la méthode wp-cli. On copie notre fichier adminer.sql sous /app/public et on lance la commande suivante:

wp db import ./adminer.sqlCode language: JavaScript (javascript)

Résultat:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)Code language: JavaScript (javascript)

Cela commence bien. La version 5 de Local utilise MySQL 8 donc certaines choses ne sont peut-être pas tout à fait au point. Comme il n’y a pas de socket mysql dans /tmp/mysql.sock, nous allons manuellement spécifier notre socket MySQL dans notre commande. Local nous donne l’adresse du socket dans l’onglet Database:

wp db import ./adminer.sql --socket="/Users/matt/Library/Application Support/Local/run/rvrb6Ce-Z/mysql/mysqld.sock"

Résultat:
ERROR 1067 (42000) at line 23841 in file: './adminer.sql': Invalid default value for 'comment_date'
Code language: JavaScript (javascript)

La bonne nouvelle, c’est que l’on peut se connecter à la base de données MySQL. Mais tiens donc, nous sommes déjà tombés sur cette erreur Invalid default value for comment_date !

Configuration de MySQL

Pour régler le problème sous Local, la marche à suivre diffère un peu de ce que nous avions lancé sur notre serveur puisqu’il n’y a pas une mais deux variables de configuration de mysqld à modifier.

On se connecte au serveur mysql:

mysql -u root -proot

Commençons par voir ce que les variables sql_mode contiennent:

SELECT @@GLOBAL.sql_mode; SELECT @@SESSION.sql_mode; Code language: CSS (css)

Résultat:

+------------------------------------------------------------------------------------------+
| @@GLOBAL.sql_mode                                                                        |
+------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------+
1 row in set (0,00 sec)

+------------------------------------------------------------------------------------------+
| @@SESSION.sql_mode                                                                       |
+------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------+Code language: JavaScript (javascript)

Le problème est, comme la dernière fois, la présence de ces deux instructions: NO_ZERO_IN_DATE,NO_ZERO_DATE.

On enlève donc ces deux instructions de nos deux directives:

SET @@GLOBAL.sql_mode="ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION";
SET @@SESSION.sql_mode="ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION";Code language: CSS (css)

Voilà ce que nous obtenons au final:

+------------------------------------------------------------------------------------------+
| @@GLOBAL.sql_mode                                                                        |
+------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------+
1 row in set (0,00 sec)

+------------------------------------------------------------------------------------------+
| @@SESSION.sql_mode                                                                       |
+------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+------------------------------------------------------------------------------------------+
1 row in set (0,00 sec)Code language: JavaScript (javascript)

On peut désormais importer notre fichier SQL:

mysql -u root -proot local < ./adminer.sql 

Hop l’import de la base de données se passe maintenant sans aucun problème.