Skip to content

Commit 4671f38

Browse files
ferr079claude
andcommitted
feat: page /journal + crosslinks entre pages
- Page /journal avec 8 entrées sourcées du journal ops réel (mars 2026) - Collection Astro journal déjà configurée, maintenant alimentée - Lien Journal ajouté dans la navigation - Crosslinks : projets→/securite, symbiose→/projets, about→/infrastructure - Maillage bidirectionnel securite↔cybersecurite déjà en place Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f9b49c2 commit 4671f38

13 files changed

Lines changed: 692 additions & 26 deletions

src/components/Nav.astro

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,22 @@ const { currentPath = '' } = Astro.props;
99
<nav class="site-nav">
1010
<div class="nav-container">
1111
<a href="/" class="nav-brand">
12-
<span class="nav-prompt">$</span> pixelium<span class="nav-dot">.</span>win
12+
<svg class="nav-logo" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
13+
<rect x="0" y="0" width="7" height="7" rx="1" fill="#38bdf8" opacity="0.9" />
14+
<rect x="9" y="0" width="7" height="7" rx="1" fill="#38bdf8" opacity="0.5" />
15+
<rect x="0" y="9" width="7" height="7" rx="1" fill="#38bdf8" opacity="0.5" />
16+
<rect x="9" y="9" width="7" height="7" rx="1" fill="#38bdf8" opacity="0.2" />
17+
</svg>
18+
<span class="nav-text">pixelium<span class="nav-dot">.</span>win</span>
1319
</a>
1420
<div class="nav-links">
1521
<a href="/symbiose" class:list={[{ active: currentPath === '/symbiose' || currentPath === '/symbiose/' }]}>Symbiose</a>
1622
<a href="/projets" class:list={[{ active: currentPath === '/projets' || currentPath === '/projets/' }]}>Projets</a>
1723
<a href="/securite" class:list={[{ active: currentPath === '/securite' || currentPath === '/securite/' }]}>Sécurité</a>
1824
<a href="/cybersecurite" class:list={[{ active: currentPath === '/cybersecurite' || currentPath === '/cybersecurite/' }]}>Cyber</a>
1925
<a href="/ia" class:list={[{ active: currentPath === '/ia' || currentPath === '/ia/' }]}>IA</a>
20-
<a href="/stack" class:list={[{ active: currentPath === '/stack' || currentPath === '/stack/' }]}>Stack</a>
26+
<a href="/infrastructure" class:list={[{ active: currentPath === '/infrastructure' || currentPath === '/infrastructure/' }]}>Infra</a>
27+
<a href="/journal" class:list={[{ active: currentPath === '/journal' || currentPath === '/journal/' }]}>Journal</a>
2128
<a href="/about" class:list={[{ active: currentPath === '/about' || currentPath === '/about/' }]}>À propos</a>
2229
</div>
2330
</div>
@@ -26,8 +33,13 @@ const { currentPath = '' } = Astro.props;
2633
<style>
2734
.site-nav {
2835
padding: 1.25rem 0;
29-
position: relative;
36+
position: sticky;
37+
top: 0;
3038
z-index: 100;
39+
background: rgba(15, 23, 42, 0.95);
40+
backdrop-filter: blur(8px);
41+
-webkit-backdrop-filter: blur(8px);
42+
border-bottom: 1px solid var(--color-border);
3143
}
3244

