33800 Docs

← Retour

Proposition : Infrastructure Rhinov - Stack Complète

Date : 02-01-2026 Demandeur : gouroubleu Statut : EN ATTENTE DE VALIDATION


Résumé

Mise en place d'une infrastructure Docker complète pour Rhinov, inspirée de 33800-stack, avec :

LLM par défaut : Gemini (Google) - Claude (Anthropic) disponible en alternative


1. Architecture Globale

Concept : 4 environnements (Blue-Green)

┌──────────────────────────────────────────────────────────────────────────────────────────┐
│                                                                                          │
│   ┌──────────────┐   ┌──────────────┐   ┌──────────────┐   ┌──────────────┐             │
│   │  DEV-STACK   │   │ PROD-NEW     │   │ PROD-CURRENT │   │ PROD LIVE    │             │
│   │  (interne)   │   │ (interne)    │   │ (interne)    │   │ (publique)   │             │
│   │              │   │              │   │              │   │              │             │
│   │ *.dev.rhinov │──▶│ *.new.rhinov │──▶│ *.cur.rhinov │◀──│ *.rhinov.fr  │             │
│   │    .local    │   │    .local    │   │    .local    │   │              │             │
│   │              │   │              │   │              │   │              │             │
│   │ Développement│   │ Prochaine    │   │ Miroir exact │   │ Production   │             │
│   │ Tests/Debug  │   │ version      │   │ de LIVE      │   │ Clients      │             │
│   └──────────────┘   └──────────────┘   └──────────────┘   └──────────────┘             │
│                                                │                   │                    │
│                                                └───────────────────┘                    │
│                                                    SYNCHRONISÉS                         │
│                                                                                          │
│   RÉSEAU INTERNE RHINOV                                             INTERNET            │
└──────────────────────────────────────────────────────────────────────────────────────────┘
Environnement Accès Domaine Usage
DEV-STACK Réseau interne *.dev.rhinov.local Développement, tests, debug
PROD-NEW-STACK Réseau interne *.new.rhinov.local Prochaine version en préparation
PROD-CURRENT-STACK Réseau interne *.cur.rhinov.local Miroir exact de ce qui est LIVE
PROD LIVE Internet *.rhinov.fr Production publique, clients

Flux de déploiement (Blue-Green)

                                    ┌─────────────────────────────────────────┐
                                    │           CYCLE DE RELEASE              │
                                    └─────────────────────────────────────────┘

     ┌──────────┐      ┌──────────┐      ┌──────────────┐      ┌──────────────┐
     │   DEV    │      │ PROD-NEW │      │ PROD-CURRENT │      │  PROD LIVE   │
     │  STACK   │      │  STACK   │      │    STACK     │      │ *.rhinov.fr  │
     └────┬─────┘      └────┬─────┘      └──────┬───────┘      └──────┬───────┘
          │                 │                   │                     │
    1. Develop              │                   │                     │
          │                 │                   │                     │
          ├────────────────▶│                   │                     │
          │            2. Deploy                │                     │
          │              to NEW                 │                     │
          │                 │                   │                     │
          │                 │ 3. Validation OK  │                     │
          │                 ├──────────────────▶│                     │
          │                 │                   │                     │
          │                 │                   │ 4. Bascule          │
          │                 │                   ├────────────────────▶│
          │                 │                   │    (même images)    │
          │                 │                   │                     │
          │                 │◀──────────────────┤                     │
          │                 │  5. NEW devient   │                     │
          │                 │     "vide" pour   │                     │
          │                 │     prochaine     │                     │
          │                 │     release       │                     │

États possibles

Situation DEV PROD-NEW PROD-CURRENT PROD LIVE
Normal v2.1-dev v2.0-rc1 v1.9 v1.9
Après bascule v2.1-dev (vide) v2.0 v2.0
Rollback urgent - - v1.9 v1.9

Règle d'or : PROD-CURRENT et PROD LIVE sont toujours synchronisés. Si LIVE = v1.9, alors CURRENT = v1.9.

