Migrate docudjeex to Docus v4 with EN/FR content

This commit is contained in:
Djeex
2026-08-30 16:41:37 +02:00
commit c51fcd5df6
241 changed files with 41143 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
title: Mes bêtises
icon: i-noto-test-tube
@@ -0,0 +1,2 @@
title: Python
icon: i-lucide-file-code-2
@@ -0,0 +1,39 @@
---
title: Nvidia Stock Bot
description: Un bot Python qui surveille la disponibilité des GPU en temps réel et envoie des alertes Discord — créé lors de la pénurie de la série RTX 5000.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
# Scripts python
Mes cochonneries en python
## 🤖 Nvidia Stock Bot
---
Depuis déjà 4 ans, la pénurie de materiel electronique fait rage. Et les cartes graphiques ne sont pas épargnées. En 2020, j'ai du attendre 2 mois pour obtenir mon exemplaire de RTX 3080, et pour cela j'ai du m'inscrire sur [JV Hardware](https://discord.gg/gxffg3GA96) où une poignée de geek avait mis en place un bot qui envoyait un ping lorsqu'elles étaient disponibles.
4 ans après et 5000 abonnés plus tard, vient la sortie des RTX 5000. Et là aucun bot dispo sur le marché ne semble fonctionner correctement. Je ne parle même pas d'un certain "influenceur" qui se permet de faire payer l'accès à son bot qui ne fonctionne meme pas. Il copie à la main les alertes provenant d'autres serveurs, comme le notre qui ont résolu le problème.
Quoiqu'il en soit, désireux d'obtenir une RTX 5090 pour ma machine dédiée à l'IA, je me suis dit qu'il était peut etre le temps de plonger dans le monde de python et de ChatGPT pour m'épauler. A l'aide d'un autre membre du serveur, KevOut, qui a principalement guidé sur le principe de départ et les sources des différentes API, j'ai réussi à obtenir un bot propre, fonctionnel, qui envoie différents types d'alertes via Discord. Avec un simple conteneur docker à déployer.
Après moult déconvenues, je suis passé de ceci :
![Nvidia Stock Bot Old](/img/nonsense/nvidia-stock-bot-old.svg)
à cela :
![Nvidia Stock bot](/img/nonsense/nvidia-stock-bot.svg)
Et plus récemment :
![Nvidia Stock bot](/img/nonsense/nvidia-stock-bot-en-v4.svg)
J'ai également eu la chance d'être référencé dans la fameuse [newsletter selfhost](https://selfh.st/weekly/2025-07-11/) !
Plus d'infos directement sur le repo :
::card{title="🐋 __Nvidia Stock Bot__"}
[Robot d'alerte de stock de GPU Nvidia](https://git.djeex.fr/Djeex/nvidia-stock-bot)
::
@@ -0,0 +1,35 @@
---
title: Adguard CIDRE
description: Un script Python pour synchroniser automatiquement les listes CIDR d'AdGuard Home et sécuriser votre serveur DNS auto-hébergé exposé sur internet.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
# 🤖 Adguard CIDRE Sync
---
Adguard Home est une solution merveilleuse pour filter ses requêtes DNS et ainsi se débarasser de la publicité ou des DNS des fournisseurs d'accès, ou encore réécrire des requetes.
Quand c'est en local, c'est très chouette. Mais quand on veut que tout ses appareils en profitent même à l'exterieur, on est obligé de l'exposer sur le net. Et n'importe qui peut s'en servir et saturer le petit remote à 1€ qu'on a pris pour l'heberger.
Adguard permet d'avoir des listes de clients autorisés ou bloqués. Problème, pour autoriser un client il faut son IP, et dans le cas d'un téléphone sur le réseau mobile, beh elle change régulièrement. L'idée est donc plutot de bloquer des listes générales plutot que d'autoriser des IP qui de toute façon changent régulièrement.
CIDRE est un outil qui permet de synchroniser des listes de plages IP géolocalisées mises à jour régulièrement avec un pare feu. Plutot que de faire tourner CIDRE sur le remote complet avec des règles de pare feu complexes, je me suis dit qu'il fallait simplement s'arranger pour ajouter les plages IP à jour que CIDRE propose au systeme de block list d'adguard, selon les pays que l'on souhaite bloquer.
C'est ainsi qu'est né Adguard CIDRE Sync, un conteneur qui synchronise régulièrement la block list d'Adguard avec les plages IP recensées par CIDRE à la fréquence que vous voulez.
L'idée etant de :
- Backup le fichier de conf d'Adguard au premier lancement (le fichier jamais touché par le robot est ainsi conservé au cas où)
- Télécharger la liste des pays selectionnés via une variable d'environnement
- Permettre d'ajouter soi-meme des IP "à la main" dans un fichier
- Concaténer le tout, backup le fichier de conf (dernière update), et injecter la liste dans la bonne section du fichier de conf d'Adguard
- Recharger Adguard en relançant le container (accès au socket via docker socket proxy pour limiter les permissions)
Tout ceci de manière complètement autonome, avec une fréquence choisie en variable d'environnement dans la conf du compose.
Plus d'infos directement sur le repo :
::card{title="🐋 __Adguard CIDRE Sync__"}
[Robot de synchronisation de la blocklist d'Adguard](https://git.djeex.fr/Djeex/adguard-cidre)
::
@@ -0,0 +1,54 @@
---
title: Lumeex
description: Lumeex est un générateur de galerie photo statique en Python — minimaliste, léger et entièrement personnalisable sans CMS.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
<div align="center">
<img src="https://git.djeex.fr/Djeex/lumeex/raw/branch/main/illustration/logo.svg" alt="Lumeex Screenshot" width="300"/>
</div>
<div align="center">
<p>Yet another minimalist, lightweight photo gallery static site generator.</p>
</div>
<div align="center">
<img src="https://git.djeex.fr/Djeex/lumeex/raw/branch/main/illustration/lumeex.png" alt="Lumeex Screenshot" />
</div>
---
Amateur de photographie, j'ai passé plusieurs semaines à chercher un framework avec une galerie photo qui rende mieux qu'Instagram. Je souhaitais quelque chose qui mette en avant les photos plutôt que l'auteur, et qui rende chaque visite unique en chargeant les photos dans un ordre aléatoire, tout en pouvant filtrer et trier par tag ou association de tags.
Finalement, je n'ai rien trouvé qui faisait exactement ce que je voulais, et lorsque quelque chose s'en approchait, c'était toujours via de lourds CMS. J'ai alors décidé de faire un site statique à la main, à l'ancienne, avec Notepad++. Me débrouillant assez bien en HTML/CSS et un peu en JavaScript, je suis vite tombé sur un résultat sympa, durant mes vacances, entre deux sessions à la plage. Après tout, un bon ouvrier doit avoir de bons outils, et il n'y a pas de meilleurs outils que ceux que l'on crée soi-même.
Puis je me suis dit qu'il serait peut-être pas mal d'automatiser certaines tâches, comme les formats de favicons, le redimensionnement et la conversion des images, la génération de la galerie au lieu de tout saisir à la main, la création des `robots.txt` et `sitemap`… Et je me suis remis à Python.
Finalement, après avoir obtenu de bons résultats, je me suis dit autant aller jusqu'au bout : un framework complet permettant de générer une galerie sur un site statique, en remplissant juste les informations du site dans un fichier de config et avec un peu de personnalisation visuelle, sans toucher au code.
C'est ainsi qu'est né **Lum[eex]{style="color: #1ad6ff"}**.
<div align="center">
<img src="https://git.djeex.fr/Djeex/lumeex/raw/branch/main/illustration/lumeex-webui.png" alt="Lumeex Screenshot" />
</div>
---
### Et voilà le bousin
:::div{class="relative"}
:ellipsis{left=0px width=40rem top=10rem blur=140px}
:::
::card-group
::card{icon="i-noto-open-book" title="Documentation" to="https://lumeex.djeex.fr" target="_blank"}
Accéder à la doc
::
::card{icon="i-simple-icons-gitea" title="Repository" to="https://git.djeex.fr/Djeex/lumeex" target="_blank"}
Voir le repo
::
::card{icon="i-fluent-color-design-ideas-48" title="Demo" to="https://modern.djeex.fr" target="_blank"}
Explorer la démo
::
::
@@ -0,0 +1,48 @@
---
title: Instameex
description: Instameex est un outil Docker pour fusionner des exports SDR et HDR en un JPEG avec gain map prêt pour l'upload HDR sur Instagram.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
<div align="center">
<img src="https://git.djeex.fr/Djeex/instameex/raw/branch/main/src/assets/img/logo-long.svg" alt="Instameex Screenshot" width="300"/>
</div>
<div align="center">
<p>Mixez vos photos SDR et HDR pour obtenir un fichier parfait pour Instagram</p>
</div>
<div align="center">
<img src="https://git.djeex.fr/Djeex/instameex/raw/branch/main/illustration/instameex-illustration.png" width="640" alt="Instameex Screenshot" />
</div>
---
Il n'y a rien de plus frustrant que la gestion du HDR d'Instagram. Ce dernier compresse et démolit les gainmaps, et au moindre changement de ratio ou de taille, supprime purement et simplement le HDR. Quant à Lightroom, son système de "SDR preview" est tout bonnement inacceptable, ne permettant pas d'obtenir des résultats corrects. Jusqu'ici, lorsque l'on veut poster sur Instagram, il faut choisir entre un SDR potable et un HDR déficient, ou l'inverse.
Pourquoi ne pas tout simplement éditer pleinement son fichier SDR d'une part, son fichier HDR d'une autre part, et recalculer une gainmap à partir de ces deux fichiers parfaits ?
Quelques aventuriers se sont déjà lancés sur ce chemin, notamment avec un plugin [Adobe Lightroom Classic](https://github.com/karachungen/lightroom-plugin-export-hdr). Mais jugez-moi comme vous voulez, je n'utilise que Lightroom CC, qui ne gère pas les plugins.
Je me suis alors inspiré d'un [fork du premier projet](https://github.com/kostis-kounadis/instagram-hdr-assembler) qui a donné lieu au plugin LrC, pour créer un front, déployable facilement avec Docker. On ne va pas se mentir, cela a été un bon moyen de tester mon abonnement Claude Code. Et je dois avouer que c'est très impressionnant de le voir créer ses propres environnements, faire des tests de bout en bout, auto-corriger son code, et écrire des bilans détaillés. J'ai quand même tout relu, je vous rassure. Et j'ai énormément appris sur les principes du HDR, des gainmaps, des courbes HLG/PQ, des espaces colorimétriques, et j'en passe.
En gros, voilà ce que donne mon workflow à présent pour poster sur Insta :
![Instameex](/img/nonsense/instameex-workflow.svg)
Je vous présente donc **Instam[eex]{style="color: #1ad6ff"}**
---
### Et voilà le résultat
:::div{class="relative"}
:ellipsis{left=0px width=40rem top=10rem blur=140px}
:::
::card-group
::card{title="🐋 __Instameex__" to="https://git.djeex.fr/Djeex/instameex" target="_blank"}
Accéder au repo
::
::card{title="🌍 __Version en ligne__" to="https://instameex.djeex.fr" target="_blank"}
Convertir en ligne
::
::
@@ -0,0 +1,2 @@
title: Bash
icon: i-lucide-file-terminal
@@ -0,0 +1,140 @@
---
title: Doublons servarr
description: Un script bash pour détecter et corriger les fichiers médias en double dans les bibliothèques Sonarr et Radarr en remplaçant les copies par des hardlinks.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
# Detection de doublons et remplacement par des hardlinks
---
Six mois après avoir téléchargé des térabytes de media, je me suis rendu compte que Sonarr et Radarr les copaient dans ma biblio Plex au lieu de créer des hardlinks. C'est dû à un mécanisme contre intuitif qui est que si vous montez plusieurs dossiers dans Sonarr/Radarr, il les voit comme deux systemes de fichiers différents. Et ne peut donc pas créer de hardlinks. C'est pour cela qu'il ne faut monter qu'un seul dossier parent, qui contient tous les enfants (`downloads`, `movies`, `tvseries` dans le dossier parent `media` par exemple).
J'ai donc restructuré mes dossiers, remis à la main chaque chemin dans Qbittorrent, Plex, et autres. Il restait à trouver un moyen de détecter les doublons existants et d'automatiquement les supprimer et de créer des hardlinks à la place, pour économiser de l'espace.
Mes dossiers :
```sh
.
└── media
├── seedbox
├── radarr
│ └── tv-radarr
├── movies
└── tvseries
```
Mes dossiers originaux sont dans `seedbox`, et il ne faut surtout pas les modifier pour qu'ils continuent d'etre "seed". Les copies, et donc doublons, sont dans `movies` et `tvseries`. Mais pour complexifier la chose, j'ai aussi des media uniques originaux déposés par ailleurs dans `movies` et `tvseries`, sinon cela serait trop facile. Et dans ces deux dossiers, il peut y avoir des sous dossiers, des sous-sous dossiers, etc.
L'idée est donc de :
- lister les originaux dans seedbox
- lister les fichiers dans movies
- comparer les deux listes et isoler les chemins des doublons
- supprimer les doublons
- hardlinker les originaux dans les dossiers des doublons supprimés
Alors oui j'ai demandé à ChatGPT et à Qwen3 (que j'héberge sur une machine dédiée à l'IA). Et evidemment ils m'ont conseillé les rfind, rdfind, dupes, rdupes, rmlint... Mais comparer les hash de 30TB de media, faudrait plusieurs jours, j'ai vite abandonné.
Au final, je n'ai que des `.mkv` à chercher et les doublons ont exactement les mêmes noms que les originaux, ce qui simplifie grandement la tâche. Un simple script bash devait donc être suffisant.
Je vous passe les incessantes questions réponses avec ChatGPT, je suis assez déçu. Qwen3 a été bien plus propre. ChatGPT n'a pas cessé de mettre des solutions type awk, qui pètent la lecture des chemins au moindre espace. En faisant relire à Qwen, et en lui demandant de se passer de awk, le résultat a été immediatement plus qualitatif.
Pour tester, j'ai d'abord demandé un script qui ne fait que lister et comparer :
```sh
#!/bin/bash
# Créer un tableau associatif pour stocker les doublons
declare -A seen
# Trouver tous les fichiers .mkv uniquement (exclure les dossiers)
find /media/seedbox /media/movies /media/tvseries -type f -name "*.mkv" -print0 | \
while IFS= read -r -d '' file; do
# Obtenir l'inode du fichier et son chemin
inode=$(stat --format="%i" "$file")
filename=$(basename "$file")
# Si ce nom de fichier a déjà été vu
if [[ -n "${seen[$filename]}" ]]; then
# Vérifier si l'inode est différent du précédent
if [[ "${seen[$filename]}" != "$inode" ]]; then
# Ajouter le doublon à la sortie en affichant les chemins complets
echo "Doublons pour \"$filename\" :"
echo "${seen["$filename"]} ${seen["$filename:full_path"]}"
echo "$inode $file"
echo
fi
else
# Si c'est la première fois qu'on rencontre ce nom de fichier
seen[$filename]="$inode"
seen["$filename:full_path"]="$file"
fi
done
```
J'ai ainsi obtenu ce type de réponse :
```
Doublons pour "episode1.mkv" :
1234567 /media/seedbox/sonarr/Serie 1/Season1/episode1.mkv
2345678 /media/tvseries/Serie 1/Season1/episode1.mkv
```
Avec "awk", il se serait arrêté à `/media/seedbox/sonarr/Serie`. Je ne suis absolument pas un pro, mais Qwen3 a été plus performant et m'a expliqué de A à Z pourquoi et comment faire.
Une fois que j'ai vu que cela fonctionnait bien, j'ai demandé un script qui fait l'intégralité de la cinématique, de la comparaison aux hardlinks en passant par la suppression des doublons.
Encore une fois ChatGPT a été décevant. Malgré mes demandes, il créait d'abord les hardlinks et ensuite il supprimait les doublons. Ce qui.. suprimme aussi le lien (meme si cela conserve l'originale). Idiot.
Petit détour par Qwen3, et ma RTX 5090 en PLS, et paf un résultat bien plus propre. Bon il a gardé les emoji de ChatGPT qui peut pas s'empecher d'en mettre partout, mais voilà :
```sh
#!/bin/bash
echo "🔍 Étape 1 : Indexation des fichiers originaux dans /media/seedbox..."
declare -A seen
# Indexe tous les .mkv dans seedbox
while IFS= read -r -d '' file; do
filename=$(basename "$file")
seen["$filename"]="$file"
done < <(find /media/seedbox -type f -name "*.mkv" -print0)
echo "📦 Étape 2 : Remplacement automatique des doublons..."
total_doublons=0
total_ko_economises=0
while IFS= read -r -d '' file; do
filename=$(basename "$file")
original="${seen[$filename]}"
if [[ -n "$original" && "$original" != "$file" ]]; then
inode_orig=$(stat -c %i "$original")
inode_dupe=$(stat -c %i "$file")
if [[ "$inode_orig" != "$inode_dupe" ]]; then
size_kb=$(du -k "$file" | cut -f1)
echo "🔁 Remplacement :"
echo " Doublon : $file"
echo " Original : $original"
echo " Taille : ${size_kb} Ko"
rm "$file" && ln "$original" "$file" && echo "✅ Hardlink créé."
total_doublons=$((total_doublons + 1))
total_ko_economises=$((total_ko_economises + size_kb))
fi
fi
done < <(find /media/movies /media/tvseries -type f -name "*.mkv" -print0)
echo ""
echo "🧾 Résumé :"
echo " 🔗 Doublons remplacés par hardlink : $total_doublons"
echo " 💾 Espace disque économisé approximatif : ${total_ko_economises} Ko (~$((total_ko_economises / 1024)) Mo)"
echo "✅ Terminé."
```
Bilan j'ai :
- appris pas mal de subtilité bash
- appris qu'il ne faut jamais copier coller un script généré ChatGPT sans le comprendre et sans le tester en dry-run
- appris que Qwen sur une RTX 5090 est plus cohérent que ChatGPT 4o sur des fermes de serveurs (je vous passe les résultats de la version "normale").
- appris que même quand on a 100TB d'espace, monitorer ce dernier m'aurait permis de voir beaucoup plus tot que j'avais 12TB de doublons qui trainent.
@@ -0,0 +1,87 @@
---
title: Luks backup
description: Un script bash pour extraire automatiquement les headers LUKS de tous les disques chiffrés, les identifier par numéro de série et les archiver de façon chiffrée.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
# Backup des headers luks pour disques/volumes chiffrés
---
Je me suis rendu compte il y a peu qu'il ne suffisait pas d'avoir le mot de passe pour deverouiller un volume luks apres une panne ou une corruption. J'ai ainsi appris à dump les headers luks des disques/volumes et à utiliser les numéros de série + noms de partitions pour pouvoir bien identifier quel header correspond à quel disque/partition (j'en ai 10 !).
Après avoir bien galéré à la main, j'avoue avoir demandé à Qwen3 (llm hebergé sur ma RTX 5090) de me faire un script qui automatise le listing et identification des disques, dump les headers et les stock dans une archive chiffrée prete à etre backupée sur mon serveur de sauvegarde.
Ainsi, ce script :
* Liste et identifie les disques avec leur numéro de série
* Liste les partition
* Dump les headers dans un dossier dans `/root` (dossier sécurisé)
* Cree une archive temporaire
* Prompt pour saisir un mot de passe
* Chiffre avec le mot de passe
* Détruit l'archive non chiffrée
```
#!/bin/bash
# Directory where LUKS headers will be backed up
DEST="/root/luks-headers-backup"
mkdir -p "$DEST"
echo "🔍 Searching for LUKS containers on all partitions..."
# Loop through all possible disk partitions (including NVMe and SATA)
for part in /dev/sd? /dev/sd?? /dev/nvme?n?p?; do
# Skip if the device doesn't exist
if [ ! -b "$part" ]; then
continue
fi
# Check if the partition is a LUKS encrypted volume
if cryptsetup isLuks "$part"; then
# Find the parent disk device (e.g. nvme0n1p4 → nvme0n1)
disk=$(lsblk -no pkname "$part" | head -n 1)
full_disk="/dev/$disk"
# Get the serial number of the parent disk
SERIAL=$(udevadm info --query=all --name="$full_disk" | grep ID_SERIAL= | cut -d= -f2)
if [ -z "$SERIAL" ]; then
SERIAL="unknown"
fi
# Extract the partition name (e.g. nvme0n1p4)
PART_NAME=$(basename "$part")
# Build the output filename with partition name and disk serial
OUTPUT="$DEST/luks-header-${PART_NAME}__${SERIAL}.img"
echo "🔐 Backing up LUKS header of $part (Serial: $SERIAL)..."
# Backup the LUKS header to the output file
cryptsetup luksHeaderBackup "$part" --header-backup-file "$OUTPUT"
if [[ $? -eq 0 ]]; then
echo "✅ Backup successful → $OUTPUT"
else
echo "❌ Backup failed for $part"
fi
fi
done
# Create a timestamped compressed tar archive of all header backups
ARCHIVE_NAME="/root/luks-headers-$(date +%Y%m%d_%H%M%S).tar.gz"
echo "📦 Creating archive $ARCHIVE_NAME..."
tar -czf "$ARCHIVE_NAME" -C "$DEST" .
# Encrypt the archive symmetrically using GPG with AES256 cipher
echo "🔐 Encrypting the archive with GPG..."
gpg --symmetric --cipher-algo AES256 "$ARCHIVE_NAME"
if [[ $? -eq 0 ]]; then
echo "✅ Encrypted archive created: ${ARCHIVE_NAME}.gpg"
# Remove the unencrypted archive for security
rm -f "$ARCHIVE_NAME"
else
echo "❌ Encryption failed"
fi
```
Ne pas oublier de backup `/etc/fstab` et `/etc/crypttab` !
@@ -0,0 +1,95 @@
---
title: Socat Proxy
description: Utiliser socat pour proxifier le socket Docker via Docker Socket Proxy, permettant à Beszel de collecter les stats des conteneurs sans exposer le socket complet.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
# Socat Proxy
---
Ce projet répond à un cas d'usage problématique :
- J'ai [Beszel](https://beszel.dev/), un conteneur de monitoring en mode host, nécessitant d'exposer le socket de Docker afin qu'il récupère les stats des conteneurs
- Afin de ne pas laisser le socket complètement ouvert pour Beszel, j'ai [Docker Socket Proxy](https://github.com/Tecnativa/docker-socket-proxy), un conteneur qui se place entre le scoket de docker et le conteneur qui en a besoin, et qui filtre le requêtes en paramétrant les bonnes permissions pour ne pas tout exposer au conteneur qui l'utilise.
Problème, si __Beszel__ est en mode host, il doit contacter __Docker Socket Proxy__ directement sur un port de l'host, c'est à dire en exposant un port de __Docker Socket Proxy__. Ce qui fait que n'importe quel conteneur/application sur mon host peut l'appeler et utiliser le socket docker.
C'est là qu'intervient [Socat Proxy](https://git.djeex.fr/Djeex/socat-proxy). Ce dernier est un conteneur qui :
- Crée un socket UNIX
- Ecoute ce socket
- Envoie les requetes vers Docker Socket Proxy et vice versa
- Permet de remplacer le vrai socket docker en exposant le socket proxy créé, dans le conteneur final via un bind mount (ici, Beszel)
Ainsi, un filtre comme Docker Socket Proxy dialogue avec Socat Proxy dans leur propre réseau isolé (en mode bridge), et le bind mount du socket UNIX créé est localisé sur l'host dans un dossier avec les permissions nécessaires pour ne pas etre visible des autres conteneurs/applicatifs.
En gros :
![](/img/nonsense/socat-proxy.svg)
Par exemple, pour Beszel cela rendrait comme ceci :
```yaml
services:
socat-proxy:
image: git.djeex.fr/djeex/socat-proxy:latest
container_name: socat-proxy-beszel
environment:
- TARGET_HOST=${TARGET_HOST}
- TARGET_PORT=${TARGET_PORT}
- UNIX_SOCKET_PATH=${UNIX_SOCKET_PATH}
- HOST_SOCKET_PATH=${HOST_SOCKET_PATH}
- UNIX_SOCKET_NAME=${UNIX_SOCKET_NAME}
volumes:
- ${HOST_SOCKET_PATH}:${UNIX_SOCKET_PATH}
restart: unless-stopped
depends_on:
- ${TARGET_HOST}
socket-proxy:
image: lscr.io/linuxserver/socket-proxy:latest
container_name: ${TARGET_HOST}
security_opt:
- no-new-privileges:true
environment:
- CONTAINERS=1
- INFO=1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
read_only: true
tmpfs:
- /run
beszel-agent:
image: henrygd/beszel-agent:latest
container_name: beszel-agent
restart: unless-stopped
network_mode: host
security_opt:
- no-new-privileges:true
volumes:
- ${HOST_SOCKET_PATH}/${UNIX_SOCKET_NAME}:/var/run/docker.sock:ro
environment:
- #... your Beszel environment var
depends_on:
- socat-proxy
```
Plus d'infos directement sur le repo :
::card{title="🐋 __Socat Proxy__"}
[A lighteweight bind mount socket proxy](https://git.djeex.fr/Djeex/socat-proxy)
::
+43
View File
@@ -0,0 +1,43 @@
---
title: HotDisk
description: Un script bash qui surveille la température des disques durs et éteint automatiquement le serveur lorsqu'ils dépassent un seuil de sécurité trop longtemps.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
# HotDisk
---
Quand on a un NAS avec plusieurs disques dans une buanderie, les températures peuvent vite grimper. Or, un disque dur est très sensible aux températures et peut subir de gros dommages s'il dépasse une température seuil pendant un certain temps. Après un été très chaud qui a fournit son lot de sueur froide en regardant la température de mes disques, j'ai cherché un moyen de pouvoir automatiser l'extinction du serveur en cas de dépassement prolonger de la température maximale supportée par mes disques.
N'ayant rien trouvé de convaincant, je l'ai donc fait moi-même.
- Le script lit la température SMART de tous les disques SATA chaque minute.
- Il compte le nombre de minutes consécutives où la température est au-dessus ou en dessous du seuil.
- Il envoie des notifications Discord si le seuil est dépassé ou si la température redescend.
- Il déclenche larrêt du système si la température dépasse la limite pendant la durée configurée.
- Il enregistre toutes les températures et l’état des compteurs, et effectue automatiquement la rotation des journaux.
Puis tant qu'on y est, j'ai ajouté un script d'installation qui installe le script, le rend éxecutable, crée un service systemd et un timer systemd et l'active. Le script d'installation permet aussi de régler les différentes variables:
| Variable | Description | Valeur par défaut |
|-----------------------|------------------------------------------------------------------------------|-----------------------------------------------|
| `MAX_TEMP` | Température maximale autorisée (°C) avant le début du compte à rebours darrêt | `60` |
| `HOT_DURATION` | Minutes consécutives au-dessus de `MAX_TEMP` avant larrêt du système | `5` |
| `COOL_RESET_DURATION` | Minutes consécutives en dessous de `MAX_TEMP` pour réinitialiser les compteurs | `5` |
| `LOG_FILE` | Chemin du fichier journal principal | `/var/log/hdd_temp_monitor.log` |
| `LOG_ROTATE_COUNT` | Nombre de fichiers journaux à conserver | `7` |
| `LOG_ROTATE_PERIOD` | Période de rotation des journaux (`daily` ou `weekly`) | `daily` |
| `DISCORD_WEBHOOK` | URL du webhook Discord pour les notifications | _Obligatoire_ |
Il execute aussi un autre script qui paramètre le logrotate avec les éléments configurés prédédemment. Et enfin, le script d'installation peut etre executé via un simple curl + execution d'un dernier script pour les plus flemmard.
Il a fallu également gérer le sujet du root sans sudo, du sudo seul, de l'utilisateur sans sudo, les divers cas d'erreur (dépendances manquantes, erreur dans les permissions, créations de fichier, de lecture des données des disques, etc...)
Et l'acces concurrent au fichier de statuts.
Plus d'infos directement sur le repo :
::card{title="📜 __HotDisk__"}
[Gardez vos disques au frais !](https://git.djeex.fr/Djeex/hotdisk)
::
@@ -0,0 +1,118 @@
---
title: Backrest Docker Stop
description: Un script bash qui arrête les conteneurs Docker avant une sauvegarde Backrest et les redémarre après — pour des sauvegardes de bases de données sans dump complexe.
---
:ellipsis{left=0px width=40rem top=10rem blur=140px zIndex=60}
# Backrest Docker Stop
---
[Backrest](https://github.com/garethgeorge/backrest) est un formidable outil de backup. Dans le cas de [Serveex](https://docu.djeex.fr/fr/serveex/introduction), la majeure partie des données à sauvegarder sont des conteneurs, et souvent ces conteneurs possèdent des bases de données. Le problème ? On ne peut pas sauvegarder proprement une BDD qui est en route. Alors, il existe plein de solutions complexe à base de dump des bases de données, mais souvent le plus simple cela reste de stopper les conteneurs, de sauvegarder, et de redémarrer les conteneurs.
**Backrest** ne propose pas de solutions native, mais il propose d'executer des scripts customisés à déclencher sur des évenements, comme le démarrage et la fin de la sauvegarde par exemple. Notre besoin est donc de stopper les conteneurs dont on veut sauvegarder la BDD, à chaque démarrage du plan de sauvegarde, et de les redémarrer à la fin de l'execution du plan de sauvegarde.
Pour cela nous allons avoir besoin d'un script bash et de connecter Backrest au socker de Docker, afin d'avoir la cinématique suivante :
- Le plan de sauvegarde se met en route
- L'evenement déclenche l'execution d'un script custom
- Le script contacte docker et demande la liste des conteneurs qui comportent le label `backrest.backup.stop=true`
- Il récupère cette liste et leur envoie une commande d'extinction
- Le plan de sauvegarde s'arrête
- L'evenement déclenche l'execution d'un script custom
- Le script contacte docker et demande la liste des conteneurs qui comportent le label `backrest.backup.stop=true`
- Il récupère cette liste et leur envoie une commande de démarrage
## Faire communiquer Backrest et Docker en toute sécurité
Pour faire communiquer **Backrest** et Docker en toute sécurité, nous utiliserons [Docker Socket Proxy](https://github.com/linuxserver/docker-socket-proxy), afin de n'accorder que les droits nécessaires plutot que d'exposer l'intégralité du socket à Docker. Voici donc la stack :
```yaml
---
services:
backrest:
image: garethgeorge/backrest:latest
container_name: backrest
hostname: backrest
security_opt:
- no-new-privileges:true
volumes:
- ... # vos volumes
environment:
- ... # vos variables
- DOCKER_HOST=tcp://socket-proxy-backrest:2375
restart: unless-stopped
ports:
- ... # vos ports
depends_on:
- socket-proxy
socket-proxy:
image: lscr.io/linuxserver/socket-proxy:latest
container_name: socket-proxy-backrest
security_opt:
- no-new-privileges:true
environment:
- CONTAINERS=1
- ALLOW_START=1
- ALLOW_STOP=1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
read_only: true
tmpfs:
- /run
```
Et voilà, Backrest pourra ainsi communiquer avec Docker en toute sécurité.
## Les scripts
Vous trouverez ci-dessous les scripts à renseigner en action pour les évèvenements de démarrage et d'arrêt de la sauvegarde dans **Backrest**.
::code-group
```sh [Stop]
#!/usr/bin/env bash
BACKUP_LABEL="backrest.backup.stop=true"
BACKUP_CONTAINERS=$(docker ps -aqf "label=$BACKUP_LABEL")
for BC in $BACKUP_CONTAINERS
do
docker stop "$BC"
done
sleep 10
```
```sh [Start]
#!/usr/bin/env bash
BACKUP_LABEL="backrest.backup.stop=true"
BACKUP_CONTAINERS=$(docker ps -aqf "label=$BACKUP_LABEL")
for BC in $BACKUP_CONTAINERS
do
docker start "$BC"
done
sleep 10
```
::
## Le label
Une fois les scripts renseignés et paramétrés pour les bons hooks dans **Backrest**, vous n'avez plus qu'à ajouter le libellé `backrest.backup.stop=true` dans les fichiers `compose.yaml` des conteneurs à éteindre et rallumer durant les sauvegardes :
```yaml
services:
votre_service:
...
labels:
- com.centurylinklabs.watchtower.enable=true
```
Et voilà, à la prochaine sauvegarde, les conteneurs correctement labelisés s'arreteront pendant la sauvegarde et redémarreront tout seuls à la fin.