- Traefik externalTrafficPolicy: Local → IP client réelle (fin du SNAT kube-proxy) - middleware ratelimit par IP (100/min, burst 200) sur les 6 routes publiques - middleware security-headers (HSTS, nosniff, X-Frame SAMEORIGIN, Referrer-Policy) - TLSOption globale : plancher TLS 1.2 + ciphers modernes - Guacamole REMOTE_IP_VALVE → ban anti-bruteforce par IP (fin du piège n°5) - nftables : fermeture des ports Internet legacy 9080/9081 (HTTP clair redondant) - allowCrossNamespace pour mutualiser les middlewares depuis infra - docs : section Durcissement (public-domain.md) + CAA OVH + pièges à jour Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| admin | ||
| ansible | ||
| archive | ||
| docs | ||
| hermes-skills | ||
| k8s | ||
| progress | ||
| stt | ||
| talos | ||
| tools | ||
| .gitignore | ||
| .mcp.json | ||
| .sops.yaml | ||
| CLAUDE.md | ||
| LICENSE | ||
| Makefile | ||
| PROGRESS.md | ||
| README.md | ||
| requirements.txt | ||
Funk Lab
Homelab IA — Kubernetes (Talos) + GPU AMD + Agent autonome (Hermes)
Vue d'ensemble
Funk est un homelab orienté IA composé de 5 machines physiques :
- un nœud de stockage/passerelle qui héberge tous les services de données et l'agent IA
- un nœud GPU dédié à l'inférence LLM local (AMD RX 6700XT)
- trois nœuds qui forment un cluster Kubernetes (Talos Linux)
L'ensemble est géré en Infrastructure-as-Code : Ansible pour les hôtes AlmaLinux, talhelper pour Talos, ArgoCD pour les workloads Kubernetes.
L'interface du homelab est Asa, un assistant vocal agentique (STT client‑serveur) qui sait interroger l'état live, chercher sur le web et agir sur l'infra — voir Asa (STT).
Architecture
Internet
│
[ Freebox ] 192.168.1.254
│ port 1 · VLAN 1
┌───────────────┴────────────────────────────┐
│ Switch Netgear GS308EV4 │ 8 ports Gigabit · managé Plus
│ 8 ports Access (sans trunk) │ VLAN 1 (Default) + VLAN 10 (cluster-funk)
└───┬───┬─────────────────────────────┬───────┘
VLAN 1 │ │ VLAN 10 │ ports 3-6 · VLAN 10 (cluster 192.168.10.0/24)
enp4s0 │ │ enp6s0f3u2c2 ┌──────────┴───────────────────────┐
(port 2) │ │ (port 7) │ │
┌──┴───┴──┐ [ compute-01 ] [ compute-02 ] [ compute-03 ] [ gpu-01 ]
│storage-01│ 192.168.10.11 192.168.10.12 192.168.10.13 192.168.10.20
│AlmaLinux │ control-plane worker worker llama-server
│Gateway· │ Talos Linux · Kubernetes AMD RX 6700XT
│NAT·DNS· │
│NFS·PG· │
│Qdrant· │
│LiteLLM· │
│Hermes │
└──────────┘
Câblage du switch (Netgear GS308EV4) — tous les ports en mode Access (pas de trunk). storage-01 utilise deux NIC physiques, une par VLAN (pas de sous-interface taguée) :
| Port | Connecté à | IP | VLAN |
|---|---|---|---|
| 1 | Freebox | — | 1 · Default |
| 2 | storage-01 — NIC1 enp4s0 (WAN) |
192.168.1.200 |
1 · Default |
| 3 | gpu-01 | 192.168.10.20 |
10 · cluster-funk |
| 4 | compute-01 (control-plane) | 192.168.10.11 |
10 · cluster-funk |
| 5 | compute-02 (worker) | 192.168.10.12 |
10 · cluster-funk |
| 6 | compute-03 (worker) | 192.168.10.13 |
10 · cluster-funk |
| 7 | storage-01 — NIC2 enp6s0f3u2c2 (LAN cluster) |
192.168.10.1 |
10 · cluster-funk |
| 8 | PC perso (poste admin) | 192.168.1.x |
1 · Default |
storage-01 fait passerelle / NAT entre la VLAN 1 (LAN domestique
192.168.1.0/24, côté Freebox) et la VLAN 10 (cluster192.168.10.0/24).
Stack IA
┌─────────────────────────────────────┐
│ Hermes Agent (storage-01) │
│ │
│ profil funk-ai (Qwen3-8B GPU) │
│ │ ask-agent system/monitor │
│ ▼ │
│ profil system (Qwen3-1.7B CPU) │
│ profil monitor (Qwen3-1.7B CPU) │
│ profil brain (Claude Sonnet API) │
└──────────────┬──────────────────────┘
│
LiteLLM Proxy :4000
│
┌────────────────────┼────────────────────┐
│ │ │
qwen3-8b GPU qwen3-1.7b CPU Claude API
gpu-01 :1234 :1236 system / :1237 monitor Anthropic
| Composant | Rôle | Hôte |
|---|---|---|
| llama-server | Inférence GPU (:1234, qwen3-8b — ROCm 7.x) + embeddings dédiés nomic-embed-text (:1238, CPU) + watchdog/heartbeat. Instances CPU :1236/:1237 (profils system/monitor) manuelles, souvent éteintes |
gpu-01 |
| LiteLLM | Proxy API — routing local/cloud transparent | storage-01 |
| Hermes Agent | Agent IA multi-profils avec mémoire vectorielle | storage-01 |
| ask-agent | Délégation inter-agents (system / monitor / brain) | storage-01 |
| STT | Assistant vocal « Jarvis » — client stt (poste) + STT-server in-cluster |
k8s (ai) |
| Qdrant | Base vectorielle — RAG (funk-docs) + mémoire STT (stt-memory) |
storage-01 |
| PostgreSQL 16 | Persistance Hermes, LiteLLM, n8n, Open WebUI, Ghostfolio | storage-01 |
Profils Hermes
| Profil | Modèle | Usage |
|---|---|---|
funk-ai |
Qwen3-8B GPU (~35 tok/s) | Agent principal — par défaut |
system |
Qwen3-1.7B CPU (~21 tok/s) | Calculs rapides, formatage, résumés |
monitor |
Qwen3-1.7B CPU (~21 tok/s) | Analyse logs, métriques, santé système |
brain |
Claude Sonnet 4.6 (API) | Raisonnement complexe, architecture |
Asa — assistant vocal agentique (STT)
Asa est l'interface vocale et graphique de Funk : un assistant type Jarvis qui écoute,
parle et affiche un HUD animé. Architecture client‑serveur — un client stt (pipx) sur le
poste (voix + HUD), un STT‑server in‑cluster (le « cerveau »). 100 % local (Qwen3‑8B).
Au‑delà du chat, Asa est une véritable agente : le modèle choisit ses outils (function calling) pour répondre à partir de données réelles.
| Capacité | Détail |
|---|---|
| 🔎 Savoir | doc Funk (RAG) + état live (santé machines/GPU, cluster, PromQL) |
| 🌐 Chercher | recherche Internet privée (SearXNG self‑host) |
| 🤖 Agir | actions d'admin via Hermes, toujours derrière une confirmation vocale |
| 🧠 Mémoire | court terme (session) + long terme (Qdrant stt-memory) |
| 🗣️ Veille/réveil | « Asa » réveille · « Asa stop » endort |
📖 Présentation complète (schémas de la chaîne + captures) : docs/stt-presentation.md
· 🗣️ Ce que tu peux lui demander : docs/asa-commandes.md
· Détails techniques : admin/ia/stt.md
Accès & authentification
L'identité est centralisée dans Authentik (IdP OIDC, namespace k8s auth) : chaque
personne a un seul compte, et sa page « My applications » sert de portail — une
tuile par application autorisée, SSO automatique au clic. Tout est exposé sur le
domaine public funklab.online en HTTPS (certificats Let's Encrypt).
Utilisateur ──▶ auth.funklab.online (hub + login unique) ──SSO──▶ app.funklab.online
(LAN ou Internet) (Guacamole, Grafana…)
| Application | URL publique (HTTPS) | Auth |
|---|---|---|
| Authentik — hub + annuaire | auth.funklab.online |
— |
| Guacamole — consoles SSH s01/g01 | portail.funklab.online |
SSO |
| Grafana — dashboards | grafana.funklab.online |
SSO (lab-admins→Admin, sinon Viewer) |
| Open WebUI — chat IA | openwebui.funklab.online |
SSO |
| Argo CD — GitOps | argocd.funklab.online |
SSO (lab-admins) |
| n8n — automatisation | n8n.funklab.online |
login natif |
- Chaîne réseau : DNS OVH
*.funklab.online → 82.67.223.17→ Freebox80/443→ s01 (DNAT nftables + rate-limit) → Traefik (Let's Encrypt HTTP-01) → l'app. En interne, dnsmasq résout*.funklab.online → Traefik(mêmes URLs sur le LAN, split-horizon). - Groupe
lab-admins: admin dans toutes les apps ; les autres comptes = accès simple. - Accès aux machines : Guacamole ouvre un terminal SSH dans le navigateur vers
storage-01 / gpu-01, sous l'utilisateur
console(sans sudo, clé dédiée — rôle Ansibleconsole_user). Accès assignés par utilisateur et journalisés. - Alternative VPN : un serveur WireGuard est prêt sur s01 (profils admin/invité) mais dormant — l'accès distant passe par le domaine public.
En images
Le parcours utilisateur, du login à la console :
📖 Architecture & pièges · 🌐 Domaine public + HTTPS · 🛠️ Administration (utilisateurs, apps du hub) · 👤 Guide utilisateur à distribuer · 🔐 WireGuard
Infrastructure
Machines
| Machine | IP | OS | RAM | Rôle |
|---|---|---|---|---|
| storage-01 | 192.168.10.1 | AlmaLinux 9.8 | 32 GB | Gateway · NFS · Services IA |
| gpu-01 | 192.168.10.20 | AlmaLinux 9.8 | 32 GB | Inférence LLM (RX 6700XT) |
| compute-01 | 192.168.10.11 | Talos v1.13 (k8s v1.33.1) | 16 GB | k8s control-plane |
| compute-02 | 192.168.10.12 | Talos v1.13 (k8s v1.33.1) | 8 GB | k8s worker |
| compute-03 | 192.168.10.13 | Talos v1.13 (k8s v1.33.1) | 8 GB | k8s worker |
Stockage
- NVMe système (
/home/data, ~845 GB XFS) — bind-monté sur/srv/datadepuis 2026-05-29 - RAID5 logiciel (
md0) — 4 × 1 TB SATA, actif mais plus monté (sdb ATA errors + sdd retiré) - Point de montage
/srv/data— héberge modèles LLM, bases de données, données Hermes
Organisation du repo
├── ansible/ # Gestion storage-01 + gpu-01 (AlmaLinux)
│ ├── inventory.yml
│ ├── playbooks/
│ │ ├── storage-01.yml
│ │ └── gpu-01.yml
│ ├── group_vars/ # Variables globales + vault chiffré
│ ├── host_vars/ # Variables par machine
│ └── roles/
│ ├── common # Paquets, sécurité, NTP
│ ├── gateway # nftables + NAT
│ ├── dnsmasq # DNS local (lab.local)
│ ├── nfs_server # Exports NFS (modèles, k8s)
│ ├── nfs_client # Montages NFS sur gpu-01
│ ├── rocm # Stack GPU AMD (ROCm 7.x)
│ ├── llama_server # Inférence LLM + embeddings
│ ├── litellm # Proxy LLM + script ask-agent
│ ├── hermes_agent # Agent IA autonome
│ ├── hermes_user # User hermes + SSH partagé entre hosts
│ ├── rag # RAG : scripts rag-ingest/rag-query + skill Hermes
│ ├── alertmanager_webhook # Pont AlertManager → ask-agent
│ ├── postfix_relay # SMTP sortant via Gmail
│ ├── node_exporter # Métriques Prometheus
│ ├── minio # ⚠️ placeholder vide — service non déployé
│ ├── postgresql # Base de données
│ ├── qdrant # Base vectorielle
│ ├── hermes_auto_improve # Worker analyse doc + trigger server :9095
│ ├── hermes_exec # Exécuteur d'actions vocales (jeton, :9096)
│ ├── console_user # User `console` sans sudo (consoles SSH du portail)
│ ├── wireguard # VPN accès distant (51820/udp — dormant)
│ └── satisfactory_server # Serveur de jeu dédié sur gpu-01 (:7777)
├── hermes-skills/ # Skills Hermes versionnés
│ ├── funk/
│ │ ├── agent-delegation/ # Délégation ask-agent (system/monitor/brain)
│ │ └── rag-docs/ # Usage de rag-query
│ └── souls/ # Prompts système par profil (funk-ai, system, monitor, brain)
├── tools/ # Sources des outils déployés
│ ├── hermes-auto-improve/ # auto-improve.py + trigger-server.py
│ └── hermes-voice/ # Client vocal Hermes (CLI faster-whisper + Piper)
├── stt/ # Asa — assistant vocal agentique (voir docs/stt-presentation.md)
│ ├── client/ # commande `stt` (pipx) : voix (VAD/wake/ASR/TTS) + HUD web
│ └── server/ # STT-server (conteneur, ns ai) : brain + tools + RAG + mémoire
├── admin/ # Base de connaissance (indexée dans le RAG)
├── docs/ # Présentations & schémas (stt-presentation.md, images)
├── progress/ # Journaux de session (référencés par PROGRESS.md)
├── archive/ # Documents historiques obsolètes (conception d'origine) — ne fait pas foi
├── talos/ # Cluster Kubernetes (talhelper)
└── k8s/ # Workloads ArgoCD
├── infra/ # monitoring, nfs-provisioner (Traefik + MetalLB via helm au bootstrap)
└── apps/ # Open WebUI, n8n, STT, SearXNG, Ghostfolio, finlab,
# Authentik + Guacamole (portail, ns auth), external-services
Démarrage rapide
Pré-requis
pip install ansible
ansible-galaxy collection install ansible.posix community.general community.postgresql
Déployer storage-01
cd ansible/
ansible-playbook -i inventory.yml playbooks/storage-01.yml
Déployer gpu-01
ansible-playbook -i inventory.yml playbooks/gpu-01.yml
Déployer un rôle spécifique
ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags litellm
ansible-playbook -i inventory.yml playbooks/gpu-01.yml --tags llama_server
Gestion du cluster
funk-start # Allume gpu-01 (WOL) + démarre tous les services
funk-start --k8s # Idem + démarre les nœuds k8s
funk-stop # Arrêt propre
funk-stop --k8s # Arrêt propre + éteint k8s avant
funk-status # État de tous les services (13 checks)
Détail complet des procédures : admin/ops/cluster.md
Secrets
Les secrets sont gérés via Ansible Vault (chiffrement AES256).
# Chiffrer le vault
ansible-vault encrypt ansible/group_vars/all/vault.yml
# Editer les secrets
ansible-vault edit ansible/group_vars/all/vault.yml
Variables stockées dans le vault : clé API Anthropic, mots de passe PostgreSQL (hermes, litellm, n8n, openwebui, ghostfolio, authentik, guacamole), App Password Gmail, clé API n8n, jeton hermes-exec, clé SSH du user console, secrets Authentik (copies des secrets k8s), secrets clients OIDC des apps du hub (grafana, openwebui, argocd) et clés WireGuard. Liste exhaustive : CLAUDE.md § Secrets Ansible Vault.
Contrainte GPU
La RX 6700XT (gfx1031) n'est pas officiellement supportée par ROCm. La variable suivante est obligatoire dans tous les services GPU :
HSA_OVERRIDE_GFX_VERSION=10.3.0
Elle est gérée automatiquement par le rôle Ansible llama_server.
Roadmap
- Ansible — storage-01 (gateway, NFS, PostgreSQL, Qdrant, LiteLLM, Hermes, postfix, AlertManager webhook)
- Ansible — gpu-01 (ROCm, llama-server : GPU :1234 + embeddings :1238 via le rôle ; 2× CPU manuels)
- Stack IA opérationnelle (Hermes multi-profils + Qwen3 + Claude API)
- Délégation inter-agents (
ask-agent+ skillagent-delegation) - RAG opérationnel — Qdrant ~436 chunks (embeddings nomic-embed-text
:1238, dim 768),rag-query/rag-ingest - User
hermesavec SSH partagé entre storage-01 et gpu-01 - Cluster Kubernetes opérationnel (Talos v1.13 + talhelper)
- MetalLB + Traefik + wildcard DNS
lab.local - Monitoring complet (kube-prometheus-stack + AlertManager → Hermes + n8n)
- Open WebUI (
openwebui.lab.local, namespaceai) - n8n (
n8n.lab.local, namespaceai, 3 workflows actifs) - Email sortant — Postfix relay → Gmail SMTP
- hermes-auto-improve — analyse quotidienne de la doc par Hermes (n8n 22h → PR
hermes/daily-work) - Ghostfolio — suivi de portefeuille (
ghostfolio.lab.local, PostgreSQL s01 + Redis) - STT — assistant vocal « Jarvis » (client
stt+ STT-server in-cluster, mémoire Qdrantstt-memory) - Modèle d'embedding dédié — nomic-embed-text sur gpu-01
:1238(utilisé par la mémoire STT et le RAG) - Réparer Qdrant — crash-loop résolu 2026-06-17 ; collection
funk-docsreconstruite depuis (436 chunks) - Re-ingérer le RAG (
rag-ingest) basculé sur l'embedding dédié:1238(dim 768) - Serveur dédié Satisfactory sur gpu-01 (
kaya.freeboxos.fr:7777, IPv4 full-stack) - Annuaire Authentik + portail consoles Guacamole (SSO, namespace
auth) - VPN WireGuard sur s01 (profils admin/invité) — dormant, prêt à activer
- Domaine public
funklab.online+ HTTPS (Let's Encrypt HTTP-01 sur Traefik, DNS OVH wildcard, Freebox 80/443) - Hub SSO complet : Grafana, Open WebUI, Argo CD en OIDC + n8n (login natif) sur
*.funklab.online; groupelab-admins= admin partout - WOL compute nodes (configuration BIOS)
- MFA/TOTP Authentik (durcissement)
- Proxy Provider Authentik pour exposer les apps sans login (Prometheus, Alertmanager, SearXNG)