Schéma réseau détaillé

                                         INTERNET
                                             │
                        ┌────────────────────┴────────────────────┐
                        │          FIREWALL / ROUTEUR             │
                        │            (IP publique)                │
                        └────────────────────┬────────────────────┘
                                             │
                                             │ NAT/Port forward :443 :80
                                             │ (uniquement vers NGINX-PUB)
                                             ▼
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│                           RÉSEAU INTERNE RHINOV                                         │
│                           192.168.X.0/24                                                │
│                                                                                         │
│  ┌───────────────────────────────────────────────────────────────────────────────────┐ │
│  │                              PROXMOX VE                                           │ │
│  │                                                                                   │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │ │
│  │  │    VM-IA     │  │  NGINX-INT   │  │  NGINX-PUB   │  │   DNS-INT    │          │ │
│  │  │    .10       │  │    .11       │  │    .12       │  │    .13       │          │ │
│  │  │              │  │              │  │              │  │              │          │ │
│  │  │ Claude/Gemini│  │ Proxy interne│  │ Proxy LIVE   │  │  dnsmasq     │          │ │
│  │  │ Orchestration│  │ DEV+NEW+CUR  │  │ *.rhinov.fr  │  │  *.local     │          │ │
│  │  └──────────────┘  └──────────────┘  └──────────────┘  └──────────────┘          │ │
│  │                                                                                   │ │
│  │  ┌────────────────────┐  ┌────────────────────┐  ┌────────────────────┐          │ │
│  │  │     DEV-STACK      │  │  PROD-NEW-STACK    │  │ PROD-CURRENT-STACK │          │ │
│  │  │                    │  │                    │  │                    │          │ │
│  │  │ ┌──────┐ ┌──────┐  │  │ ┌──────┐ ┌──────┐  │  │ ┌──────┐ ┌──────┐  │          │ │
│  │  │ │DEV-01│ │DEV-02│  │  │ │NEW-01│ │NEW-02│  │  │ │CUR-01│ │CUR-02│  │          │ │
│  │  │ │ .20  │ │ .21  │  │  │ │ .30  │ │ .31  │  │  │ │ .40  │ │ .41  │  │          │ │
│  │  │ └──────┘ └──────┘  │  │ └──────┘ └──────┘  │  │ └──────┘ └──────┘  │          │ │
│  │  │                    │  │                    │  │                    │          │ │
│  │  │ *.dev.rhinov.local │  │ *.new.rhinov.local │  │ *.cur.rhinov.local │          │ │
│  │  │ (développement)    │  │ (prochaine version)│  │ (miroir LIVE)      │          │ │
│  │  └────────────────────┘  └────────────────────┘  └────────────────────┘          │ │
│  │                                                            ║                      │ │
│  │                                                            ║ SYNC                 │ │
│  │                                                            ▼                      │ │
│  │                                                   ┌────────────────┐              │ │
│  │                                                   │  PROD LIVE     │              │ │
│  │                                                   │  *.rhinov.fr   │              │ │
│  │                                                   │  (via NGINX-PUB)              │ │
│  │                                                   └────────────────┘              │ │
│  │                                                                                   │ │
│  │  ┌────────────────────────────────────────────────────────────────────────────┐  │ │
│  │  │                         STOCKAGE ZFS + NFS                                 │  │ │
│  │  │  /rhinov-stack/                                                            │  │ │
│  │  │  ├── docker/dev/          (data DEV-STACK)                                 │  │ │
│  │  │  ├── docker/prod-new/     (data PROD-NEW-STACK)                            │  │ │
│  │  │  ├── docker/prod-current/ (data PROD-CURRENT-STACK = LIVE)                 │  │ │
│  │  │  ├── secrets/                                                              │  │ │
│  │  │  └── ...                                                                   │  │ │
│  │  └────────────────────────────────────────────────────────────────────────────┘  │ │
│  └───────────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                         │
│  ┌───────────────────────────────────────────────────────────────────────────────────┐ │
│  │                         VMs WINDOWS RENDU 3D                                      │ │
│  │   WIN-3D-01 (.60)    WIN-3D-02 (.61)    WIN-3D-03 (.62)   ...                    │ │
│  └───────────────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────────┘

2. Plan d'adressage IP (à adapter)

VMs Infrastructure

VM Hostname IP suggérée mDNS Rôle
VM-IA ia 192.168.X.10 ia.local Orchestration LLM (Claude/Gemini)
NGINX-INT nginx-int 192.168.X.11 nginx-int.local Reverse Proxy interne (DEV + NEW + CUR)
NGINX-PUB nginx-pub 192.168.X.12 nginx-pub.local Reverse Proxy public (PROD LIVE)
DNS-INT dns 192.168.X.13 dns.local DNS interne (dnsmasq)

VMs DEV-STACK (développement)

VM Hostname IP suggérée mDNS Rôle
DEV-01 dev-01 192.168.X.20 dev-01.local Portainer DEV #1
DEV-02 dev-02 192.168.X.21 dev-02.local Portainer DEV #2 (futur)
DEV-03 dev-03 192.168.X.22 dev-03.local Portainer DEV #3 (futur)
DEV-04 dev-04 192.168.X.23 dev-04.local Portainer DEV #4 (futur)
DEV-05 dev-05 192.168.X.24 dev-05.local Portainer DEV #5 (futur)

VMs PROD-NEW-STACK (prochaine version)

VM Hostname IP suggérée mDNS Rôle
NEW-01 new-01 192.168.X.30 new-01.local Portainer PROD-NEW #1
NEW-02 new-02 192.168.X.31 new-02.local Portainer PROD-NEW #2 (futur)
NEW-03 new-03 192.168.X.32 new-03.local Portainer PROD-NEW #3 (futur)
NEW-04 new-04 192.168.X.33 new-04.local Portainer PROD-NEW #4 (futur)
NEW-05 new-05 192.168.X.34 new-05.local Portainer PROD-NEW #5 (futur)