3345
.nav-container {
@@ -41,19 +53,36 @@ const { currentPath = '' } = Astro.props;
4153

4254
.nav-brand {
4355
font-family: var(--font-mono);
44-
font-size: 0.95rem;
56+
font-size: 1.1rem;
4557
color: var(--color-text);
46-
font-weight: 600;
58+
font-weight: 700;
4759
text-decoration: none;
60+
display: flex;
61+
align-items: center;
62+
gap: 0.5rem;
4863
}
4964

5065
.nav-brand:hover {
5166
color: var(--color-accent);
5267
}
5368

54-
.nav-prompt {
55-
color: var(--color-accent);
56-
margin-right: 0.3rem;
69+
.nav-brand:hover .nav-logo rect {
70+
opacity: 1;
71+
}
72+
73+
.nav-logo {
74+
width: 1.25rem;
75+
height: 1.25rem;
76+
flex-shrink: 0;
77+
transition: filter 0.3s;
78+
}
79+
80+
.nav-logo rect {
81+
transition: opacity 0.3s;
82+
}
83+
84+
.nav-brand:hover .nav-logo {
85+
filter: drop-shadow(0 0 4px rgba(56, 189, 248, 0.5));
5786
}
5887

5988
.nav-dot {
@@ -66,13 +95,15 @@ const { currentPath = '' } = Astro.props;
6695
}
6796

6897
.nav-links a {
69-
font-family: var(--font-mono);
70-
font-size: 0.85rem;
98+
font-family: var(--font-sans);
99+
font-size: 0.95rem;
100+
font-weight: 500;
71101
color: var(--color-text-muted);
72102
text-decoration: none;
73103
padding: 0.25rem 0;
74104
border-bottom: 1px solid transparent;
75105
transition: color 0.2s, border-color 0.2s;
106+
letter-spacing: 0.01em;
76107
}
77108

78109
.nav-links a:hover {
@@ -91,7 +122,7 @@ const { currentPath = '' } = Astro.props;
91122
justify-content: flex-end;
92123
}
93124
.nav-links a {
94-
font-size: 0.75rem;
125+
font-size: 0.8rem;
95126
}
96127
}
97128
</style>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
title: "DNS-over-TLS et DNS secondaire"
3+
date: 2026-03-20
4+
tags: ["dns", "sécurité", "technitium"]
5+
summary: "Déploiement DNS secondaire CT 101 + DoT port 853 + blocklists OISD et Hagezi sur les deux serveurs."
6+
---
7+
8+
Le DNS est critique — c'est le premier service que tout le réseau interroge. J'ai renforcé l'architecture DNS du homelab sur deux axes.
9+
10+
**DNS secondaire (CT 101 sur pve2) :**
11+
- Réplication AXFR automatique depuis le primaire CT 100 (pve1)
12+
- Les nœuds Proxmox et terre2 utilisent les deux serveurs en résolveurs
13+
- Si pve1 tombe, le DNS continue de répondre
14+
15+
**DNS-over-TLS (port 853) :**
16+
- Activé sur les deux serveurs TechnitiumDNS
17+
- terre2 configuré en DoT strict via `systemd-resolved`
18+
- Les requêtes DNS sont chiffrées entre la workstation et les résolveurs
19+
20+
**Blocklists :**
21+
- OISD (full) + Hagezi (Pro) déployées sur les deux instances
22+
- Couverture publicité, tracking, malware et telemetry
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
title: "Lien direct 2.5G entre pve1 et pve2"
3+
date: 2026-03-20
4+
tags: ["réseau", "proxmox", "infrastructure"]
5+
summary: "Câble Ethernet direct entre les deux nœuds principaux — 2.36 Gbps mesurés, 0.17ms de latence."
6+
---
7+
8+
Les deux nœuds Proxmox principaux communiquaient jusque-là via le switch et la Freebox — en gigabit. J'ai configuré un lien direct entre pve1 et pve2 via leurs NICs RTL8125B 2.5GbE.
9+
10+
**Ce qui a été fait :**
11+
- Câble Ethernet direct entre les NICs secondaires (nic1) de pve1 et pve2
12+
- Création du bridge `vmbr1` sur chaque nœud — `10.10.10.1/30``10.10.10.2/30`
13+
- Test de débit : **2.36 Gbps** mesuré avec iperf3, latence **0.17ms**
14+
15+
Ce lien sert aux migrations live de CTs entre nœuds et au trafic de backup, sans saturer le réseau LAN principal.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: "Désactivation de la télémétrie — Loki et Tailscale"
3+
date: 2026-03-21
4+
tags: ["sécurité", "vie-privée", "hardening"]
5+
summary: "Blocage des phone-home de Grafana et Tailscale — le homelab ne fuit pas de données vers l'extérieur."
6+
---
7+
8+
Un self-hosted qui phone-home, c'est un self-hosted qui ne l'est qu'à moitié. Audit et correction de deux services qui envoyaient de la télémétrie.
9+
10+
**Loki (CT 240) :**
11+
- Le binaire Loki contactait `stats.grafana.org` à chaque démarrage
12+
- Résolution DNS bloquée via TechnitiumDNS (enregistrement CNAME vers `0.0.0.0`)
13+
- Configuration ajustée : `analytics.reporting_enabled: false`
14+
15+
**Tailscale/Headscale (CT 106) :**
16+
- Le client Tailscale envoyait des logs à `log.tailscale.com`
17+
- Désactivé via `--no-logs-no-support` dans la configuration du service
18+
- Vérifié : plus aucune connexion sortante vers les serveurs Tailscale
19+
20+
Philosophie : chaque service tourne en local, les données restent en local.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
title: "Beszel — Monitoring agents sur tout le homelab"
3+
date: 2026-03-22
4+
tags: ["monitoring", "ansible", "beszel"]
5+
summary: "Déploiement Beszel sur 32 systèmes via Ansible — dashboard unifié CPU, RAM, disque, réseau."
6+
---
7+
8+
Beszel est un outil de monitoring léger (agent ~5 MB, communication SSH) que j'ai choisi pour remplacer une stack Grafana+Prometheus trop lourde pour le homelab.
9+
10+
**Déploiement :**
11+
- Playbook Ansible `deploy_beszel_agent.yml` exécuté via Semaphore (CT 202)
12+
- 27 CTs/VMs + 3 nœuds Proxmox + OMV + terre2 = **32 systèmes** enregistrés
13+
- Règle firewall Proxmox ajoutée : port 45876/TCP pour la communication agent ↔ hub
14+
15+
**Résultat :**
16+
- 31/32 systèmes UP au premier déploiement
17+
- Dashboard unifié sur `beszel.pixelium.internal` : CPU, RAM, disque, réseau, uptime
18+
- Alertes configurables par seuil (pas encore activées)
19+
20+
Le gotcha principal : l'agent beszel nécessite la variable `KEY` (clé publique du hub) dans son service systemd — sans elle, il crashe silencieusement en boucle.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
title: "Hardening Proxmox — Firewall natif datacenter"
3+
date: 2026-03-22
4+
tags: ["sécurité", "proxmox", "firewall"]
5+
summary: "Firewall Proxmox activé au niveau datacenter et host — IP Sets, Security Groups, politique DROP par défaut."
6+
---
7+
8+
Les trois nœuds Proxmox étaient exposés sur le LAN sans filtrage réseau. J'ai implémenté le firewall natif Proxmox à deux niveaux.
9+
10+
**Niveau datacenter :**
11+
- Politique par défaut : **DROP** en entrée
12+
- IP Sets créés : `management` (terre2, Semaphore), `dns-servers` (CT 100, 101), `web-services` (CT 110)
13+
- Security Groups : SSH+WebUI limités aux IPs de management uniquement
14+
15+
**Niveau host (pve1, pve2, pve3) :**
16+
- Firewall activé sur chaque nœud individuellement
17+
- Règles héritées du datacenter + règles spécifiques par nœud
18+
- Ports Proxmox API (8006), SSH (22), et cluster (corosync) autorisés uniquement depuis les sources légitimes
19+
20+
**Vérification :**
21+
- Connectivité inter-services testée après activation
22+
- Accès WebUI confirmé depuis terre2 uniquement
23+
- Les CTs continuent de communiquer normalement entre eux
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
title: "netboot.xyz — Boot PXE sur le LAN"
3+
date: 2026-03-23
4+
tags: ["infrastructure", "pxe", "commission"]
5+
summary: "CT 188 déployé sur pve1 — les machines du LAN peuvent booter un OS depuis le réseau."
6+
---
7+
8+
Objectif : permettre aux Dell OptiPlex et autres machines du LAN de démarrer un système d'exploitation sans clé USB, directement depuis le réseau.
9+
10+
**Déploiement :**
11+
- CT 188 sur pve1 via script tteck — Debian, 1 vCPU, 512 MB RAM, 8 GB disque
12+
- TFTP (`in.tftpd --secure`) sert le fichier boot depuis `/var/www/html/`
13+
- Freebox configurée en DHCP TFTP : serveur `192.168.1.188`, fichier `netboot.xyz-snp.efi`
14+
15+
**Gotcha résolu :**
16+
- Le fichier boot standard (`.efi`) ne fonctionnait pas sur les Dell OptiPlex — driver UNDI bugué
17+
- Solution : utiliser `netboot.xyz-snp.efi` qui embarque son propre driver réseau (SNP)
18+
- Le flag `firewall=1` sur l'interface `net0` du CT est obligatoire — sans lui, les réponses TFTP sur port éphémère sont bloquées
19+
20+
**Enregistrement complet :**
21+
DNS, clés SSH (terre2 + Semaphore), Ansible, Beszel agent, Homepage, NetBox — le CT est pleinement intégré au homelab.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
title: "Authentik SSO — Semaphore, Proxmox, Jellyfin"
3+
date: 2026-03-25
4+
tags: ["sécurité", "authentik", "sso"]
5+
summary: "OAuth2/OIDC intégré sur 3 services — identité centralisée via Authentik CT 118."
6+
---
7+
8+
Authentik (CT 118) est le fournisseur d'identité centralisé du homelab. Après l'intégration réussie avec Forgejo, j'ai étendu le SSO à trois nouveaux services.
9+
10+
**Intégrations réalisées :**
11+
- **Semaphore** (CT 202) — OAuth2/OIDC, login transparent depuis Authentik
12+
- **Proxmox** (pve1, pve2) — Realm OpenID Connect, les utilisateurs Authentik accèdent à l'interface Proxmox
13+
- **Jellyfin** (CT 220) — SSO plugin, fix critique sur `KnownProxies` pour que les headers `X-Forwarded-Proto` de Traefik soient respectés
14+
15+
**Gotcha Jellyfin :**
16+
Sans la configuration `KnownProxies` dans Jellyfin, le service ignore les headers du reverse proxy et génère des URLs de callback en HTTP au lieu de HTTPS — ce qui casse le flux OAuth silencieusement.
17+
18+
**Résultat :**
19+
Un seul login Authentik donne accès à Forgejo, Semaphore, Proxmox et Jellyfin. Les mots de passe locaux restent en fallback.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
title: "pixelium.win — GitHub Action CI/CD"
3+
date: 2026-03-27
4+
tags: ["cicd", "cloudflare", "déploiement"]
5+
summary: "Pipeline automatisé : git push main → build Astro → deploy Cloudflare Workers en ~35 secondes."
6+
---
7+
8+
Jusqu'ici, le déploiement de pixelium.win nécessitait trois commandes manuelles : build, wrangler deploy, git push. J'ai automatisé la chaîne.
9+
10+
**GitHub Action :**
11+
- Déclenchement : push sur `main`
12+
- Étapes : checkout → Node 22 → `npm ci``npm run build``npx wrangler deploy`
13+
- Durée totale : **~35 secondes**
14+
- Secret : `CLOUDFLARE_API_TOKEN` configuré dans les secrets du repo GitHub
15+
16+
**Résultat :**
17+
Un `git push origin main` suffit — le site est live sur Cloudflare Workers quelques secondes après. Le push Forgejo reste manuel (`git -c http.sslVerify=false push forgejo main`) et ne déclenche pas de deploy.
18+
19+
Ce même site a aussi reçu les logos Simple Icons (via CDN) sur 5 pages et une refonte complète de la page `/infrastructure`.

0 commit comments

Comments
 (0)