SheevaPlug

IWLA 0.5

Thursday, 16 April 2020
|
Écrit par
Grégory Soutadé

Capture d'écran IWLA

3 ans se sont écoulés depuis la dernière version d'IWLA. C'est avant tout une histoire de flemme avec des commits restés trop longtemps en test (notamment la série d'août 2019), mais cela prouve aussi que le logiciel est relativement stable et répond au besoin. Cette nouvelle mouture apporte :

  • L'ajout d'un mode test (dry run)
  • De nouvelles règles pour la détection des robots (plus de 10 erreurs 404, affichage d'une page sans élément (hit), pas de page et pas de hit)
  • Un nouveau format de base de données qui réduit considérablement la taille à stocker : les statistiques de pages (vues et non vues), de hits (vus et non vus) ainsi que la bande passante sont désormais cumulés et non plus stockés jour par jour. Cette modification entraîne une incompatibilité avec les versions précédentes
  • La mise à jour des données depuis la branche de développement d'AWSTATS
  • Plugin top_pages_diff
  • La possibilité d'exclure une IP des statistiques
  • L'utilisation de cPickle à la place de Pickle
  • Les requêtes des robots ne sont plus sauvegardées (gain de place)
  • Quelques corrections de bug

Comme mentionnées, les modifications visent avant tout à réduire l'empreinte mémoire et disque du logiciel, ce dernier devant tourner sur un serveur avec seulement 1GB de RAM.

À vos téléchargements !

Upgrade Cubox-i Linux kernel

Saturday, 05 October 2019
|
Écrit par
Grégory Soutadé

In the beginning of October, Debian pushed a security update for libssl. After installing it, all new SSH connections fails with message (even with correct password, or root login) :

fatal: privsep_preauth: preauth child terminated by signal 31

After searching on Internet, I found that nor SSH, nor libssl were in cause. It was due to an old kernel. I was running Linux 3.14 kernel because http://repo.r00t.website is not maintained.

Fortunately, Solid Run still maintains Linux kernel source tree on Github. Next instructions are based on this page.

First, mount Cubox-i filesystem from SDcard (assume it's in /mnt/cubox).

At startup, uBoot is configured to load zImage and dtb/$dtb_file. zImage is a symbolic link allowing us to have multiple kernel in /boot, let's do the same for dtb directory :

cd /mnt/cubox
cd boot
sudo mv dtb/ 3.4.14
sudo mkdir dtbs
sudo mv 3.4.14 dtbs
sudo ln -s dtbs/3.4.14/ dtb

Next, kernel compilation. The linked page suggest to do a git clone which is very big (~3GB), I suggest to download a snapshot from Github. Now, we'll follows Solid Run instructions :

sudo apt install crossbuild-essential-armhf
cd linux_sources
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
make imx_v7_cbi_hb_defconfig
make -j4 zImage dtbs modules

Then, install compiled files :

export INSTALL_PATH=$PWD/linux_install
export INSTALL_MOD_PATH=$PWD/modules_install
mkdir linux_install
make install modules_install dtbs_install
cp arch/arm/boot/zImage linux_install/vmlinuz-4.9.124
sudo cp -r linux_install/* /mnt/cubox/boot/
sudo cp -r modules_install/lib/modules/4.9.124/ /mnt/cubox/lib/modules/

Linux creates an image compressed with lzop which not seems to be supported by my version of uBoot, so we need to manually copy created zImage.

Modules installation can be done in one line :

sudo make modules_install INSTALL_MOD_PATH=/mnt/cubox/

Optionally, you can export headers :

sudo make headers_install INSTALL_HDR_PATH=/mnt/cubox/usr/local/include

Switch kernel

cd /mnt/cubox
sudo rm dtb
sudo ln -s dtbs/4.9.124/ dtb
sudo rm zImage
sudo ln -s vmlinuz-4.9.124 zImage
sync

Unmount and unplug SDcard. Power up. It should now run new Linux kernel !

Solid Run also have a repository for a Debian package for kernel, but for now I didn't saw any binary repository available on Internet.

Warning, Github kernel make my server crash a lot of time due to an error in ext4/fs driver. I compiled a vanilla kernel, from linux-4.19.y branch (same as Debian stable one). Use the same instructions for compilation (just add dtbs_install to make install command). My .config is available here. I didn't test HDMI, Bluetooth nor IR (red LED is off). Last thing : root partition is now on /dev/mmcblk1p1, don't forget to update kernel command line !

Enabling serial console

The serial console seems to not work anymore. To enable it, first edit /etc/inittab and add at then end :

1:2345:respawn:/sbin/getty -L ttymxc0 115200 vt100

Then, we need to enable getty with SystemD to have login prompt at startup :

sudo systemctl enable "getty@ttymxc0"

Finally, we need to update kernel command line. Edit /boot/boot.cmd and put :

consoleconsole=ttymxc0,115200n8

Build boot.scr from boot.cmd, documentation here:

mkimage -C none -A arm -T script -d boot.cmd boot.scr
sync

Neuf ans

Sunday, 04 August 2019
|
Écrit par
Grégory Soutadé

Gâteau anniversaire 9 ans

Neuf ans. Voilà un chiffre qui commence à faire mal sur le coin de la tête ! Comme tout événement ou jalon qui ponctue notre vie et nous fait réaliser des rétrospectives, on se dit qu'il y a 9 ans, après l'achat et la configuration du SheevaPlug et bien ... j'avais neuf ans de moins !

Sans refaire tout l'historique, qui sera sûrement abordé l'année prochaine, revenons sur les événements marquants de cette année. Quelque chose qui était attendu depuis longtemps : l'arrivée d'une connexion fibre. Certes, pour l'usage personnel, l'ancienne connexion ADSL avec ses 13Mb/s descendants était suffisante pour assurer une navigation fluide, mais concernant le débit montant (donc les connexions des utilisateurs externes) ça ramait dès qu'il y avait quelques photos. Voilà un problème de résolu. Pour autant, je ne vais pas abandonner mon architecture actuelle de pages statiques pré compressées, ni mettre des tas de scripts inutiles et consommateurs de ressources aussi bien côté client que côté serveur. Vive l'internet libre, léger et sans pub ! Néanmoins, et c'est une grosse déception sur ce point, il n'y a toujours pas d'IPv6.

Buster, la version 10 de Debian, est sortie début juillet. La mise à jour du serveur était donc au menu. Elle s'est parfaitement déroulée avec très peu de problèmes concernant les fichiers de configuration et sans coupure majeure. Ce fut l'occasion de se rendre compte que Bouygues Telecom avait mis à jour sa box en ajoutant une règle qui bloque le port entrant 25... Ce qui signifie que les mails en @soutade.fr ne fonctionnaient plus depuis environ 8 mois.

Les statistiques pour cette année (entre parenthèses, les années précédentes) :

  • 19 articles publiés (22, 30, 31, 34, 49, 50, 60, 60)
  • 9 270 visites (9 580, 9 510, 23 800, 21 300, 25 000, 12 000, 18 000, 9 000)
  • 15.3 Go de données envoyées (12.5, 17, 17,9, 9, 5.5, 2.7, 2.5)
  • 22 230 pages affichées (19 887, 20 180, 26 700)

Le fameux top 10 qui cumule 41% des pages affichées (en gras, consultation principalement pour les images. Entre parenthèses, l'année de publication) :

Certes, les chiffres sont encore en baisses par rapport aux années précédentes. Je ne compte pas pour autant fermer les services. D'autant plus que certains sujets sont encore très actifs ! On continue donc avec la philosophie Debian : une nouvelle sortie quand c'est prêt ! Normalement, une nouvelle version de gPass devrait sortir courant de cette année. Il faut dire que ce projet rencontre un certain succès avec quelques 175 utilisateurs actifs ce jour. Il y a même eu un pic à 275 en début d'année. La concurrence est pourtant féroce, avec en prime deux logiciels de gestion de mots de passes homonymes (un pour Gnome et un pour Google).

Let's encrypt certificate renewal with Gandi LiveDNS API

Tuesday, 02 April 2019
|
Écrit par
Grégory Soutadé

It's now one year I use Let's Encrypt TLS wildcard certificates. Until now, all was fine, but since the beginning of 2019, there is two domains on my certificate : soutade.fr and *.soutade.fr and (maybe due to my certificate generation) I need to perform two challenges for renewal : HTTP (http01) and DNS (dns01).

So, I wrote a Python script that performs both :

#!/usr/bin/env python3
#-*- encoding: utf-8 -*-

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

#
# Handle certificate renewal using HTTP and DNS challenges
# DNS challenge performed by Gandi Live v5 API
#

import requests
import os
import argparse
import shutil

# Config
API_KEY = "YOUR-KEY"
LIVEDNS_API = "https://dns.api.gandi.net/api/v5/"
ACME_RECORD = '_acme-challenge'
ACME_CHALLENGE_PATH = '/var/www/.well-known/acme-challenge'

headers = {
    'X-Api-Key': API_KEY,
}

CERTBOT_TOKEN = os.environ.get('CERTBOT_TOKEN', None)
CERTBOT_VALIDATION = os.environ.get('CERTBOT_VALIDATION', None)
DOMAIN = os.environ.get('CERTBOT_DOMAIN', None)

optparser = argparse.ArgumentParser(description='Letsencrypt challenge for Gandi v5 API')
optparser.add_argument('-c', '--cleanup', dest='cleanup',
                       action="store_true", default=False,
                       help='Cleanup chanllenge')

options = optparser.parse_args()     

if options.cleanup:
    print('Cleanup')
    if os.path.exists(ACME_CHALLENGE_PATH):
        shutil.rmtree(ACME_CHALLENGE_PATH)
else:
    if CERTBOT_TOKEN and CERTBOT_VALIDATION:
        print('Build HTTP authentication')
        # Create token file for web server
        if not os.path.exists(ACME_CHALLENGE_PATH):
            os.makedirs(ACME_CHALLENGE_PATH)
        token_path = os.path.join(ACME_CHALLENGE_PATH, CERTBOT_TOKEN)

        with open(token_path, 'w') as token:
            token.write(CERTBOT_VALIDATION)
        exit(0)

response = requests.get(LIVEDNS_API + "zones", headers=headers)

target_zone = None
if (response.ok):
    zones = response.json()
    for zone in zones:
        if zone['name'] == DOMAIN:
            target_zone = zone
            break
else:
    response.raise_for_status()
    exit(1)

if not target_zone:
    print('Any zone found for domain %s' % (DOMAIN))
    exit(1)

domain_records_href = target_zone['zone_records_href']

# Get TXT record
response = requests.get(domain_records_href + "/" + ACME_RECORD, headers=headers)

# Delete record if it exists
if (response.ok):
    requests.delete(domain_records_href + "/" + ACME_RECORD, headers=headers)

if options.cleanup:
    exit(0)

print('Build DNS authentication')
record = {
    "rrset_name": ACME_RECORD,
    "rrset_type": "TXT",
    "rrset_ttl": 300,
    "rrset_values": [CERTBOT_VALIDATION],
    }

response = requests.post(domain_records_href,
                         headers=headers, json=record)

if (response.ok):
    print("DNS token created")
else:
    print("Something went wrong")
    response.raise_for_status()
    exit(1)

A downloadable version is available here

Crontab

In /etc/crontab :

0  1   1 * *   root   certbot renew  --manual -n --manual-public-ip-logging-ok --manual-auth-hook /root/gandi_letsencrypt.py --manual-cleanup-hook /root/letsencrypt_token_cleanup.sh

Aditionnals Scripts

Where /root/letsencrypt_token_cleanup.sh is

#!/bin/bash

/root/gandi_letsencrypt.py --cleanup

And in /etc/letsencrypt/renewal-hooks/post/ :

#!/bin/bash

service nginx restart

Errors

If you get a 404 error with nginx, you may add this line to ensure it will not delegate treatment in other part (or send it to another webserver) :

        location /.well-known/acme-challenge/ {
        }

Huit ans

Saturday, 04 August 2018
|
Écrit par
Grégory Soutadé

Gâteau 8 ans

Une bougie de plus pour le blog ! L'occasion de faire un nouveau bilan. Comme chaque année, le temps passe vite et le temps libre devient une ressource rare, dispersée entre le travail professionnel et les multiples activités. Du coup, ce sont les projets informatiques qui prennent du retard. J'ai particulièrement en tête la sortie de Pannous qui a pas mal traînée.

Contrairement à ce que j'avais pré annoncé l'année passée, il n'y a toujours pas de support IPv6, mais ça devrait être réglé d'ici la fin de l'année ! Si on regarde les statistiques, elles sont plutôt stables, avec un pic de connexions en janvier grâce mon vieil article fétiche : 1 message service reçu. La bande passante a bien diminuée car moins de photos en première page. Certes, il y a un petit peu moins d'articles publiés, mais certains sont vraiment conséquents et, même s'ils n'apparaissent pas dans le top 10, j'en suis assez fier. En parlant de chiffres et de fierté, à l'occasion du correctif 0.8.2 de gPass, j'ai jeté un oeil (par hasard) sur les statistiques d'utilisation de l'addon Chrome. Et quelle ne fût pas ma surprise de voir une moyenne de 168 utilisateurs quotidiens + une douzaine sur Firefox ! C'est un chiffre impressionant pour un projet sans pub (mis à part sur le blog), auto hébergé, sans instance centrale et à l'esthétique un peu vieillot (c'est à ça que l'on reconnaît la sécurité).

Les statistiques pour cette année (entre parenthèses, les années précédentes) :

  • 22 articles publiés (30, 31, 34, 49, 50, 60, 60)
  • 9 580 visites (9 510, 23 800, 21 300, 25 000, 12 000, 18 000, 9 000)
  • 12.5 Go de données envoyées (17, 17,9, 9, 5.5, 2.7, 2.5)
  • 19 887 pages affichées (20 180, 26 700)

Le fameux top 10 qui cumule pour cette année 38% des visites (en gras, consultation principalement pour les images. Entre parenthèses, l'année de publication) :

On notera deux entrées : l'astuce pour windows et la revue du Canon EOS M10 de janvier 2017 !

Quid de l'avenir ? Pas d'annonce cette année, ni de projet particulier à mener. Je pense avoir atteint un rythme de croisière et j'espère faire aussi bien (voir mieux) l'année prochaine !