VMs PROD-CURRENT-STACK (miroir de LIVE)

VM Hostname IP suggérée mDNS Rôle
CUR-01 cur-01 192.168.X.40 cur-01.local Portainer PROD-CURRENT #1
CUR-02 cur-02 192.168.X.41 cur-02.local Portainer PROD-CURRENT #2 (futur)
CUR-03 cur-03 192.168.X.42 cur-03.local Portainer PROD-CURRENT #3 (futur)
CUR-04 cur-04 192.168.X.43 cur-04.local Portainer PROD-CURRENT #4 (futur)
CUR-05 cur-05 192.168.X.44 cur-05.local Portainer PROD-CURRENT #5 (futur)

VMs Windows Rendu 3D

VM Hostname IP suggérée mDNS GPU
WIN-3D-01 win3d-01 192.168.X.60 win3d-01.local NVIDIA RTX
WIN-3D-02 win3d-02 192.168.X.61 win3d-02.local NVIDIA RTX
WIN-3D-03 win3d-03 192.168.X.62 win3d-03.local NVIDIA RTX
... ... ... ... ...

Convention de nommage des services

Environnement Format domaine Exemple Accès
DEV-STACK {service}.dev.rhinov.local api.dev.rhinov.local Interne
PROD-NEW-STACK {service}.new.rhinov.local api.new.rhinov.local Interne
PROD-CURRENT-STACK {service}.cur.rhinov.local api.cur.rhinov.local Interne
PROD LIVE {service}.rhinov.fr api.rhinov.fr Internet

Règle : PROD-CURRENT = miroir exact de PROD LIVE. Même images Docker, même configs (seul le domaine diffère).


3. Spécifications des VMs

VM-IA (Orchestration LLM)

Propriété Valeur
OS Debian 12 (bookworm)
CPU 2 vCPU
RAM 4 Go
Disque 32 Go
User rhinov (sudoer)
Rôle LLM (Claude/Gemini) + Scripts + SSH vers toutes VMs

Packages :

Configuration LLM :

# /mnt/rhinov-stack/secrets/llm.env
LLM_PROVIDER=gemini              # gemini (défaut) ou claude
GOOGLE_API_KEY=AIza...           # Gemini (requis)
ANTHROPIC_API_KEY=sk-ant-...     # Claude (optionnel, si switch)

DNS-INT (DNS Interne)

Propriété Valeur
OS Debian 12 (bookworm)
CPU 1 vCPU
RAM 512 Mo
Disque 10 Go
User rhinov (sudoer)
Rôle Résolution DNS interne (dnsmasq)

Configuration dnsmasq :

# /etc/dnsmasq.d/rhinov.conf

# ========================================
# WILDCARDS ENVIRONNEMENTS → NGINX-INT
# ========================================
# DEV-STACK
address=/.dev.rhinov.local/192.168.X.11

# PROD-NEW-STACK (prochaine version)
address=/.new.rhinov.local/192.168.X.11

# PROD-CURRENT-STACK (miroir LIVE)
address=/.cur.rhinov.local/192.168.X.11

# ========================================
# MACHINES INDIVIDUELLES
# ========================================
# Infrastructure
address=/ia.local/192.168.X.10
address=/nginx-int.local/192.168.X.11
address=/nginx-pub.local/192.168.X.12
address=/dns.local/192.168.X.13

# DEV-STACK
address=/dev-01.local/192.168.X.20
address=/dev-02.local/192.168.X.21

# PROD-NEW-STACK
address=/new-01.local/192.168.X.30
address=/new-02.local/192.168.X.31

# PROD-CURRENT-STACK
address=/cur-01.local/192.168.X.40
address=/cur-02.local/192.168.X.41

# Windows 3D
address=/win3d-01.local/192.168.X.60
address=/win3d-02.local/192.168.X.61

Usage : Toutes les machines du réseau utilisent DNS-INT comme serveur DNS primaire (192.168.X.13).

NGINX-INT (Reverse Proxy Interne)

Propriété Valeur
OS Debian 12 (bookworm)
CPU 2 vCPU
RAM 2 Go
Disque 20 Go
User rhinov (sudoer)
Rôle Nginx + Certbot + SSL Wildcard

Packages :

VM-DEV-01 (Portainer DEV)

Propriété Valeur
OS Debian 12 (bookworm)
CPU 4 vCPU
RAM 8 Go
Disque 50 Go
User rhinov (sudoer)
Rôle Docker + Portainer DEV

Docker data-root : /mnt/nfs/rhinov-stack/docker/dev/

VM-PROD-01 (Portainer PROD)

