Archives
Tous les articles archivés.
-
RAM d’un NAS de 2011 : dmidecode dément la fiche commerciale
RAM d’un NAS de 2011 : trouver le vrai type et le plafond chipset avec dmidecode, contre une fiche commerciale qui annonçait 1 Go DDR3 non extensible.
-
Backup générique multi-DB : Postgres et ClickHouse
Backup générique multi-DB : superuser Postgres auto-détecté via POSTGRES_USER et tables ClickHouse découvertes par system.tables.
-
Répliquer une prod Coolify sans Coolify avec Traefik
Coolify rend ses composes et labels Traefik sur disque : un standby se monte par rsync et un Traefik standalone, sans piloter Coolify.
-
Deux VPN sur le même /24 : le full-tunnel éclipse ton mesh
Ping OK mais services injoignables : quand un second VPN en full-tunnel sur le même 10.8.0.0/24 détourne silencieusement la route de ton mesh WireGuard.
-
Console série muette : c’était la RAM, pas l’UART
Console série muette : ce n’était pas l’UART mais une RAM incompatible bloquant le POST. Et comment envoyer F1 à un BIOS headless.
-
GEO : 6 réglages pour être cité par ChatGPT et Claude
GEO : 6 réglages pour qu’un site soit lu, compris et cité par ChatGPT, Claude et Perplexity, au-delà du SEO.
-
Message d’erreur : une hypothèse, pas un diagnostic
Message d’erreur trompeur : quatre incidents où croire la cause affichée a fait perdre du temps, et le réflexe de debug à acquérir pour l’éviter.
-
Doublons de n° de facture : MAX+1 et advisory lock
Doublons de numéros de facture en prod : pourquoi le calcul « dernier créé + 1 » échoue et comment un advisory lock PostgreSQL sécurise la concurrence.
-
robots.txt et bots IA : autoriser les moteurs de réponse
robots.txt et bots IA : entraînement et citation se contrôlent séparément, et robots.txt seul ne suffit pas à bloquer un crawler.
-
llms.txt : donner un plan de site aux LLM
llms.txt est un fichier Markdown qui résume le site pour les LLM, comme robots.txt pour les crawlers : format et génération automatique avec Astro.
-
Mocker `navigator.wakeLock` readonly : defineProperty
Mocker navigator.wakeLock en headless : la propriété est readonly, il faut Object.defineProperty là où geolocation accepte l’assignation directe.
-
Un POC sans tests n’est pas un départ, c’est une direction
Du POC à la prod sans réécrire l’intention : refonte par extractions successives, CI dès la première MR et filet de tests de régression.
-
Edge marker Leaflet : caché sous les contrôles, intappable
Edge marker Leaflet : un marqueur de bord se place sous les contrôles et devient invisible et intappable. Diagnostic et zones d’évitement.
-
Leaflet : `marker.remove()` ne nettoie pas son `LayerGroup`
Leaflet : marker.remove() retire le marker de la carte mais pas de son LayerGroup parent, doublons à chaque cycle add/remove. Solution : clearLayers().
-
Wake Lock API : relâché en arrière-plan, à ré-acquérir
Wake Lock API : le navigateur relâche le lock en arrière-plan ; il faut le ré-acquérir au visibilitychange, sinon l’écran s’éteint au retour.
-
State machine : fail-open vs fail-closed selon la criticité
State machine sur mesures bruitées : choisir fail-open ou fail-closed selon le coût d’erreur de chaque transition.
-
Wording UX : erreurs inline par champ sur des uploads
Wording UX sur des uploads Symfony : reproduire les messages au mot près et afficher l’erreur inline sous chaque champ, sans flash global.
-
iOS Safari injecte une NBSP : la regex `\s` ne la voit pas
iOS Safari glisse une espace insécable (U+00A0) dans un input téléphone : la regex `\s` côté serveur ne la matche pas, et rejette un numéro valide.
-
Tunnel SSH invisible des conteneurs Docker : bind 0.0.0.0
Tunnel SSH inaccessible depuis un conteneur Docker : binder le forward sur 0.0.0.0 au lieu de 127.0.0.1 pour le rendre joignable.
-
Tracker GPS : positions « fantôme » sans fix (sat absent)
Tracker GPS en mode économie : sans le champ « sat », une position est un cache de la dernière connue, pas un fix frais. Comment la filtrer côté serveur.
-
Anti-spam notifs IoT : pattern épisode + ack + ré-armement
Anti-spam des notifications IoT : une machine d’état « épisode » avec acquittement par URL ou bouton et ré-armement, plutôt qu’un simple cooldown.
-
1NCE Flat 10 ans : 500 Mo TOTAL sur la décennie, pas annuel
SIM M2M 1NCE IoT Lifetime Flat : 500 Mo et 250 SMS pour 12 €, mais ce quota est TOTAL sur 10 ans, pas annuel. Lecture attentive obligatoire.
-
`Access denied @localhost` : grant @'%' vs socket Unix
MariaDB Access denied @localhost : un grant sur @'%' (TCP) ne couvre pas le socket Unix. Connectez-vous en 127.0.0.1 pour forcer le TCP.
-
Traccar `position.attributes` : bien plus que lat/lon
Le webhook JSON de Traccar expose un champ position.attributes riche (battery, RSSI, satellites, mode) trop souvent ignoré à l’intégration.
-
Leaflet : `L.geoJSON()` n’est pas un layer mais un groupe
Leaflet : L.geoJSON() retourne une FeatureGroup, pas un layer simple, et removeLayer sur le parent échoue en silence, laissant des polygones fantômes.
-
Free Mobile SMS API : un canal de notif gratuit
Free Mobile SMS API : un GET HTTP gratuit pour s’envoyer des SMS d’alerte sur ses projets IoT, monitoring serveur et domotique.
-
Tracker IoT 4G : INTERNET FAILED en intérieur, bande B20
Tracker IoT 4G qui affiche INTERNET FAILED en intérieur alors que la SIM marche : la cause est la bande B20 absente du modem. Diagnostic et solutions.
-
`extra_hosts` override le DNS Docker en silence
extra_hosts: host-gateway override silencieusement le DNS Docker du réseau : un alias réutilisant un nom de service casse la résolution en prod.
-
Traccar : forcer un protocole sur un port précis
Traccar : forcer un protocole GPS sur un port précis via une entrée traccar.xml, quand l’auto-assignment des ports ne donne pas le bon mapping.
-
JT808 : l’ID du device est 12 chiffres BCD, pas 11
Tracker JT808 jamais Offline dans Traccar : l’uniqueId attendu fait 12 chiffres BCD avec le zéro de tête, pas l’ID raccourci du label.
-
Tracker GPS chinois : identifier le protocole par sniff hex
Identifier le protocole wire d’un tracker GPS chinois par sniff hex avec tcpdump quand le label produit ment et que Traccar ferme sans log.
-
Le piège RCS : configurer un device GSM-only en SMS
RCS envoie vos SMS de config dans le vide vers un device IoT GSM-only : pourquoi le message reste « envoyé » sans jamais arriver, et comment le forcer.
-
Hash avec `$` en env var : tronqué en silence
Hash scrypt avec `$` stocké en env var : compose ou un PaaS interprète le séparateur et tronque la valeur en silence, d’où un 401. Cause et solution.
-
Override d’entrypoint : l’image perd son ENTRYPOINT
Override entrypoint en docker-compose : on remplace l’ENTRYPOINT de l’image, pas seulement le CMD, et le wrapper sh -c casse en silence.
-
Bind mount fantôme : git ne remplace pas un dossier
Bind mount fantôme : après qu’un dossier vide a été auto-créé par Docker, git refuse de le remplacer par un fichier lors d’un git pull.
-
Docker bind mount : la source absente crée un dossier vide
Docker bind mount : quand le fichier source n’existe pas sur l’hôte, le daemon crée un dossier vide et le conteneur échoue avec une erreur cryptique.
-
Harnais de tests bash pour une API PDF qu’on ne maîtrise pas
Tester une API PDF externe avec un harnais bash : curl, pdftotext et grep -F pour vérifier le contenu métier à chaque livraison.
-
Coolify « Pre-deployment Command » : un exec, pas un shell
La « Pre-deployment Command » de Coolify n’est pas un shell sur l’hôte mais un docker exec dans un conteneur : comment templater un fichier de conf.
-
Hash de mot de passe en Node : scrypt sans dépendance native
Hash de mot de passe en Node avec scrypt de la stdlib : zéro dépendance native, paramètres OWASP et format auto-portable pour migrer plus tard.
-
Sécuriser un webhook avec un secret dans l’URL (Fastify)
Sécuriser un webhook Fastify exposé en HTTPS avec un secret dans l’URL et une comparaison timing-safe, sans signature HMAC.
-
« GT06 » vs MiCODUS : syntaxe SMS et port Traccar différents
Tracker GPS MiCODUS MP50G muet sur Traccar : la syntaxe SMS GT06 générique ne marche pas et le protocole micodus écoute sur le port 5174.
-
« Compatible Traccar » : 80 % des colliers GPS sont faux
Compatible Traccar sur AliExpress : repérer la fausse compatibilité des colliers GPS et monter une clôture GPS self-hosted fiable.
-
Migrer Nextcloud v16→v30 en Docker : le config.php qui ment
Migrer Nextcloud de la v16 à la v30 en Docker impose des upgrades majeurs un par un : voici les trois pièges (version.php, UID 33, needsDbUpgrade).
-
Qwen3.6-27B dense bat un MoE 397B sur le code, en local
Qwen3.6-27B (Alibaba, 22 avril 2026, Apache 2.0) est probablement le modèle local le plus impactant de l’année pour les développeurs.
-
Claude Code sur un Ollama local ? Oui, mais mauvaise idée
Réponse honnête : techniquement oui. En pratique, mauvaise idée.
-
NPU de laptop : le faire travailler la nuit, gratuitement
NPU de Copilot+ PC : 45 TOPS sous-exploités qu’on fait tourner la nuit, sur secteur, pour des batches IA notifiés sur le téléphone via ntfy.
-
Vous avez un Copilot+ PC. Quel runtime LLM choisir en 2026 ?
Runtime LLM sur Copilot+ PC : six options testées sur Snapdragon X Elite, du CPU Ollama au NPU avec Foundry Local et QNN.
-
Gemma 4 : le 26B MoE bat des modèles 5x plus gros
Gemma 4 décline quatre variantes locales : le 26B MoE et le 31B dense rivalisent avec des modèles bien plus gros sur Arena AI.
-
45 TOPS de NPU Snapdragon : Ollama en utilise zéro
Snapdragon X Elite : ses 45 TOPS de NPU restent inutilisés par Ollama, qui tourne 100 % CPU. Quels runtimes exploitent vraiment le NPU sur Copilot+.
-
Ollama/LM Studio sur Snapdragon : NPU 45 TOPS à zéro
Ollama et LM Studio tournent en CPU-only sur Snapdragon X Elite : le NPU 45 TOPS reste à zéro, faute de backend Hexagon activé dans llama.cpp.
-
Gatsby + styled-components : `develop` cache le SSR cassé
Gatsby develop tourne en CSR-only et masque un SSR styled-components cassé : tout passe en local, mais FOUC garanti en prod.
-
Self-hosted LiveSync : « rebuilt or corrupted » au 1er sync
Obsidian LiveSync affiche « database rebuilt or corrupted » au premier sync sur un CouchDB neuf : un faux positif anti-conflits, pas une corruption.
-
Coolify + Apache front TLS : le certresolver fait du 502
Coolify génère un certresolver Traefik qui tente un challenge ACME dans le vide derrière Apache, d’où un 502 silencieux malgré un container healthy.
-
Argon2 dans LUKS : moins de mémoire ≠ moins sûr
LUKS et Argon2 : réduire --pbkdf-memory ne baisse pas la sécurité, cryptsetup compense en itérations à temps de calibration constant.
-
Argon2 : le KDF par défaut piège les cibles à 1 GB de RAM
LUKS2 et Argon2id : le coût KDF par défaut, calibré sur la machine qui chiffre, provoque un swap thrash fatal au déchiffrement sur une cible à 1 GB de RAM.
-
Migrer Plausible vers Coolify v4 : 5 pièges en 30 min
Migrer Plausible Analytics vers Coolify v4 : user SSH, proxy, magic env var Traefik et labels, les 5 pièges qui font perdre du temps.
-
Cert wildcard Let’s Encrypt : DNS-01 OVH & catch-all Apache
Cert wildcard Let’s Encrypt via DNS-01 OVH : un vhost Apache catch-all sert tous les sous-domaines avec un seul certificat, sans HTTP-01 par site.
-
OVH DNS via Terraform : refresh zone auto, MX préservés
OVH DNS via Terraform : le provider rafraîchit la zone automatiquement et préserve vos MX, le 403 ovhcloud refresh étant purement cosmétique.
-
Coolify : « Registration is disabled » = email introuvable
Coolify v4 réutilise « Registration is disabled » sur /login quand l’email est absent de la base : explication et diagnostic SQL en 5 sec.
-
ReadyNAS RNDU2000 sous Debian 12 : panneau avant mort
ReadyNAS RNDU2000 réinstallé en Debian 12 + OMV 7 : le bouton et les LED du panneau avant sont invisibles depuis Linux. Contournement via udev.
-
Coolify v4 : le `ports:` du compose n’est PAS ignoré
Coolify v4 lance docker compose up tel quel : le ports: est respecté, pas ignoré au profit de Traefik, et peut entrer en conflit avec un autre service.
-
Coolify v4 + Gitea WG : 2 pièges de validation d’URL
Coolify rejette une URL de repo Gitea en IP privée derrière WireGuard : deux validations bloquantes et leurs contournements (Deploy Key, schéma ssh://).
-
Sync Gitea qui échoue en silence : 3 pièges et la méthode
Sync Gitea qui réussit en HTTP 200 mais ne fait rien : token invalide, filtre owner ignoré, compteur bash en subshell. 3 pièges et la méthode.
-
Gitea : `mirror=true` et `issues=true` incompatibles
Gitea : en mode `mirror: true`, les options issues, PR et labels sont silencieusement ignorées ; seul `mirror: false` importe la meta.
-
Double Gitea mirror : 3 pièges API GitHub & perm `gitea.db`
Mirror double Gitea de 28 repos GitHub en mode PULL : 3 pièges (perm gitea.db, API GitHub, scopes Gitea) et l’archi DR retenue.
-
Backup PULL : clé SSH restreinte avec `from=` + `no-pty`
Backup en mode PULL : le NAS récupère les sauvegardes, le serveur compromis ne peut pas les chiffrer. Clé SSH restreinte avec from= et no-pty.
-
Monitoring perso : l’API SMS gratuite de Free Mobile
Monitoring perso d’un serveur : recevoir une alerte SMS gratuite via l’API Free Mobile depuis un script bash, sans Prometheus ni Twilio.
-
Mirror Docker Hub partagé sur 3 serveurs via mesh WireGuard
Mirror Docker Hub partagé entre 3 serveurs via un mesh WireGuard et un double bind du compose, sans jamais exposer le registry sur Internet.
-
Supabase Coolify : rate limit Docker Hub, mirror local
Supabase dans Coolify refuse de redémarrer : rate limit Docker Hub atteint. Diagnostic des trois pièges et mise en place d’un mirror local.
-
Maïté n’aurait jamais jeté ce NAS
NAS récup : un ReadyNAS Ultra 2 de 2010 sous Debian et OpenMediaVault, 10 W, silencieux, qui sauvegarde sans faillir depuis quatre ans.
-
Le « protocole série propriétaire » qui n’en était pas un
Le « protocole série propriétaire » du ventilateur d’un ReadyNAS Ultra 2 était en fait une puce ITE IT8721 standard, pilotable en sysfs sous Debian.
-
Un NAS aux petits oignons, comme un plat mijoté
NAS basse conso : disques en spindown, ventilateur piloté par les capteurs thermiques et failsafe systemd sur un ReadyNAS sous OpenMediaVault.
-
WireGuard sur Coolify : 2 pièges en 30 minutes
WireGuard sur un serveur Coolify : deux pièges évitables, le conflit de subnet avec les bridges Docker et la limite de 15 caractères de NetworkManager.
-
fancontrol cassé au reboot : hwmonN n’est pas stable
fancontrol et lm-sensors sur un NAS Debian 12 : la numérotation hwmonN change au reboot et casse le service. Fix par détection des chips via name.
-
Reconstruire un RAID1 dégradé : cloner la GPT en 3 commandes
Reconstruire un RAID1 dégradé sur un NAS : cloner la table GPT, régénérer le GUID et relancer le resync mdadm en quelques commandes.
-
`apt install grub-pc` qui se fige sans tty
apt install grub-pc qui se fige sans tty : pourquoi debconf bloque en SSH non interactif et comment débloquer dpkg proprement.
-
Booter un RAID1 dégradé : `rootdelay` + mdadm dans l’initrd
RAID1 dégradé au boot : mdadm dans l’initrd et rootdelay pour laisser le temps d’assembler l’array et monter le rootfs.
-
Clé USB de boot quand le bootloader natif refuse
Booter un NAS Netgear sur clé USB GRUB quand le flash interne refuse, avec un rootfs sur RAID mdadm assemblé depuis le disque SATA.
-
Adaptateur USB-SATA bon marché : l’écriture ment
Adaptateur USB-SATA bon marché : la lecture fonctionne, mais l’écriture est acquittée sans être propagée au disque. Diagnostic et workaround mdadm/ext4.
-
Pousser un binaire en série vers BusyBox, sans réseau
Transférer un binaire vers un shell BusyBox sans réseau ni USB : encodage en \xNN, envoi par chunks sur la console série et contrôle MD5.
-
Le piège du « Chainboot failed! » sur disque GPT
Chainboot failed! sur disque GPT : chain.c32 de syslinux exige une partition active dans le MBR, absente avec une MBR Protective. Solutions.
-
BusyBox recovery sans réseau : transfert via clé USB
BusyBox recovery sans driver Ethernet : comment transférer un fichier vers le flash d’un NAS via une clé USB intermédiaire.
-
Syslinux 3.31, ses faux amis et le mot magique `kernel`
Syslinux 3.31 ignore LOCALBOOT et COM32 : seul KERNEL chain.c32 permet le chainload sur ce bootloader figé, contrairement aux versions récentes.
-
Backup, Reset, et le piège du double bouton
Reset ou Backup sur un NAS Netgear : lequel lance vraiment le boot USB, et pourquoi confondre les deux fait perdre des heures.
-
Quand le boot loader est soudé sur la carte mère
Flash NAND soudé sur la carte mère d’un NAS Netgear : pourquoi le bootloader est irretirable et comment booter Debian malgré tout.
-
Recovery firmware NAS : forcé de booter sous Windows
Recovery firmware NAS Netgear : usbrecovery.exe est Windows-only. Comment restaurer le RAIDiator depuis un laptop Linux via une VM.
-
ext4 64bit : pourquoi un kernel ancien refuse de monter
ext4 64bit : la feature activée par défaut sur les mke2fs récents rend un filesystem inaccessible aux kernels antérieurs à la version 3.7.
-
Le service système qui sabote silencieusement votre install
udisks2 sabote l’install Debian via QEMU sur clé USB : superblock corrompu par l’auto-mount de l’hôte, et comment l’éviter.
-
Shell BusyBox caché derrière un mot de passe non documenté
ReadyNAS bloqué : un shell BusyBox caché en Telnet (root / infr8ntdebug), credential Infrant historique, m’a permis de réparer le boot.
-
Bootloader de 2011 incapable de charger un kernel de 2024
Syslinux 3.31 de 2011 plante en silence sur un kernel Debian moderne : diagnostic du format bzImage et solution par chainload vers GRUB.
-
Une pile à 1€ qui sabote des heures de configuration
Pile CMOS morte sur un vieux NAS : la config BIOS s’efface à chaque coupure de courant. Diagnostic, symptômes et réparation à 1 €.
-
Quand le BIOS ignore sa propre configuration de boot
Le BIOS d’un ReadyNAS Ultra 2 ignore la priorité de boot configurée et démarre toujours son flash interne : pourquoi, et comment chaînloader vers le SATA.
-
Le bouton de reset qui n’en est pas vraiment un
Reset ReadyNAS : ce mode attend un firmware signé Netgear, pas un boot USB générique. Pourquoi ma clé Debian n’a jamais démarré.
-
Pinout de la doc inversé : 6 heures de debug perdues
Console série sur un NAS Netgear ReadyNAS : la doc donnait un pinout inversé, six heures perdues avant que le multimètre ne trouve le bon GND.
-
CI/CD illimité sur GitHub : self-hosted runners en 25 min
Self-hosted runners GitHub Actions : dépasse la limite de 2000 min CI/mois sur tes repos privés et accélère tes pipelines, en 25 min de setup.
-
SnappyMail timeout au login sur OVH : le piège SASL
J’installe SnappyMail (webmail PHP léger) sur un serveur frais. Login : timeout. 0 message d’erreur.
-
Bascule DNS zéro-downtime : la checklist qui marche
Migration de serveur, étape la plus stressante : la bascule DNS. Voici ma checklist 6 étapes pour rendre ça boring.
-
Apache + PaaS moderne : cohabiter sur un seul serveur
Apache et Coolify (Traefik) sur le même serveur : reverse-proxy frontal en 80/443 vers la PaaS en 8080, sans conflit de ports.
-
UUID v7 : pas les 8 premiers caractères pour un ID court
UUID v7 : les 8 premiers caractères encodent l’horodatage et collisionnent. Pour un ID court anti-collision, prenez la queue de l’UUID.
-
Coolify : le PaaS open source qui remplace Vercel et Netlify
Coolify, le PaaS open source self-hosted en « git push = déploiement », remplace Vercel et Netlify pour 0 €/mois avec tes données chez toi.
-
GitHub Actions self-hosted runners : Docker ou systemd ?
Self-hosted runners GitHub Actions : pourquoi Docker casse les jobs avec services et comment systemd règle le problème.
-
OVH : renommer le user debian sans casser sa session SSH
OVH installe Debian avec un user debian imposé : comment le renommer en monuser via systemd-run, sans casser votre session SSH ni les UID.
-
Migrer un serveur de prod en 1 journée : downtime < 10 min
Migrer un serveur de prod auto-hébergé (110 Go) avec moins de 10 min de downtime : rsync incrémental, version-parity et TTL DNS bas.
-
Parser une date FR en PHP : le `!` qui force minuit
Parser une date `d/m/Y` en PHP : le modificateur `!` force minuit, le roundtrip rejette le 31/02, et l’âge se calcule au 1er janvier.
-
Magic strings de session : un SessionManager typé
Magic strings de session éparpillées sur plusieurs contrôleurs : centraliser les clés dans un SessionManager typé pour tuer les typos silencieuses.
-
State machine dans l’agrégat : transitions protégées
State machine dans l’agrégat : exposez des transitions nommées qui valident l’état de départ au lieu d’un setStatus() public.
-
Remplacer un array de constantes par un enum PHP 8.1
Enum PHP 8.1 backed pour remplacer un array de constantes : slug, titre et résolution réunis dans une seule source de vérité.