Propriété Valeur
OS Debian 12 (bookworm)
CPU 4 vCPU
RAM 8 Go
Disque 50 Go
User rhinov (sudoer)
Rôle Docker + Portainer PROD

Docker data-root : /mnt/nfs/rhinov-stack/docker/prod/


4. Structure NFS

/rhinov-stack/
├── docker/
│   ├── dev/                    # data-root Docker DEV
│   ├── prod/                   # data-root Docker PROD
│   ├── secrets/
│   │   ├── dev.env             # Variables DEV
│   │   └── prod.env            # Variables PROD
│   ├── shortcuts/              # Dockerfiles templates
│   │   ├── node/
│   │   ├── bun/
│   │   └── qwik/
│   └── stacks/                 # Compose files
│
├── scripts/
│   ├── setup/                  # Scripts d'installation
│   │   ├── 01-proxmox-init.sh
│   │   ├── 02-vm-claude.sh
│   │   ├── 03-vm-nginx.sh
│   │   ├── 04-vm-dev.sh
│   │   └── 05-vm-prod.sh
│   ├── nginx/                  # Génération configs Nginx
│   ├── dns/                    # Scripts DNS Gandi/OVH
│   ├── docker/                 # Management Docker
│   ├── deploy/                 # Déploiement automatisé
│   └── lib/                    # Fonctions partagées
│
├── claude/
│   ├── propositions/           # Propositions Claude
│   ├── tasks/                  # Tâches en cours
│   ├── backlog/                # Backlog
│   └── CLAUDE.md               # Instructions Claude
│
├── databases/
│   ├── dev/                    # Données DB DEV
│   └── prod/                   # Données DB PROD
│
└── docs/                       # Documentation

5. Fichier .env Template

secrets/template.env (À REMPLIR PAR EDOUARD)

# ============================================
# RHINOV STACK - VARIABLES D'ENVIRONNEMENT
# ============================================
# Ce fichier doit être copié en dev.env et prod.env
# avec les valeurs appropriées pour chaque environnement
# ============================================

# -----------------------------
# INFRASTRUCTURE
# -----------------------------
STACK_ENV=dev                          # dev ou prod
STACK_DOMAIN=rhinov.fr                 # Domaine principal
STACK_WILDCARD=*.stack.rhinov.fr       # Wildcard pour les services

# -----------------------------
# PROXMOX
# -----------------------------
PROXMOX_HOST=192.168.X.1
PROXMOX_USER=root@pam
PROXMOX_TOKEN_ID=rhinov-stack
PROXMOX_TOKEN_SECRET=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

# -----------------------------
# VMS - IPs
# -----------------------------
VM_CLAUDE_IP=192.168.X.10
VM_NGINX_IP=192.168.X.11
VM_DEV_01_IP=192.168.X.20
VM_PROD_01_IP=192.168.X.30

# -----------------------------
# SSH
# -----------------------------
SSH_USER=rhinov
SSH_KEY_PATH=/home/rhinov/.ssh/id_ed25519

# -----------------------------
# PORTAINER
# -----------------------------
PORTAINER_DEV_URL=https://192.168.X.20:9443
PORTAINER_DEV_API_KEY=ptr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
PORTAINER_PROD_URL=https://192.168.X.30:9443
PORTAINER_PROD_API_KEY=ptr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# -----------------------------
# DNS - GANDI
# -----------------------------
GANDI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxx
GANDI_DOMAIN=rhinov.fr
GANDI_SHARING_ID=                      # Si compte organisation

# -----------------------------
# DNS - OVH
# -----------------------------
OVH_ENDPOINT=ovh-eu
OVH_APPLICATION_KEY=xxxxxxxxxxxxxxxx
OVH_APPLICATION_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
OVH_CONSUMER_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
OVH_DOMAIN=rhinov.com

# -----------------------------
# EMAIL - MAILJET
# -----------------------------
MAILJET_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MAILJET_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
MAILJET_SENDER_EMAIL=noreply@rhinov.fr
MAILJET_SENDER_NAME=Rhinov

# -----------------------------
# NOTIFICATIONS - NTFY
# -----------------------------
NTFY_SERVER=https://ntfy.sh            # ou serveur self-hosted
NTFY_TOPIC=rhinov-stack
NTFY_TOKEN=tk_xxxxxxxxxxxxxxxxxxxxxxxx  # si auth requise

# -----------------------------
# NOTIFICATIONS - TELEGRAM
# -----------------------------
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
TELEGRAM_CHAT_ID=-123456789            # ID du groupe/channel

# -----------------------------
# DATABASES (si utilisées)
# -----------------------------
# PostgreSQL
POSTGRES_HOST=
POSTGRES_PORT=5432
POSTGRES_USER=
POSTGRES_PASSWORD=
POSTGRES_DB=

# Redis
REDIS_HOST=
REDIS_PORT=6379
REDIS_PASSWORD=

# -----------------------------
# GITLAB (si utilisé)
# -----------------------------
GITLAB_URL=https://gitlab.rhinov.fr
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx

# -----------------------------
# GITHUB (si utilisé)
# -----------------------------
GITHUB_USER=
GITHUB_PAT=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# -----------------------------
# SSL CERTIFICATES
# -----------------------------
SSL_EMAIL=admin@rhinov.fr
SSL_CERT_PATH=/etc/letsencrypt/live/${STACK_WILDCARD}/

6. Sécurité et Accès

Principe de sécurité

┌─────────────────────────────────────────────────────────────────┐
│                    UTILISATEUR HUMAIN                           │
│                    (compte: edouard)                            │
│                                                                 │
│  - Accès root sur toutes les VMs                               │
│  - Peut désactiver Claude à tout moment                        │
│  - Détient les clés SSH master                                 │
└─────────────────────────────┬───────────────────────────────────┘
                              │
                              │ Peut révoquer l'accès
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    COMPTE CLAUDE                                │
│                    (compte: rhinov)                             │
│                                                                 │
│  - Sudo SANS password sur VM-CLAUDE uniquement                 │
│  - SSH vers autres VMs avec clé dédiée                         │
│  - Droits limités (pas de rm -rf /, pas de reboot Proxmox)     │
│  - Toutes les actions loguées                                  │
└─────────────────────────────────────────────────────────────────┘

Fichier sudoers pour Claude (sur VM-CLAUDE)

# /etc/sudoers.d/rhinov-claude
rhinov ALL=(ALL) NOPASSWD: ALL

# Commandes interdites (blacklist)
rhinov ALL=(ALL) !NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/init, /usr/bin/rm -rf /

Clés SSH

Clé Usage
/home/rhinov/.ssh/id_ed25519 Clé Claude → autres VMs
/home/edouard/.ssh/id_ed25519 Clé admin → toutes VMs

Logging des actions Claude

Toutes les commandes exécutées par Claude sont loguées dans :


7. Scripts d'Installation

7.1 Script Proxmox Init

#!/bin/bash
# 01-proxmox-init.sh
# À exécuter sur le Proxmox

set -e

# Création du pool ZFS (si pas déjà fait)
# zpool create rhinov-pool /dev/sdX

# Création du dataset NFS
zfs create rhinov-pool/rhinov-stack
zfs set sharenfs="rw=@192.168.X.0/24,no_root_squash" rhinov-pool/rhinov-stack

# Structure de base
mkdir -p /rhinov-pool/rhinov-stack/{docker/{dev,prod,secrets,shortcuts,stacks},scripts/{setup,nginx,dns,docker,deploy,lib},claude/{propositions,tasks,backlog},databases/{dev,prod},docs}

# Templates VMs Debian 12
pveam download local debian-12-standard_12.2-1_amd64.tar.zst 2>/dev/null || true

echo "Proxmox initialisé. Créer les VMs avec les scripts suivants."

7.2 Script VM Claude

#!/bin/bash
# 02-vm-claude.sh
# À exécuter sur la VM Claude après installation Debian

set -e

# Variables
NFS_SERVER="192.168.X.1"
NFS_PATH="/rhinov-pool/rhinov-stack"
MOUNT_POINT="/mnt/rhinov-stack"

# Mise à jour
apt update && apt upgrade -y

# Packages essentiels
apt install -y \
    git curl wget jq htop tree \
    sudo openssh-server \
    nfs-common autofs \
    avahi-daemon libnss-mdns

# Création utilisateur rhinov
useradd -m -s /bin/bash rhinov
echo "rhinov ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/rhinov-claude

# Configuration SSH
mkdir -p /home/rhinov/.ssh
ssh-keygen -t ed25519 -N "" -f /home/rhinov/.ssh/id_ed25519
chown -R rhinov:rhinov /home/rhinov/.ssh
chmod 700 /home/rhinov/.ssh
chmod 600 /home/rhinov/.ssh/id_ed25519

# Montage NFS
mkdir -p $MOUNT_POINT
echo "$NFS_SERVER:$NFS_PATH $MOUNT_POINT nfs defaults,_netdev 0 0" >> /etc/fstab
mount -a

# Symlinks Claude
ln -sf $MOUNT_POINT/claude/propositions /home/rhinov/propositions
ln -sf $MOUNT_POINT/claude/tasks /home/rhinov/tasks
ln -sf $MOUNT_POINT/claude/backlog /home/rhinov/backlog

# Installation Node.js (pour Claude Code)
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs

# Installation Claude Code (à adapter selon la méthode officielle)
# npm install -g @anthropic-ai/claude-code

# mDNS
hostnamectl set-hostname claude
systemctl enable avahi-daemon
systemctl start avahi-daemon

# Logging des actions
cat > /etc/rsyslog.d/claude-actions.conf << 'EOF'
if $programname == 'sudo' and $msg contains 'rhinov' then /var/log/claude-actions.log
EOF
systemctl restart rsyslog

echo "VM Claude configurée. Clé publique à distribuer :"
cat /home/rhinov/.ssh/id_ed25519.pub

7.3 Script VM Nginx

#!/bin/bash
# 03-vm-nginx.sh
# À exécuter sur la VM Nginx après installation Debian

set -e

# Variables
NFS_SERVER="192.168.X.1"
NFS_PATH="/rhinov-pool/rhinov-stack"

# Mise à jour
apt update && apt upgrade -y

# Packages
apt install -y \
    nginx certbot python3-certbot-nginx \
    sudo openssh-server \
    nfs-common \
    avahi-daemon libnss-mdns

# Création utilisateur rhinov
useradd -m -s /bin/bash rhinov
usermod -aG sudo rhinov

# Configuration SSH (accepter clé Claude)
mkdir -p /home/rhinov/.ssh
# La clé publique de Claude sera ajoutée ici
chown -R rhinov:rhinov /home/rhinov/.ssh
chmod 700 /home/rhinov/.ssh

# Montage NFS (lecture seule pour les configs)
mkdir -p /mnt/rhinov-stack
echo "$NFS_SERVER:$NFS_PATH /mnt/rhinov-stack nfs defaults,ro,_netdev 0 0" >> /etc/fstab
mount -a

# Configuration Nginx de base
cat > /etc/nginx/nginx.conf << 'EOF'
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 1024;
}

http {
    sendfile on;
    tcp_nopush on;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}
EOF

# mDNS
hostnamectl set-hostname nginx
systemctl enable avahi-daemon nginx
systemctl start avahi-daemon nginx

echo "VM Nginx configurée. Ajouter la clé publique Claude dans /home/rhinov/.ssh/authorized_keys"

7.4 Script VM DEV/PROD (Portainer)

#!/bin/bash
# 04-vm-portainer.sh
# À exécuter sur les VMs DEV ou PROD

set -e

# Variables (à personnaliser)
ENV_TYPE="${1:-dev}"  # dev ou prod
NFS_SERVER="192.168.X.1"
NFS_PATH="/rhinov-pool/rhinov-stack"
DOCKER_DATA_ROOT="/mnt/rhinov-stack/docker/${ENV_TYPE}"

# Mise à jour
apt update && apt upgrade -y

# Packages
apt install -y \
    ca-certificates curl gnupg \
    sudo openssh-server \
    nfs-common \
    avahi-daemon libnss-mdns

# Création utilisateur rhinov
useradd -m -s /bin/bash rhinov
usermod -aG sudo rhinov

# Montage NFS
mkdir -p /mnt/rhinov-stack
echo "$NFS_SERVER:$NFS_PATH /mnt/rhinov-stack nfs defaults,_netdev 0 0" >> /etc/fstab
mount -a

# Installation Docker
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  tee /etc/apt/sources.list.d/docker.list > /dev/null

apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Configuration Docker data-root sur NFS
mkdir -p $DOCKER_DATA_ROOT
cat > /etc/docker/daemon.json << EOF
{
  "data-root": "$DOCKER_DATA_ROOT",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
EOF

systemctl restart docker

# Ajout rhinov au groupe docker
usermod -aG docker rhinov

# Installation Portainer
docker volume create portainer_data
docker run -d \
  -p 8000:8000 -p 9443:9443 \
  --name portainer \
  --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:latest

# mDNS
hostnamectl set-hostname "${ENV_TYPE}-01"
systemctl enable avahi-daemon docker
systemctl start avahi-daemon

echo "VM ${ENV_TYPE}-01 configurée."
echo "Portainer accessible sur https://$(hostname -I | awk '{print $1}'):9443"
echo "Ajouter la clé publique Claude dans /home/rhinov/.ssh/authorized_keys"

8. CLAUDE.md pour Rhinov

Un fichier CLAUDE.md complet sera généré avec :


9. Contenu du ZIP Final

rhinov-stack-setup.zip
├── README.md                           # Guide d'installation rapide
├── CLAUDE.md                           # Instructions Claude (template)
│
├── env/
│   └── template.env                    # Variables à remplir
│
├── scripts/
│   ├── setup/
│   │   ├── 01-proxmox-init.sh
│   │   ├── 02-vm-claude.sh
│   │   ├── 03-vm-nginx.sh
│   │   └── 04-vm-portainer.sh
│   │
│   ├── nginx/
│   │   ├── generate-config.sh          # Génère config Nginx
│   │   ├── deploy-config.sh            # Déploie sur VM Nginx
│   │   └── templates/
│   │       ├── reverse-proxy.conf.tpl
│   │       └── ssl-redirect.conf.tpl
│   │
│   ├── dns/
│   │   ├── gandi-add-record.sh
│   │   ├── ovh-add-record.sh
│   │   └── check-propagation.sh
│   │
│   ├── docker/
│   │   ├── health-check.sh
│   │   ├── logs.sh
│   │   └── cleanup.sh
│   │
│   ├── deploy/
│   │   ├── deploy-service.sh
│   │   └── rollback.sh
│   │
│   └── lib/
│       ├── colors.sh                   # Couleurs terminal
│       ├── logging.sh                  # Fonctions de log
│       ├── notifications.sh            # Ntfy/Telegram
│       └── utils.sh                    # Fonctions utilitaires
│
├── shortcuts/
│   ├── node/
│   │   └── Dockerfile
│   ├── bun/
│   │   └── Dockerfile
│   └── qwik/
│       └── Dockerfile
│
└── docs/
    ├── architecture.md
    ├── scaling.md                      # Guide ajout instances
    └── troubleshooting.md

10. Actions Demandées à Edouard

Informations réseau

Credentials à fournir

Accès Proxmox

Décisions


11. VMs Windows Rendu 3D

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    VMs WINDOWS RENDU 3D                         │
│                    (H24 / GPU passthrough)                      │
│                                                                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │  WIN-3D-01  │  │  WIN-3D-02  │  │  WIN-3D-0N  │             │
│  │ 192.168.X.50│  │ 192.168.X.51│  │ 192.168.X.5N│             │
│  │             │  │             │  │             │             │
│  │ - Windows   │  │ - Windows   │  │ - Windows   │             │
│  │ - OpenSSH   │  │ - OpenSSH   │  │ - OpenSSH   │             │
│  │ - Bonjour   │  │ - Bonjour   │  │ - Bonjour   │             │
│  │ - GPU NVIDIA│  │ - GPU NVIDIA│  │ - GPU NVIDIA│             │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘             │
│         │                │                │                     │
│         └────────────────┴────────────────┘                     │
│                          │                                      │
│                          ▼                                      │
│              ┌───────────────────────┐                         │
│              │      VM-CLAUDE        │                         │
│              │   Monitoring & Ctrl   │                         │
│              └───────────────────────┘                         │
└─────────────────────────────────────────────────────────────────┘

Plan d'adressage VMs Windows

VM Hostname IP suggérée GPU Rôle
WIN-3D-01 win3d-01 192.168.X.50 NVIDIA RTX Rendu 3D #1
WIN-3D-02 win3d-02 192.168.X.51 NVIDIA RTX Rendu 3D #2
WIN-3D-03 win3d-03 192.168.X.52 NVIDIA RTX Rendu 3D #3
... ... ... ... ...

Configuration SSH sur Windows

Script PowerShell d'installation (à exécuter en Admin)

# install-ssh-windows.ps1
# À exécuter en tant qu'Administrateur sur chaque VM Windows

# Installation OpenSSH Server
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0

# Démarrage et activation automatique
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

# Firewall - autoriser SSH
New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22

# Configuration sshd_config pour authentification par clé
$sshdConfig = @"
# Configuration OpenSSH pour Rhinov
Port 22
ListenAddress 0.0.0.0
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

# Shell par défaut : PowerShell
Subsystem sftp sftp-server.exe
"@

$sshdConfig | Out-File -Encoding utf8 "C:\ProgramData\ssh\sshd_config" -Force

# Création utilisateur rhinov (compte de service pour Claude)
$Password = ConvertTo-SecureString "MotDePasseTemporaire123!" -AsPlainText -Force
New-LocalUser -Name "rhinov" -Password $Password -PasswordNeverExpires -UserMayNotChangePassword
Add-LocalGroupMember -Group "Administrators" -Member "rhinov"

# Création dossier .ssh pour rhinov
$sshPath = "C:\Users\rhinov\.ssh"
New-Item -ItemType Directory -Path $sshPath -Force

# Placeholder pour la clé publique Claude (à remplacer)
$authorizedKeys = @"

"@
$authorizedKeys | Out-File -Encoding utf8 "$sshPath\authorized_keys" -Force

# Permissions sur authorized_keys (important pour Windows)
icacls "$sshPath\authorized_keys" /inheritance:r /grant "rhinov:F" /grant "SYSTEM:F"

# Redémarrage du service
Restart-Service sshd

Write-Host "OpenSSH Server installé et configuré."
Write-Host "Ajouter la clé publique Claude dans C:\Users\rhinov\.ssh\authorized_keys"

Installation Bonjour (mDNS)

# install-bonjour.ps1
# Permet la résolution .local (mDNS)

# Télécharger Bonjour Print Services (contient mDNS)
$bonjourUrl = "https://support.apple.com/kb/DL999"
# Ou utiliser le lien direct si disponible

# Alternative : installer via winget si disponible
winget install Apple.Bonjour

# Vérification
Test-NetConnection -ComputerName "claude.local" -Port 22

Script de configuration depuis VM-CLAUDE

#!/bin/bash
# setup-windows-ssh.sh
# À exécuter depuis VM-CLAUDE pour configurer l'accès aux VMs Windows

set -e

WINDOWS_VMS=("192.168.X.50" "192.168.X.51" "192.168.X.52")
SSH_KEY="/home/rhinov/.ssh/id_ed25519.pub"
WIN_USER="rhinov"
WIN_PASS="MotDePasseTemporaire123!"  # À changer après setup

for VM_IP in "${WINDOWS_VMS[@]}"; do
    echo "Configuration de $VM_IP..."

    # Copie de la clé publique
    sshpass -p "$WIN_PASS" ssh -o StrictHostKeyChecking=no $WIN_USER@$VM_IP "mkdir -p C:\Users\$WIN_USER\.ssh"
    sshpass -p "$WIN_PASS" scp $SSH_KEY $WIN_USER@$VM_IP:"C:\Users\\$WIN_USER\\.ssh\\authorized_keys"

    # Test de connexion sans mot de passe
    ssh -o PasswordAuthentication=no $WIN_USER@$VM_IP "hostname"

    echo "$VM_IP configuré avec succès."
done

echo "Toutes les VMs Windows sont accessibles via SSH."

Commandes utiles depuis Claude

# Connexion SSH à une VM Windows
ssh rhinov@win3d-01.local

# Exécuter une commande PowerShell
ssh rhinov@win3d-01.local "powershell -Command Get-Process"

# Vérifier l'état GPU
ssh rhinov@win3d-01.local "nvidia-smi"

# Lister les jobs de rendu en cours
ssh rhinov@win3d-01.local "powershell -Command Get-Process | Where-Object {$_.Name -like '*3dsmax*' -or $_.Name -like '*blender*'}"

# Redémarrer une VM (avec précaution)
ssh rhinov@win3d-01.local "shutdown /r /t 60 /c 'Redémarrage planifié par Claude'"

# Annuler un redémarrage
ssh rhinov@win3d-01.local "shutdown /a"

# Copier un fichier vers Windows
scp /path/to/file rhinov@win3d-01.local:"C:\Rendu\input\"

# Récupérer un rendu
scp rhinov@win3d-01.local:"C:\Rendu\output\scene.png" /local/path/

Monitoring des VMs Windows

#!/bin/bash
# monitor-windows-3d.sh
# Collecte les métriques des VMs de rendu

WINDOWS_VMS=("win3d-01.local" "win3d-02.local" "win3d-03.local")
OUTPUT_FILE="/mnt/rhinov-stack/monitoring/windows-3d.json"

echo "[" > $OUTPUT_FILE

for i in "${!WINDOWS_VMS[@]}"; do
    VM="${WINDOWS_VMS[$i]}"

    # Collecte des infos
    HOSTNAME=$(ssh rhinov@$VM "hostname" 2>/dev/null || echo "offline")
    GPU_USAGE=$(ssh rhinov@$VM "nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits" 2>/dev/null || echo "N/A")
    GPU_MEM=$(ssh rhinov@$VM "nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader,nounits" 2>/dev/null || echo "N/A")
    CPU_USAGE=$(ssh rhinov@$VM "powershell -Command \"(Get-Counter '\\Processor(_Total)\\% Processor Time').CounterSamples.CookedValue\"" 2>/dev/null || echo "N/A")

    # JSON
    COMMA=""
    [[ $i -lt $((${#WINDOWS_VMS[@]}-1)) ]] && COMMA=","

    cat >> $OUTPUT_FILE << EOF
  {
    "hostname": "$HOSTNAME",
    "vm": "$VM",
    "gpu_usage": "$GPU_USAGE",
    "gpu_memory": "$GPU_MEM",
    "cpu_usage": "$CPU_USAGE",
    "timestamp": "$(date -Iseconds)"
  }$COMMA
EOF
done

echo "]" >> $OUTPUT_FILE

Variables .env supplémentaires pour Windows

# Ajouter dans template.env

# -----------------------------
# VMs WINDOWS RENDU 3D
# -----------------------------
WIN3D_USER=rhinov
WIN3D_PASSWORD=                        # À définir (ou vide si clé SSH)

WIN3D_01_IP=192.168.X.50
WIN3D_01_HOSTNAME=win3d-01
WIN3D_01_GPU=RTX3090

WIN3D_02_IP=192.168.X.51
WIN3D_02_HOSTNAME=win3d-02
WIN3D_02_GPU=RTX3090

# Ajouter autant de VMs que nécessaire...

12. Prochaines Étapes

  1. Validation de cette proposition
  2. Réception des credentials d'Edouard
  3. Génération du ZIP complet avec tous les scripts
  4. Envoi par email à gouroubleu@gmail.com
  5. Documentation de déploiement étape par étape

Validation

En attente de validation pour générer le ZIP final.