Aller au contenu
Perfect Homelab [E08] : LXC-Frontend(110) - Déployer une Stack Frontend sécurisée avec Traefik, Authelia et CrowdSec
  1. Posts/

Perfect Homelab [E08] : LXC-Frontend(110) - Déployer une Stack Frontend sécurisée avec Traefik, Authelia et CrowdSec

Fabien ALLAMANCHE
Auteur
Fabien ALLAMANCHE
Géomaticien @ Vienne Condrieu Agglomération
Sommaire
Perfect Homelab - Cet article fait partie d'une série.
Partie 8: Cet article

Perfect Homelab

Introduction
#

Dans le monde du self-hosting et des homelabs, la sécurité est souvent reléguée au second plan au profit de la simplicité. Pourtant, exposer des services sur Internet sans une infrastructure de sécurité solide, c’est prendre le risque de voir son système compromis en quelques heures seulement.

Dans cet article, nous allons apprendre à déployer une stack frontend complète et sécurisée qui combine quatre composants essentiels :

  • Traefik comme reverse proxy avec génération automatique de certificats SSL,
  • Authelia pour l’authentification (2FA,SSO, Clés d’accès),
  • CrowdSec pour la protection contre les attaques,
  • Redis comme cache performant.

Nous allons couvrir la création d’un conteneur LXC Proxmox dédié, la configuration de chaque service, leurs interactions, le déploiement complet et les bonnes pratiques de sécurité.

Ce tutoriel suppose que vous avez déjà un serveur Proxmox VE opérationnel, des connaissances de base sur les conteneurs LXC et Docker, ainsi qu’un nom de domaine configuré.

Table des matières
#

🌐 Architecture réseau
#

Avant de déployer la stack, comprenons comment elle s’intègre dans l’architecture réseau de mon homelab.

Ma configuration réseau est basée sur une segmentation VLAN pour isoler les différents composants :

Segmentation VLAN
#

VLAN Sous-réseau Description Composants
VLAN 10 10.10.10.x/24 Infrastructure Proxmox Hôtes Proxmox VE & PBS
VLAN 20 10.10.20.x/24 LXC et/ou VMs LXC-Mediaserver, LXC-Elephant, LXC Storage
VLAN 99 10.99.99.x/24 Zone DMZ isolée (Frontend) LXC-Frontend (Stack Traefik + Authelia + CrowdSec)

Schéma réseau simplifié
#

graph TB
    Internet[Internet] --> Router[Routeur/Firewall]
    Router --> SW[Switch managé]

    SW --> VLAN10[VLAN 10
10.10.10.x] SW --> VLAN99[VLAN 99
10.99.99.x
Mode isolé] VLAN10 --> PVE[Proxmox VE
10.10.10.x] VLAN10 --> PBS[Proxmox Backup
10.10.10.x] VLAN99 --> LXC[LXC-Frontend
10.99.99.10] LXC --> TraefikStack[Stack Frontend
Traefik + Authelia
CrowdSec + Redis] style VLAN99 fill:#ffcdd2,stroke:#c62828,stroke-width:3px,color:#000 style LXC fill:#ffebee,stroke:#d32f2f,stroke-width:2px,color:#000 style TraefikStack fill:#fff3e0,stroke:#f57c00,stroke-width:2px,color:#000

Isolation du VLAN 99 (Mode DMZ)
#

Pourquoi isoler la stack frontend dans un VLAN dédié ?

Le VLAN 99 est configuré en mode isolé sous Unifi Network (ou tout autre contrôleur réseau) pour des raisons de sécurité :

  • Isolation du réseau de confiance : Les services exposés sur Internet ne peuvent pas accéder directement à mes réseaux internes (VLAN 10-20-30-etc)
  • Principe de défense en profondeur : En cas de compromission du conteneur LXC, l’attaquant est limité au VLAN 99
  • Règles de pare-feu strictes : Seuls les ports 80 (HTTP) et 443 (HTTPS) sont ouverts depuis Internet vers 10.99.99.10
  • Flux contrôlés : Les services backend dans d’autres VLANs peuvent initier des connexions vers la stack frontend, mais pas l’inverse

Configuration Unifi Network : Dans le contrôleur Unifi, le VLAN 99 doit avoir l’option “Isolate Network” activée pour empêcher toute communication avec les autres réseaux locaux.

Flux réseau typique
#

  1. Client externe (Internet) → Requête HTTPS sur le port 443
  2. Routeur/Firewall → NAT vers 10.99.99.10:443 (LXC-Frontend)
  3. Traefik (dans LXC) → Termine le SSL et applique la chaîne de sécurité
  4. CrowdSec + Authelia → Validation de l’IP et authentification
  5. Proxy vers backend → Traefik forward vers les services applicatifs (autres VLANs si autorisé)
Adaptez à votre configuration : Si vous n’utilisez pas Unifi Network, configurez l’isolation VLAN via votre switch managé et firewall (pfSense, OPNsense, routeur Mikrotik, etc.).

🖥️ Préparation du conteneur LXC Proxmox
#

Avant de déployer la stack, créons un conteneur LXC dédié sous Debian 13 optimisé pour Docker.

Création du conteneur LXC en ligne de commande
#

Téléchargement du template Debian 13
#

Connectez-vous à votre serveur Proxmox via SSH et téléchargez le template :

# Télécharge le template Debian 13 dans le stockage local
pveam update
pveam download iso-morpheus debian-13-standard_13.0-1_amd64.tar.zst
Info : iso-morpheus correspond ici au nom de mon storage Proxmox contenant vos images ISO de VMs et vos templates LXC. Pensez à l’adapter à votre infrastructure.

Création du conteneur
#

Créez le conteneur LXC avec la commande pct create :

pct create 110 iso-morpheus:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst \
  --hostname frontend \
  --memory 2048 \
  --cores 2 \
  --rootfs datastore-zfs:16 \
  --net0 name=eth0,bridge=vmbr0,firewall=1,gw=10.99.99.1,ip=10.99.99.10/24,tag=99,type=veth \
  --nameserver 192.168.0.153 \
  --searchdomain mydomain.local \
  --password \
  --unprivileged 0 \
  --features nesting=1,keyctl=1 \
  --onboot 1 \
  --startup order=1
Info : De la même façon, datastore-zfs correspond ici au nom de mon storage ZFS Proxmox contenant les images disques de VMs/LXC. Pensez à l’adapter à votre infrastructure.

Explication des paramètres :

  • 110 : ID du conteneur (adaptez selon votre environnement)
  • --hostname frontend : Nom d’hôte du conteneur
  • --memory 2048 : 2 GB de RAM (minimum recommandé)
  • --cores 2 : 2 cœurs CPU
  • --rootfs datastore-zfs:16 : Disque de 16 GB sur le stockage datastore-zfs
  • --net0 : Configuration réseau (adaptez l’IP, gateway et bridge selon votre réseau)
  • --unprivileged 0 : Conteneur privilégié (voir avertissement de sécurité ci-dessous)
  • --features nesting=1,keyctl=1 : Nécessaire pour Docker dans LXC
  • --onboot 1 : Démarre automatiquement au boot de Proxmox
  • --startup order=1 : Ordre de démarrage

Info : Les paramètres nesting=1 et keyctl=1 sont indispensables pour exécuter Docker dans un conteneur LXC.

Avertissement de sécurité : Conteneur LXC privilégié

Le paramètre --unprivileged 0 crée un conteneur privilégié, ce qui signifie que :

Risques de sécurité importants :

  • L’utilisateur root dans le conteneur correspond à l’utilisateur root de l’hôte Proxmox
  • Une compromission du conteneur peut entraîner une compromission complète de l’hôte Proxmox
  • Les processus du conteneur ont un accès quasi-illimité aux ressources système de l’hôte
  • En cas de faille de sécurité (CVE Docker, vulnérabilité applicative), un attaquant pourrait s’échapper du conteneur LXC

Pourquoi utiliser un conteneur privilégié ici ?

Dans certains cas, Docker dans un conteneur LXC non-privilégié peut rencontrer des problèmes de :

  • Mapping des UID/GID complexe
  • Permissions sur les volumes montés
  • Compatibilité avec certaines images Docker

Recommandations de sécurité :

  1. Isolation réseau : Placez ce conteneur dans un VLAN dédié séparé de votre réseau de confiance
  2. Pare-feu strict : N’autorisez que les ports 80 et 443 depuis Internet, bloquez tous les autres ports
  3. Mises à jour régulières : Appliquez systématiquement les mises à jour de sécurité (Debian, Docker, images)
  4. Monitoring actif : Surveillez les logs système et les comportements anormaux
  5. Snapshots réguliers : Effectuez des sauvegardes fréquentes de votre conteneur avant toute modification
  6. Limitez l’accès SSH : Restreignez l’accès root au conteneur et utilisez des clés SSH plutôt que des mots de passe
  7. Principe du moindre privilège : N’exposez que les services strictement nécessaires

Alternative plus sécurisée :

Si votre environnement le permet, envisagez d’utiliser un conteneur non-privilégié (--unprivileged 1) avec un mapping d’UID/GID correct :

# Dans /etc/pve/lxc/110.conf (après création)
lxc.idmap: u 0 100000 1000
lxc.idmap: g 0 100000 1000
lxc.idmap: u 1000 1000 1
lxc.idmap: g 1000 1000 1
lxc.idmap: u 1001 101001 64535
lxc.idmap: g 1001 101001 64535

Cependant, cette configuration nécessite des ajustements supplémentaires pour Docker et peut compliquer le déploiement voir même le rendre impossible.

Pour un environnement de production critique et si vous ne maîtrisez pas tous les tenants et aboutissants d’un telle configuration, privilégiez :

  • Une VM complète (plutôt qu’un conteneur LXC)

Démarrage du conteneur
#

# Démarre le conteneur
pct start 110

# Vérifie le statut
pct status 110

# Entre dans le conteneur
pct enter 110

Configuration initiale du conteneur
#

Une fois dans le conteneur, effectuez la configuration de base :

Mise à jour du système
#

# Met à jour les dépôts et le système
sudo apt upgrade -y

Installation de Docker et Docker Compose
#

# Installe les dépendances
sudo apt install -y ca-certificates curl gnupg lsb-release

# Add Docker's official GPG key:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF

sudo apt update

# Installation des paquets
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Vérifie l'installation
sudo systemctl status docker
docker --version
docker compose version

Création de l’utilisateur pour la stack
#

Créez un utilisateur dédié s’il n’existe pas déjà (UID 1000) pour gérer la stack :

# Crée l'utilisateur myuser avec UID 1000
useradd -m -u 1000 -s /bin/bash myuser

# Définit un mot de passe
passwd myuser

# Ajoute l'utilisateur au groupe docker
usermod -aG docker myuser

# Ajoute l'utilisateur au groupe sudo (optionnel)
usermod -aG sudo myuser

Création de la structure de dossiers
#

# Crée le répertoire de travail principal
mkdir -p /opt/docker/frontend-stack

# Donne les droits à l'utilisateur myuser (UID 1000)
chown -R 1000:1000 /opt/docker
chmod -R 755 /opt/docker
Rappel : Tous les fichiers de la stack seront stockés dans /opt/docker/frontend-stack.

🔭 Vue d’ensemble de l’architecture
#

L’architecture suit un modèle en couches où chaque requête traverse plusieurs services de sécurité avant d’atteindre l’application finale.

Schéma de l’architecture
#

graph TB
    subgraph "Internet"
        Client[Client Web]
    end

    subgraph "Proxmox Host"
        Bridge[Bridge vmbr0
10.10.10.X/24] end subgraph "LXC Container
10.99.99.10" subgraph "Docker Network: frontend
172.18.0.0/16" Traefik[Traefik
Reverse Proxy + SSL
Ports 80/443] CrowdSec[CrowdSec
WAF + Detection
Port 8081] Authelia[Authelia
SSO + 2FA
Port 9091] Redis[Redis
Cache Sessions
Port 6379] App[Application
Backend Services] end end Client -->|HTTPS| Bridge Bridge --> Traefik Traefik -->|Middleware Chain| CrowdSec CrowdSec --> Authelia Authelia --> App Authelia -.Session.-> Redis CrowdSec -.Cache.-> Redis Traefik -.Logs.-> CrowdSec Authelia -.Logs.-> CrowdSec

Légende :

  • Traefik : Point d’entrée unique, gestion SSL automatique
  • CrowdSec : Protection contre les cyberattaques
  • Authelia : Authentification et autorisation
  • Redis : Cache haute performance
  • Application : Services backend protégés

Tous les services communiquent via un réseau Docker bridge nommé frontend avec un sous-réseau dédié (172.18.0.0/16).

Services composant la stack
#

Service Rôle Port(s) Image Docker
Traefik Reverse proxy, routage HTTP/HTTPS, génération SSL automatique 80, 443, 8080 traefik:latest
Authelia Authentification SSO, double facteur (TOTP, WebAuthn) 9091 authelia/authelia:4.39.15
CrowdSec Détection et blocage d’attaques, AppSec WAF 8081 crowdsecurity/crowdsec:latest
Redis Cache session Authelia, cache CrowdSec bouncer 6379 redis:latest
Redis Insight Interface web pour administrer Redis 5540 redis/redisinsight:latest

Version fixe d’Authelia (4.39.15) : Le tag de version d’Authelia est volontairement fixé et non en latest. Cette décision est critique car :

  • Authelia contrôle l’accès à tous vos services exposés : C’est le composant le plus sensible de la stack
  • Les mises à jour majeures peuvent casser la configuration : Les versions 4.38+ et 4.39+ ont introduit des changements de configuration importants
  • Évite les surprises en production : Une mise à jour automatique pourrait bloquer l’accès à toutes vos applications
  • Version stable et éprouvée : La version 4.39.15 est testée et fonctionnelle avec cette configuration

Recommandation : Avant de mettre à jour Authelia, consultez les release notes officielles et testez dans un environnement de développement. Les changements de configuration doivent être validés avant le passage en production.

Flux de données
#

sequenceDiagram
    participant Client
    participant Traefik
    participant CrowdSec
    participant Authelia
    participant Redis
    participant App as Application

    Client->>Traefik: 1. Requête HTTPS
    Traefik->>CrowdSec: 2. Vérification IP
    CrowdSec->>Redis: Consultation cache décisions
    Redis-->>CrowdSec: ✓ IP autorisée

    CrowdSec->>Authelia: 3. Demande authentification
    Authelia->>Redis: Vérification session
    Redis-->>Authelia: ✓ Session valide + 2FA OK

    Authelia->>App: 4. Transmission requête
    App-->>Authelia: 5. Réponse applicative
    Authelia-->>Traefik: 6. Réponse sécurisée
    Traefik-->>Client: 7. Réponse HTTPS

    Note over Traefik,CrowdSec: Les logs Traefik/Authelia sont
analysés en temps réel par CrowdSec

Explication simplifiée du flux :

  1. Client → Traefik : L’utilisateur accède à https://app.mydomain.com via HTTPS
  2. Traefik → CrowdSec : Vérification de l’IP dans la base de décisions (mise en cache Redis)
  3. CrowdSec → Authelia : Si l’IP est autorisée, vérification de l’authentification utilisateur
  4. Authelia → Application : Si l’utilisateur est authentifié et 2FA validé, la requête est transmise
  5. Application → Client : La réponse remonte la chaîne jusqu’au client
En cas d’échec : Si l’IP est bannie par CrowdSec, une page 403 est affichée. Si l’utilisateur n’est pas authentifié, Authelia redirige vers la page de connexion.

CrowdSec analyse en continu les logs de Traefik et Authelia pour détecter les comportements suspects et mettre à jour automatiquement les décisions de blocage.

📋 Prérequis techniques
#

Assurez-vous d’avoir tous les prérequis avant de commencer le déploiement de la stack.

Infrastructure Proxmox
#

  • Proxmox VE : version 8.0+ recommandée
  • Conteneur LXC : Debian 13 avec fonctionnalités nesting et keyctl activées
  • Réseau : Bridge réseau configuré (vmbr0) avec accès Internet

Logiciels requis (dans le LXC)
#

  • Docker : version 24.0+ Installer Docker
  • Docker Compose : version 2.0+ (inclus avec Docker via docker-compose-plugin)
  • Git : pour cloner le projet si nécessaire
  • Éditeur de texte : vi, vim ou accès distant via VS Code

Connaissances recommandées
#

Docker & conteneurs
Networking & DNS
Certificats SSL/TLS
LXC Proxmox
Gestion des secrets

Configuration minimale LXC
#

Composant Minimum Recommandé
CPU 1 cœurs 2 cœurs
RAM 1 GB 2 GB
Disque 8 GB 16 GB
Système Debian 13 (template officiel Proxmox) -
Réseau IP statique, ports 80/443 accessibles -
DNS Nom de domaine avec accès DNS (certificats wildcard) -

Accès requis
#

  • Cloudflare ou OVH : Compte avec API token pour le DNS challenge ACME
  • Email : Adresse email pour les notifications Authelia (SMTP Gmail ou autre)

📁 Structure du projet
#

Découvrons l’organisation complète des fichiers et dossiers de la stack frontend.

Voici l’arborescence complète du projet dans /opt/docker/frontend-stack :

/opt/docker/frontend-stack/
├── docker-compose.yml              # Orchestration principale (include des sous-stacks)
├── .env                            # Variables d'environnement (SENSIBLE - ne pas commiter)
├── .env.example                    # Variables d'environnement modèles
├── authelia/
│   ├── docker-compose.yml          # Service Authelia
│   ├── configuration.yml           # Configuration complète Authelia
│   ├── users/                      # Base utilisateurs (fichier YAML)
│   │   └── config.yml              # Fichier utilisateurs avec hash Argon2id
│   ├── db/                         # Base SQLite locale (persistance)
│   └── logs/                       # Logs Authelia (analysés par CrowdSec)
│       └── authelia.log            # Fichier de log principal
├── traefik/
│   ├── docker-compose.yml          # Service Traefik
│   ├── config.yml                  # Configuration statique Traefik
│   ├── rules/                      # Configuration dynamique (fichiers YAML)
│   │   ├── 00-middlewares.yml      # Définition des middlewares (sécurité, compression)
│   │   ├── 100-frontend.yml        # Routes pour Traefik et Authelia
│   │   └── ...                     # Autres règles de routage par catégorie
│   ├── certs/                      # Certificats SSL générés (JSON ACME)
│   ├── logs/                       # Logs Traefik (analysés par CrowdSec)
│   │   ├── access.log              # Logs d'accès HTTP
│   │   └── error.log               # Logs d'erreurs
│   └── plugins/                    # Plugin CrowdSec bouncer (templates HTML)
│       └── crowdsec-bouncer/
│           ├── captcha.html        # Page captcha CrowdSec
│           └── ban.html            # Page de ban CrowdSec
├── crowdsec/
│   ├── docker-compose.yml          # Service CrowdSec
│   ├── config/
│   │   ├── acquis.yaml             # Sources de logs à analyser
│   │   ├── profiles.yaml           # Profils de décisions
│   │   └── notifications/          # Configuration notifications (ntfy)
│   │       └── ntfy.yaml           # Configuration ntfy.sh
│   └── data/                       # Base de données CrowdSec (persistance)
└── redis/
    ├── docker-compose.yml          # Services Redis + Redis Insight
    ├── data/                       # Persistance Redis
    └── insight/                    # Données Redis Insight

Fichiers clés
#

Fichier Chemin absolu Description
docker-compose.yml /opt/docker/frontend-stack/docker-compose.yml Orchestre les 4 sous-stacks via la directive include
.env /opt/docker/frontend-stack/.env Variables sensibles (mots de passe Redis, tokens API DNS, clés CrowdSec)
config.yml /opt/docker/frontend-stack/traefik/config.yml Configuration statique Traefik (entrypoints, certificats, plugins)
00-middlewares.yml /opt/docker/frontend-stack/traefik/rules/00-middlewares.yml Middlewares de sécurité (headers, rate-limit, CrowdSec, Authelia)
configuration.yml /opt/docker/frontend-stack/authelia/configuration.yml Configuration complète Authelia (authentification, règles d’accès, session Redis)
users/config.yml /opt/docker/frontend-stack/authelia/users/config.yml Base utilisateurs Authelia avec hash Argon2id
acquis.yaml /opt/docker/frontend-stack/crowdsec/config/acquis.yaml Définit les logs à analyser et le composant AppSec
Astuce : Tous les chemins relatifs dans les commandes docker-compose sont relatifs au répertoire /opt/docker/frontend-stack.

⚙️ Configuration des services
#

Service 1 : Redis
#

Redis joue un rôle central comme cache haute performance partagé entre Authelia et CrowdSec.

Rôle et responsabilités
#

Redis joue un rôle central dans cette architecture en fournissant un cache haute performance pour deux services critiques :

  • Authelia : Stockage des sessions utilisateurs (base de données 0)
  • CrowdSec Bouncer : Cache des décisions de blocage (base de données 5) pour éviter de surcharger l’API CrowdSec

Redis Insight est inclus pour faciliter l’administration et le monitoring.

Configuration Docker Compose
#

Fichier : /opt/docker/frontend-stack/redis/docker-compose.yml

services:
  redis:
    container_name: redis
    image: redis:latest
    security_opt:
      - no-new-privileges:true  # Sécurité : empêche l'escalade de privilèges
    restart: always
    ports:
      - 6379:6379                # Port standard Redis
    command: >
      redis-server
      --save 60 1                 # Sauvegarde sur disque toutes les 60s si ≥1 modification
      --loglevel notice           # Niveau de log équilibré
      --requirepass ${REDIS_PASSWORD}  # Authentification obligatoire
    volumes:
      - ./data:/data              # Persistance des données
    healthcheck:
      test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
      interval: 15s               # Vérification toutes les 15s
      timeout: 3s
      retries: 3
    networks:
      - frontend

  redis-insight:
    container_name: redis-insight
    image: redis/redisinsight:latest
    security_opt:
      - no-new-privileges:true
    restart: unless-stopped
    ports:
      - 5540:5540                 # Interface web
    volumes:
      - ./insight:/data           # Configuration Redis Insight
    networks:
      - frontend

Variables d’environnement
#

Variable Description Valeur par défaut Obligatoire
REDIS_PASSWORD Mot de passe Redis - Oui

Volumes et persistance
#

  • ./data/opt/docker/frontend-stack/redis/data : Données Redis (persistance RDB activée toutes les 60 secondes)
  • ./insight/opt/docker/frontend-stack/redis/insight : Configuration et données Redis Insight

Dépendances
#

Aucune dépendance. Redis démarre en premier car d’autres services en dépendent.


Service 2 : Authelia
#

Authelia est le gardien de votre infrastructure, gérant l’authentification via mot de passe, l’authentification double facteur ou encore le SSO.

Rôle et responsabilités
#

Authelia est le gardien de votre infrastructure. Il fournit :

  • Authentification SSO : Connexion unique pour tous les services
  • Double facteur : TOTP (Google Authenticator, Authy) et WebAuthn (Yubikey, Touch ID)
  • Gestion fine des accès : Politiques par domaine, réseau et utilisateur
  • Réinitialisation de mot de passe : Via email SMTP

Configuration Docker Compose
#

Fichier : /opt/docker/frontend-stack/authelia/docker-compose.yml

services:
  authelia:
    container_name: authelia
    image: authelia/authelia:4.39.15
    user: 1000:1000              # Exécute avec l'utilisateur myuser (UID 1000)
    security_opt:
      - no-new-privileges:true   # Sécurité renforcée
    restart: always
    ports:
      - 9091:9091                # API et interface web
    depends_on:
      redis:
        condition: service_healthy  # Attend que Redis soit opérationnel
    volumes:
      - ./:/config               # Configuration complète montée dans le répertoire courant authelia
    environment:
      - TZ=Europe/Paris          # Fuseau horaire pour les logs
    networks:
      - frontend

Variables d’environnement
#

Authelia utilise principalement son fichier configuration.yml plutôt que des variables d’environnement. Les secrets suivants doivent être définis dans /opt/docker/frontend-stack/authelia/configuration.yml :

Variable (dans config.yml) Description Obligatoire
jwt_secret Clé JWT pour réinitialisation mot de passe Oui
session.secret Clé de chiffrement des sessions Oui
storage.encryption_key Clé de chiffrement de la base de données Oui
session.redis.password Mot de passe Redis (depuis .env) Oui
notifier.smtp.password Mot de passe SMTP pour les emails Oui
Astuce : Générez des secrets cryptographiquement sûrs avec : openssl rand -base64 32

Volumes et persistance
#

  • ./configuration.yml/opt/docker/frontend-stack/authelia/configuration.yml : Configuration principale Authelia
  • ./users/config.yml/opt/docker/frontend-stack/authelia/users/config.yml : Base utilisateurs (hash Argon2id)
  • ./db/db.sqlite3/opt/docker/frontend-stack/authelia/db/db.sqlite3 : Base de données locale (données 2FA, consentements) générée au démarrage du conteneur docker
  • ./logs/authelia.log/opt/docker/frontend-stack/authelia/logs/authelia.log : Fichier de logs (analysé par CrowdSec)

Dépendances
#

  • Redis : Stockage des sessions (condition: service_healthy)

Configuration des règles d’accès
#

Authelia propose trois niveaux de politique :

  • bypass : Accès sans authentification (services publics, applications avec auth native)
  • one_factor : Mot de passe uniquement
  • two_factor : Mot de passe + TOTP/WebAuthn

Exemple de règles dans /opt/docker/frontend-stack/authelia/configuration.yml :

access_control:
  default_policy: "deny"  # Par défaut, tout est bloqué
  rules:
    # Services publics ou avec auth native
    - domain: 'nextcloud.mydomain.com'
      policy: 'bypass'

    # Monitoring léger
    - domain: 'argus.ci.mydomain.com'
      policy: 'one_factor'

    # Services critiques
    - domain: 'proxmox.pve.mydomain.com'
      policy: 'two_factor'

    # Bypass depuis réseaux internes
    - domain:
        - "*.mydomain.com"
      policy: "bypass"
      networks:
        - "internal"  # Défini dans access_control.networks

Service 3 : Traefik
#

Traefik est le point d’entrée unique de toute votre infrastructure avec SSL automatique et middlewares de sécurité.

Approche de sécurité : Configuration par fichiers plutôt que par labels Docker

Dans cette stack, j’ai volontairement choisi de ne pas binder le socket Docker (/var/run/docker.sock) dans les volumes Traefik. Cette décision architecturale présente plusieurs avantages sécuritaires :

Pourquoi éviter le socket Docker ?

  • Réduction de la surface d’attaque : Le socket Docker donne un accès root complet à l’hôte. Une compromission de Traefik ne permet pas d’accéder à Docker.
  • Principe du moindre privilège : Traefik n’a pas besoin d’un accès complet à l’API Docker pour fonctionner.
  • Isolation renforcée : Aucun conteneur de la stack ne peut interagir avec Docker lui-même.

Configuration par fichiers YAML

Au lieu d’utiliser les labels Traefik dans les docker-compose.yml des différents services, toute la configuration de routage se fait via des fichiers YAML situés dans le dossier traefik/rules/ :

  • 00-middlewares.yml : Définition des middlewares de sécurité
  • 100-frontend.yml : Routes pour Traefik et Authelia
  • Autres fichiers de règles organisés par service ou catégorie

Avantages de cette approche :

  • ✅ Configuration centralisée et versionnée
  • ✅ Pas de redémarrage des conteneurs pour modifier le routage puisque les fichiers de routage se situent sous le dossier ./rules/ qui est rechargé à chaud
  • ✅ Meilleure lisibilité et organisation

Rôle et responsabilités
#

Traefik est le point d’entrée unique de toute notre infrastructure.

Il gère :

  • Reverse proxy : Routage vers les différents services Docker
  • SSL/TLS automatique : Génération et renouvellement via Let’s Encrypt (DNS challenge)
  • Middlewares : Application de la chaîne de sécurité (CrowdSec, Authelia, headers, compression)
  • Observabilité : Dashboard et logs détaillés

Configuration Docker Compose
#

Fichier : /opt/docker/frontend-stack/traefik/docker-compose.yml

services:
  traefik:
    container_name: traefik
    image: traefik:latest
    restart: always
    ports:
      - 80:80                    # HTTP (redirige vers HTTPS)
      - 443:443                  # HTTPS
      - 8080:8080                # Dashboard (ne pas exposer en production !)
    command:
      - --configFile=/etc/traefik/config.yml
    depends_on:
      authelia:
        condition: service_started
    volumes:
      - ./:/etc/traefik          # Configuration complète
      - ./logs:/var/log/traefik  # Logs (analysés par CrowdSec)
      - ./plugins/crowdsec-bouncer/captcha.html:/captcha.html
      - ./plugins/crowdsec-bouncer/ban.html:/ban.html
    environment:
      - OVH_ENDPOINT=${OVH_ENDPOINT}
      - OVH_APPLICATION_KEY=${OVH_APPLICATION_KEY}
      - OVH_APPLICATION_SECRET=${OVH_APPLICATION_SECRET}
      - OVH_CONSUMER_KEY=${OVH_CONSUMER_KEY}
      - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}  # Cloudflare API
      - TZ=Europe/Paris
    networks:
      - frontend

Variables d’environnement
#

Définies dans /opt/docker/frontend-stack/.env :

Variable Description Valeur par défaut Obligatoire
CF_DNS_API_TOKEN Token API Cloudflare pour DNS challenge - Oui (si Cloudflare)
OVH_ENDPOINT Endpoint OVH API (ovh-eu, ovh-ca, etc.) ovh-eu Oui (si OVH)
OVH_APPLICATION_KEY Clé application OVH - Oui (si OVH)
OVH_APPLICATION_SECRET Secret application OVH - Oui (si OVH)
OVH_CONSUMER_KEY Clé consommateur OVH - Oui (si OVH)
Attention : Choisissez un seul fournisseur DNS (Cloudflare OU OVH) et configurez le certResolver correspondant dans /opt/docker/frontend-stack/traefik/config.yml.

Volumes et persistance
#

  • ./config.yml/opt/docker/frontend-stack/traefik/config.yml : Configuration statique (entrypoints, certificats)
  • ./rules//opt/docker/frontend-stack/traefik/rules/ : Configuration dynamique (routers, services, middlewares)
  • ./certs//opt/docker/frontend-stack/traefik/certs/ : Certificats ACME générés (JSON)
  • ./logs//opt/docker/frontend-stack/traefik/logs/ : Logs access et error

Dépendances
#

  • Authelia : Middleware forwardAuth (condition: service_started)

Configuration complète de Traefik (config.yml)
#

Voici la configuration statique complète de Traefik située dans /opt/docker/frontend-stack/traefik/config.yml :

---
global:
  checkNewVersion: true           # Vérifie les nouvelles versions
  sendAnonymousUsage: false       # Désactive la télémétrie

serversTransport:
  insecureSkipVerify: true        # Accepte les certificats auto-signés (backends internes)

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure           # Redirige tout le trafic HTTP vers HTTPS
          scheme: https
  websecure:
    address: ":443"
    http:
      tls:
        certResolver: cloudflare  # Resolver par défaut (cloudflare, ovh, ou staging)
        domains:
          - main: mydomain.com
            sans:
              - "*.mydomain.com"   # Certificat wildcard pour tous les sous-domaines
          - main: subdomain1.mydomain.com
            sans:
              - "*.subdomain1.mydomain.com"
          - main: subdomain2.mydomain.com
            sans:
              - "*.subdomain2.mydomain.com"
      middlewares:
        - chain-secure            # Applique la chaîne de sécurité par défaut

providers:
  file:
    directory: /etc/traefik/rules # Chargement des fichiers de configuration dynamique
    watch: true                   # Rechargement automatique des modifications

log:
  level: error                    # Niveau de log (debug, info, warn, error)
  format: common                  # Format des logs
  filePath: /var/log/traefik/error.log

accessLog:
  filePath: /var/log/traefik/access.log
  format: common                  # Format analysable par CrowdSec
  fields:
    defaultMode: keep             # Conserve tous les champs par défaut
    headers:
      defaultMode: keep           # Conserve tous les headers (utile pour le debugging)

api:
  dashboard: true                 # Active le dashboard Traefik
  insecure: true                  # Dashboard accessible sur :8080 (à sécuriser en prod !)
  debug: false                    # Mode debug désactivé

# Resolvers de certificats SSL (4 configurations disponibles)
certificatesResolvers:
  # Production Cloudflare
  cloudflare:
    acme:
      email: user@gmail.com       # Email pour les notifications Let's Encrypt
      storage: /etc/traefik/certs/acme-cloudflare.json
      caServer: "https://acme-v02.api.letsencrypt.org/directory"
      dnsChallenge:
        provider: cloudflare
        propagation:
          disableChecks: true     # Désactive la vérification de propagation DNS
          delayBeforeChecks: 60   # Attente 60s avant vérification ACME
        resolvers:
          - "1.1.1.1:53"          # DNS Cloudflare
          - "1.0.0.1:53"

  # Staging Cloudflare (certificats de test)
  cloudflare-staging:
    acme:
      email: user@gmail.com
      storage: /etc/traefik/certs/acme-cloudflare-staging.json
      caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
      dnsChallenge:
        provider: cloudflare
        propagation:
          disableChecks: true
          delayBeforeChecks: 60
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

  # Production OVH
  ovh:
    acme:
      email: user@gmail.com
      storage: /etc/traefik/certs/acme-ovh.json
      caServer: "https://acme-v02.api.letsencrypt.org/directory"
      dnsChallenge:
        provider: ovh
        propagation:
          disableChecks: true
          delayBeforeChecks: 60
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

  # Staging OVH (certificats de test)
  ovh-staging:
    acme:
      email: user@gmail.com
      storage: /etc/traefik/certs/acme-ovh-staging.json
      caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
      dnsChallenge:
        provider: ovh
        propagation:
          disableChecks: true
          delayBeforeChecks: 60
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

# Plugin CrowdSec Bouncer pour Traefik
experimental:
  plugins:
    crowdsec-bouncer:
      moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
      version: "v1.4.5"

Points clés de cette configuration :

Certificats wildcard multi-domaines : Cette configuration permet de générer des certificats wildcard pour plusieurs domaines et sous-domaines simultanément. Chaque entrée dans domains génère un certificat couvrant le domaine principal et tous ses sous-domaines via *..

Choix du resolver : Vous disposez de 4 resolvers (Cloudflare prod/staging, OVH prod/staging). Utilisez d’abord les versions -staging pour valider votre configuration sans risquer d’atteindre les limites de Let’s Encrypt, puis basculez sur les versions production.

Dashboard Traefik : Le paramètre api.insecure: true expose le dashboard sur le port 8080 sans authentification. En production, sécurisez-le avec Authelia via une route dans traefik/rules/100-frontend.yml.

Configuration de la chaîne de sécurité
#

Le middleware chain-secure défini dans /opt/docker/frontend-stack/traefik/rules/00-middlewares.yml applique plusieurs couches de protection :

http:
  middlewares:
    chain-secure:
      chain:
        middlewares:
          - https-redirect      # Force HTTPS
          - crowdsec            # Vérification CrowdSec (blocage IPs malveillantes)
          - compression         # Compression gzip/brotli
          - secure-headers      # Headers de sécurité (HSTS, X-Frame-Options, CSP)
          - authelia            # Authentification SSO

Cette chaîne est appliquée automatiquement à toutes les requêtes HTTPS grâce à la configuration de l’entrypoint websecure :

entryPoints:
  websecure:
    http:
      middlewares:
        - chain-secure          # Chaîne appliquée par défaut

Service 4 : CrowdSec
#

CrowdSec est le système de défense actif de notre infrastructure avec WAF et détection collaborative des menaces.

Rôle et responsabilités
#

CrowdSec est le système de défense actif de notre infrastructure.

Il assure :

  • Détection d’attaques : Analyse en temps réel des logs Traefik et Authelia
  • Blocage automatique : Ban des IPs malveillantes (intégré à Traefik via plugin)
  • Application Security (AppSec) : WAF virtuel avec patching et règles CRS
  • Intelligence collective : Partage anonyme des attaques détectées

Configuration Docker Compose
#

Fichier : /opt/docker/frontend-stack/crowdsec/docker-compose.yml

services:
  crowdsec:
    container_name: crowdsec
    image: crowdsecurity/crowdsec:latest
    restart: unless-stopped
    ports:
      - 8081:8080                # API locale (LAPI)
    depends_on:
      redis:
        condition: service_healthy
      traefik:
        condition: service_started
    volumes:
      - ./config/acquis.yaml:/etc/crowdsec/acquis.yaml:ro
      - ./config/profiles.yaml:/etc/crowdsec/profiles.yaml:ro
      - ./config/notifications/ntfy.yaml:/etc/crowdsec/notifications/ntfy.yaml:ro
      - ./data:/var/lib/crowdsec/data  # Base de données décisions
      - ../traefik/logs:/var/log/traefik:ro  # Logs à analyser
      - ../authelia/logs/:/var/log/authelia:ro
    environment:
      - GID=${GID-1000}
      - COLLECTIONS=crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/base-http-scenarios crowdsecurity/sshd crowdsecurity/linux crowdsecurity/appsec-generic-rules crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-crs LePresidente/authelia
      - CUSTOM_HOSTNAME=frontend-crowdsec
      - BOUNCER_KEY_TRAEFIK="${BOUNCER_KEY_TRAEFIK}"
    networks:
      - frontend

Variables d’environnement
#

Variable Description Valeur par défaut Obligatoire
COLLECTIONS Collections de scénarios à installer au démarrage - Oui
BOUNCER_KEY_TRAEFIK Clé API du bouncer Traefik - Oui
GID Group ID pour les permissions fichiers 1000 Non
Rappel : La clé BOUNCER_KEY_TRAEFIK est générée avec la commande : docker exec crowdsec cscli bouncers add crowdsec-bouncer-traefik-plugin

Volumes et persistance
#

  • ./config/acquis.yaml/opt/docker/frontend-stack/crowdsec/config/acquis.yaml : Définition des sources de logs
  • ./config/profiles.yaml/opt/docker/frontend-stack/crowdsec/config/profiles.yaml : Profils de décisions (durée ban, remédiation)
  • ./data/opt/docker/frontend-stack/crowdsec/data : Base de données SQLite (décisions, métriques)
  • ../traefik/logs/opt/docker/frontend-stack/traefik/logs : Logs Traefik (lecture seule)
  • ../authelia/logs/opt/docker/frontend-stack/authelia/logs : Logs Authelia (lecture seule)

Dépendances
#

  • Redis : Cache optionnel (condition: service_healthy)
  • Traefik : Nécessaire pour que les logs existent (condition: service_started)

Configuration des sources de logs (acquis.yaml)
#

Fichier : /opt/docker/frontend-stack/crowdsec/config/acquis.yaml

---
filenames:
  - /var/log/traefik/*.log
labels:
  type: traefik               # Applique les parsers traefik
---
filenames:
  - /var/log/authelia/authelia.log
labels:
  type: authelia              # Applique les parsers authelia
---
listen_addr: 0.0.0.0:7422     # Port AppSec
appsec_config: crowdsecurity/virtual-patching
name: myAppSecComponent
source: appsec
labels:
  type: appsec

Le composant AppSec analyse les requêtes HTTP en temps réel (via le plugin Traefik) pour détecter les tentatives d’exploitation (SQLi, XSS, RCE, etc.).

Collections installées
#

  • crowdsecurity/traefik : Détection spécifique Traefik (scan, brute-force)
  • crowdsecurity/http-cve : Exploitation de CVE HTTP connues
  • crowdsecurity/base-http-scenarios : Scénarios HTTP génériques (crawlers agressifs)
  • crowdsecurity/appsec-generic-rules : Règles WAF génériques
  • crowdsecurity/appsec-virtual-patching : Patching virtuel de vulnérabilités
  • crowdsecurity/appsec-crs : Core Rule Set (équivalent ModSecurity)
  • LePresidente/authelia : Scénarios spécifiques Authelia

🚀 Déploiement étape par étape
#

Prérequis : Vous avez créé le conteneur LXC et vous êtes connecté en tant qu’utilisateur myuser (UID 1000).

Workflow de déploiement
#

Le déploiement suit un processus en 7 étapes :

graph LR
    A[1. Préparation
Création dossiers] --> B[2. Configuration
Fichiers .env et YAML] B --> C[3. Réseau Docker
Création bridge] C --> D[4. Téléchargement
Images Docker] D --> E[5. Lancement
Services démarrés] E --> F[6. Post-config
Utilisateurs + clés] F --> G[7. Vérification
Tests et validation] G -.Erreurs.-> F style A fill:#bbdefb,stroke:#1976d2,stroke-width:2px,color:#000 style B fill:#bbdefb,stroke:#1976d2,stroke-width:2px,color:#000 style C fill:#ffe0b2,stroke:#f57c00,stroke-width:2px,color:#000 style D fill:#ffe0b2,stroke:#f57c00,stroke-width:2px,color:#000 style E fill:#c8e6c9,stroke:#388e3c,stroke-width:2px,color:#000 style F fill:#c8e6c9,stroke:#388e3c,stroke-width:2px,color:#000 style G fill:#e1bee7,stroke:#7b1fa2,stroke-width:2px,color:#000

Étape 1 : Préparation de l’environnement
#

1.1 Se positionner dans le répertoire de travail
#

# Se connecte au conteneur LXC (depuis Proxmox host)
pct enter 110

# Switch vers l'utilisateur myuser
su - myuser

# Se positionne dans le répertoire de travail
cd /opt/docker/frontend-stack

1.2 Créer la structure de dossiers
#

# Crée la structure complète
mkdir -p /opt/docker/frontend-stack/{authelia/{db,logs,users},traefik/{certs,logs,rules,plugins/crowdsec-bouncer},crowdsec/{config/notifications,data},redis/{data,insight}}

# Vérifie les permissions (doit être 1000:1000)
ls -la /opt/docker/

1.3 Configuration des variables d’environnement
#

Créez le fichier .env :

# Crée le fichier .env
vi /opt/docker/frontend-stack/.env

Contenu de /opt/docker/frontend-stack/.env :

COMPOSE_PROJECT_NAME=frontend

########################
# REDIS
########################
REDIS_PASSWORD="votre_mot_de_passe_redis_securise_32_caracteres"

########################
# TRAEFIK
########################
###### DNS CHALLENGE ######
########### OVH ###########
OVH_ENDPOINT="ovh-eu"
OVH_APPLICATION_KEY="votre_ovh_application_key"
OVH_APPLICATION_SECRET="votre_ovh_application_secret"
OVH_CONSUMER_KEY="votre_ovh_consumer_key"
########### OVH ###########
####### CLOUDFLARE ########
CF_DNS_API_TOKEN="votre_cloudflare_dns_api_token"

########################
# CROWDSEC
########################
######## BOUNCER ##########
# Sera généré à l'étape 4.2 avec la commande:
# docker exec crowdsec cscli bouncers add crowdsec-bouncer-traefik-plugin
BOUNCER_KEY_TRAEFIK="sera_genere_plus_tard"

Variables à personnaliser obligatoirement :

  • REDIS_PASSWORD : Mot de passe Redis sécurisé (minimum 16 caractères)

    # Exemple de génération
    openssl rand -base64 24
    
  • CF_DNS_API_TOKEN : Token API Cloudflare avec permissions DNS:Edit

  • BOUNCER_KEY_TRAEFIK : Sera généré après le premier démarrage de CrowdSec (voir Étape 4.2)

Info : Si vous utilisez OVH au lieu de Cloudflare, configurez OVH_ENDPOINT, OVH_APPLICATION_KEY, OVH_APPLICATION_SECRET et OVH_CONSUMER_KEY. Suivez la documentation OVH pour générer ces clés.

1.4 Configuration Authelia
#

Modifiez /opt/docker/frontend-stack/authelia/configuration.yml :

  1. Générez les secrets nécessaires :
# Génère 3 secrets de 32 caractères
openssl rand -base64 32
openssl rand -base64 32
openssl rand -base64 32
  1. Éditez le fichier :
vi /opt/docker/frontend-stack/authelia/configuration.yml
  1. Remplacez dans le fichier :

    • jwt_secret: "create_jwt_secret_here" → Premier secret généré
    • session.secret: "create_secret_session_here" → Deuxième secret
    • storage.encryption_key: "create_encryption_key_here" → Troisième secret
  2. Configurez votre domaine :

    • Remplacez mydomain.com par votre domaine réel
    • Adaptez les règles d’accès selon vos services
  3. Configurez le mot de passe Redis :

    • Remplacez from_redis_env_password par la valeur de ${REDIS_PASSWORD} du fichier .env
  4. Configurez SMTP (pour réinitialisation mot de passe) :

    • Si Gmail : activez les “App passwords” dans votre compte Google
    • Remplacez user@gmail.com et get_password_from_google

1.5 Configuration Traefik
#

Modifiez /opt/docker/frontend-stack/traefik/config.yml :

vi /opt/docker/frontend-stack/traefik/config.yml
  1. Remplacez tous les mydomain.com par votre domaine
  2. Choisissez votre resolver de certificats :
    • Ligne 21 : certResolver: cloudflare (ou ovh)
  3. Vérifiez votre email ACME dans les différents resolver

Modifiez /opt/docker/frontend-stack/traefik/rules/00-middlewares.yml :

vi /opt/docker/frontend-stack/traefik/rules/00-middlewares.yml
  1. Middleware CrowdSec : Mettez à jour les credentials Redis

    • Ligne 30 : redisCachePassword: "votre-mot-de-passe-redis"
    • Ligne 22 : crowdsecLapiKey sera mis à jour après génération (Étape 4.2)
  2. IPs de confiance : Ajustez clientTrustedIPs avec vos IPs publiques et réseau local

Attention : Ne commitez JAMAIS le fichier /opt/docker/frontend-stack/traefik/rules/00-middlewares.yml avec des vraies clés dans un dépôt public.

Étape 2 : Configuration du réseau Docker via docker-compose.yml
#

Le réseau Docker frontend est automatiquement créé lors du lancement de la stack via le fichier docker-compose.yml principal.

Vérifiez la configuration réseau dans /opt/docker/frontend-stack/docker-compose.yml :

---
include:
  - ./redis/docker-compose.yml
  - ./authelia/docker-compose.yml
  - ./traefik/docker-compose.yml
  - ./crowdsec/docker-compose.yml

networks:
  frontend:
    name: frontend              # Nom du réseau
    driver: bridge              # Type de réseau (bridge = réseau local isolé)
    ipam:
      config:
        - subnet: 172.18.0.0/16   # Plage d'adresses IP (65536 adresses)
          gateway: 172.18.0.1     # Passerelle du réseau

Pourquoi cette approche ?

Avantage de la définition dans docker-compose.yml :

  • Création automatique : Le réseau est créé lors du premier docker compose up -d
  • Gestion déclarative : La configuration réseau fait partie du projet, pas de commande CLI à retenir
  • Reproductibilité : La stack peut être déployée de manière identique sur plusieurs environnements
  • Pas de réseau orphelin : Le réseau est supprimé automatiquement avec docker compose down

Que se passe-t-il au lancement ?

Lors du docker compose up -d (Étape 3), Docker Compose :

  1. Vérifie si le réseau frontend existe
  2. Si non, le crée automatiquement avec la configuration spécifiée
  3. Connecte tous les services (Redis, Authelia, Traefik, CrowdSec) à ce réseau
  4. Attribue des adresses IP dans la plage 172.18.0.0/16

Vérification manuelle : Après le déploiement, vous pouvez inspecter le réseau avec :

docker network inspect frontend

Étape 3 : Lancement de la stack
#

# Se positionne dans le répertoire de la stack
cd /opt/docker/frontend-stack

# Lance tous les services en arrière-plan
docker compose up -d

Que se passe-t-il ?

  1. Docker Compose lit le fichier /opt/docker/frontend-stack/docker-compose.yml et inclut les 4 sous-stacks
  2. Les images sont téléchargées (première fois uniquement)
  3. Les services démarrent dans l’ordre des dépendances :
    • Redis démarre en premier (healthcheck actif)
    • Authelia attend que Redis soit healthy
    • Traefik attend qu’Authelia soit démarré
    • CrowdSec attend Redis (healthy) et Traefik (started)
  4. Les volumes sont créés et initialisés dans /opt/docker/frontend-stack/
  5. Traefik commence à générer les certificats SSL (peut prendre 1-2 minutes)

Vérifiez le démarrage :

# Affiche l'état de tous les conteneurs
docker compose ps

Sortie attendue :

NAME           IMAGE                         STATUS          PORTS
redis          redis:latest                  Up 1 minute     0.0.0.0:6379->6379/tcp
authelia       authelia/authelia:4.39.15     Up 1 minute     0.0.0.0:9091->9091/tcp
traefik        traefik:latest                Up 1 minute     0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:8080->8080/tcp
crowdsec       crowdsecurity/crowdsec:latest Up 30 seconds   0.0.0.0:8081->8080/tcp
redis-insight  redis/redisinsight:latest     Up 1 minute     0.0.0.0:5540->5540/tcp

Étape 4 : Configuration post-démarrage
#

4.1 Création du premier utilisateur Authelia
#

Générez un hash de mot de passe Argon2id :

# Génère un hash pour le mot de passe "VotreMotDePasse123!"
docker exec -it authelia authelia crypto hash generate argon2 --password 'VotreMotDePasse123!'

Il va s’en dire qu’il est nécessaire de remplacer VotreMotDePasse123! par un vrai mot de passe robuste et sécurisé.

Sortie exemple :

Digest: $argon2id$v=19$m=65536,t=3,p=4$abcdefghijklmnop$xyz123...

Créez le fichier utilisateurs :

vi /opt/docker/frontend-stack/authelia/users/config.yml

Contenu de /opt/docker/frontend-stack/authelia/users/config.yml :

---
users:
  myuser:
    displayname: "Administrateur"
    password: "$argon2id$v=19$m=65536,t=3,p=4$..."  # Hash généré ci-dessus
    email: admin@mydomain.com
    groups:
      - admins
      - users
Astuce : Ajoutez plusieurs utilisateurs en répétant la structure sous users:.

Vérifiez les permissions du fichier :

# Les fichiers doivent appartenir à l'utilisateur 1000:1000
chown 1000:1000 /opt/docker/frontend-stack/authelia/users/config.yml
chmod 644 /opt/docker/frontend-stack/authelia/users/config.yml

4.2 Configuration du bouncer CrowdSec
#

Générez la clé API du bouncer Traefik :

# Entre dans le conteneur CrowdSec
docker exec crowdsec cscli bouncers add crowdsec-bouncer-traefik-plugin

Sortie :

Api key for 'crowdsec-bouncer-traefik-plugin':
   abc123def456ghi789jkl...

Mettez à jour la configuration :

  1. Copiez la clé générée

  2. Éditez /opt/docker/frontend-stack/.env et remplacez la valeur de BOUNCER_KEY_TRAEFIK :

vi /opt/docker/frontend-stack/.env
  1. Éditez /opt/docker/frontend-stack/traefik/rules/00-middlewares.yml ligne 22 et renseignez la clé générée pour crowdsecLapiKey :
vi /opt/docker/frontend-stack/traefik/rules/00-middlewares.yml
  1. Redémarrez les services :
cd /opt/docker/frontend-stack
docker compose restart traefik crowdsec

4.3 Vérification des certificats SSL
#

Suivez la génération des certificats :

# Affiche les logs Traefik en temps réel
docker compose logs -f traefik

Recherchez les lignes :

time="..." level=info msg="Certificate obtained for domains [mydomain.com *.mydomain.com]"
time="..." level=info msg="Certificates obtained for domains"

Vérifiez le fichier ACME :

# Liste les certificats générés
cat /opt/docker/frontend-stack/traefik/certs/acme-cloudflare.json | grep -A 2 '"domain"'

Attention : Si les certificats ne se génèrent pas, vérifiez :

  • Les credentials API (Cloudflare ou OVH) dans /opt/docker/frontend-stack/.env
  • Les logs Traefik pour des erreurs DNS
  • Que votre domaine pointe bien vers votre IP publique (IP du serveur Proxmox ou du conteneur LXC si NAT)

Étape 5 : Accès et configuration initiale
#

5.1 Accès au dashboard Traefik
#

Ouvrez votre navigateur : http://10.99.99.10:8080 (remplacez par l’IP de votre conteneur LXC)

Vous devriez voir :

  • Tous les routers configurés
  • Les services backend
  • Les middlewares actifs
  • Les certificats générés
Sécurité : En production, désactivez le dashboard insecure (port 8080) ou protégez-le avec Authelia.

5.2 Première connexion Authelia
#

Accédez à : https://auth.mydomain.com

  1. Connectez-vous avec le compte créé à l’étape 4.1
  2. Configurez votre double facteur :
    • TOTP : Scannez le QR code avec Google Authenticator ou autre utilitaire 2FA
    • WebAuthn (optionnel) : Enregistrez une clé de sécurité (Yubikey, Touch ID)
  3. Testez la déconnexion/reconnexion

5.3 Vérification CrowdSec
#

Consultez les métriques CrowdSec :

# Affiche les métriques
docker exec crowdsec cscli metrics

# Liste les décisions actives (bans)
docker exec crowdsec cscli decisions list

Testez le blocage manuellement :

# Bannit votre IP pendant 4 heures (test)
docker exec crowdsec cscli decisions add --ip VOTRE_IP --duration 4h --reason "Test"

# Supprime le ban
docker exec crowdsec cscli decisions delete --ip VOTRE_IP

✅ Vérification et tests
#

Vérifier que tous les services sont démarrés
#

# Liste les conteneurs en cours d'exécution
cd /opt/docker/frontend-stack
docker compose ps

Sortie attendue :

NAME            STATUS          PORTS
redis           Up 10 minutes   0.0.0.0:6379->6379/tcp
authelia        Up 10 minutes   0.0.0.0:9091->9091/tcp
traefik         Up 10 minutes   0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:8080->8080/tcp
crowdsec        Up 10 minutes   0.0.0.0:8081->8080/tcp
redis-insight   Up 10 minutes   0.0.0.0:5540->5540/tcp

Tous les conteneurs doivent avoir le statut Up. Si un conteneur est en Restarting ou Exited, consultez les logs :

docker compose logs <nom-du-service>

Tests fonctionnels
#

Test 1 : Redirection HTTP vers HTTPS
#

# Teste la redirection automatique
curl -I http://mydomain.com

Résultat attendu :

HTTP/1.1 308 Permanent Redirect
Location: https://mydomain.com/

Test 2 : Validité SSL
#

# Vérifie le certificat SSL
openssl s_client -connect mydomain.com:443 -servername mydomain.com < /dev/null | grep -A 2 "Verify return code"

Résultat attendu :

Verify return code: 0 (ok)

Test 3 : Headers de sécurité
#

# Affiche les headers de sécurité
curl -I https://mydomain.com

Headers attendus :

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin

Test 4 : Authentification Authelia
#

Accédez à un service protégé (configuré avec policy: two_factor) :

  1. Vous êtes redirigé vers https://auth.mydomain.com
  2. Connectez-vous avec vos identifiants
  3. Saisissez le code TOTP
  4. Vous êtes redirigé vers le service demandé

Test 5 : Protection CrowdSec
#

Simulez une attaque par brute-force :

# Tente 20 connexions échouées sur Authelia
for i in {1..20}; do
  curl -X POST https://auth.mydomain.com/api/firstfactor \
    -H "Content-Type: application/json" \
    -d '{"username":"admin","password":"wrong"}'
done

Vérifiez le ban :

docker exec crowdsec cscli decisions list

Vous devriez voir votre IP bannie avec le scénario crowdsecurity/authelia-bf.

Supprimez le ban :

docker exec crowdsec cscli decisions delete --ip VOTRE_IP

Vérification des logs
#

Logs de tous les services
#

# Affiche les logs en temps réel
cd /opt/docker/frontend-stack
docker compose logs -f

# Logs d'un service spécifique
docker compose logs -f traefik
docker compose logs -f authelia
docker compose logs -f crowdsec

Logs Traefik détaillés
#

# Logs d'accès (toutes les requêtes)
tail -f /opt/docker/frontend-stack/traefik/logs/access.log

# Logs d'erreurs uniquement
tail -f /opt/docker/frontend-stack/traefik/logs/error.log

Logs Authelia
#

# Logs Authelia (connexions, échecs, etc.)
tail -f /opt/docker/frontend-stack/authelia/logs/authelia.log

Signaux d’alerte :

Message Signification Solution
Failed to connect to Redis Authelia ne peut pas joindre Redis Vérifiez le mot de passe Redis dans /opt/docker/frontend-stack/authelia/configuration.yml
TLS challenge failed Échec génération certificat Vérifiez les credentials API DNS dans /opt/docker/frontend-stack/.env
Error 502 Bad Gateway Service backend non joignable Vérifiez que le service existe et est démarré
authentication failed (Authelia) Échec connexion utilisateur Vérifiez le hash de mot de passe dans /opt/docker/frontend-stack/authelia/users/config.yml
crowdsec LAPI unreachable Le bouncer ne peut pas joindre CrowdSec Vérifiez la BOUNCER_KEY_TRAEFIK dans /opt/docker/frontend-stack/.env et /opt/docker/frontend-stack/traefik/rules/00-middlewares.yml

Vérification Redis
#

Accédez à Redis Insight : http://10.99.99.10:5540 (remplacez par l’IP de votre conteneur LXC)

  1. Ajoutez une connexion :
    • Host: redis
    • Port: 6379
    • Password: le contenur de ${REDIS_PASSWORD} dans .env
  2. Explorez les bases de données :
    • DB 0 : Sessions Authelia (clés authelia-session:*)
    • DB 5 : Cache CrowdSec (clés crowdsec:*)

Alternativement, via CLI :

# Se connecte à Redis
docker exec -it redis redis-cli -a "${REDIS_PASSWORD}"

# Liste les clés de la base 0 (sessions Authelia)
SELECT 0
KEYS authelia-session:*

# Liste les clés de la base 5 (cache CrowdSec)
SELECT 5
KEYS crowdsec:*

🔧 Maintenance et monitoring
#

Commandes utiles au quotidien
#

Toutes les commandes doivent être exécutées depuis /opt/docker/frontend-stack.

Redémarrer un service
#

cd /opt/docker/frontend-stack

# Redémarre un service spécifique
docker compose restart traefik
docker compose restart authelia
docker compose restart crowdsec

Mettre à jour la stack
#

cd /opt/docker/frontend-stack

# Récupère les dernières images
docker compose pull

# Reconstruit et redémarre (sans interruption grâce à rolling update)
docker compose up -d

Arrêter la stack
#

cd /opt/docker/frontend-stack

# Arrête tous les services (conserve les données)
docker compose down

Sauvegarder les données
#

Pensez à sauvegarder les données contenues dans le dossier racine du projet, c’est-à-dire /opt/docker/frontend-stack. Cela fera l’objet d’un autre article de blog sur la sauvegarde avec l’utilitaire Restic.

Monitoring des ressources
#

Utilisation CPU/RAM en temps réel
#

# Affiche les stats de tous les conteneurs
docker stats

# Stats d'un seul conteneur
docker stats traefik

Consommation attendue (à vide) :

  • Redis : ~10 MB RAM, <1% CPU
  • Authelia : ~50-80 MB RAM, <1% CPU
  • Traefik : ~40-60 MB RAM, 1-2% CPU
  • CrowdSec : ~100-150 MB RAM, 1-3% CPU

Espace disque des volumes
#

# Affiche l'espace utilisé par Docker
docker system df -v

# Affiche l'espace utilisé par la stack
du -sh /opt/docker/frontend-stack/*

Logs système (dans le conteneur LXC)
#

Vérifiez les journaux système pour détecter des problèmes matériels :

# Logs du daemon Docker (dans le conteneur LXC)
sudo journalctl -u docker -f

Monitoring depuis Proxmox
#

Depuis l’interface web Proxmox ou en ligne de commande :

# Affiche les ressources du conteneur LXC 110
pct status 110

# Affiche les statistiques détaillées
pct exec 110 -- top

Nettoyage et maintenance
#

Nettoyage sélectif
#

# Supprime les images inutilisées (anciennes versions)
docker image prune -a

# Supprime les conteneurs arrêtés
docker container prune

# Supprime les volumes non utilisés
docker volume prune

Nettoyage complet
#

# Supprime tout ce qui n'est pas utilisé (conteneurs, images, volumes, networks)
docker system prune -a

# ⚠️ DANGER : Supprime aussi les volumes (perte de données)
docker system prune -a --volumes
Attention : docker system prune -a --volumes supprimera TOUTES les données persistantes (Redis, Authelia, CrowdSec). N’utilisez cette commande qu’après une sauvegarde complète.

Rotation des logs
#

Les logs Traefik et Authelia peuvent rapidement consommer de l’espace disque. Configurez une rotation automatique via l’utilisature logrotate.

Généralement, cet utilitaire fait parti des packages par défaut de la distribution. Si toutefois, logrotate n’est pas installé sur votre système, installez-le :

sudo apt install -y logrotate

Dans le conteneur LXC, créez le fichier de configuration /etc/logrotate.d/frontend-stack :

vi /etc/logrotate.d/frontend-stack

Contenu :

/opt/docker/frontend-stack/traefik/logs/*.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d
    copytruncate
    sharedscripts
    create 0644 1000 1000
}

/opt/docker/frontend-stack/authelia/logs/*.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    dateext
    dateformat -%Y%m%d
    copytruncate
    sharedscripts
    create 0644 1000 1000
}

Explication de la configuration :

Directive Description
daily Rotation quotidienne des logs
rotate 14 Conserve 14 jours d’historique (2 semaines)
missingok Ne génère pas d’erreur si le fichier de log est manquant
notifempty Ne fait pas de rotation si le fichier est vide
compress Compresse les anciens logs avec gzip
delaycompress Compresse le fichier lors de la rotation suivante (pour laisser le temps à CrowdSec de lire les logs)
dateext Ajoute une date au nom du fichier rotaté
dateformat -%Y%m%d Format de date : -20250327 (année-mois-jour)
copytruncate Copie le fichier puis le tronque (évite de devoir recharger les services Docker)
sharedscripts Exécute les scripts post-rotation une seule fois pour tous les fichiers
create 0644 1000 1000 Crée un nouveau fichier avec permissions 0644 et propriétaire 1000:1000 (myuser)
Astuce : L’option copytruncate est essentielle ici car elle permet de faire la rotation sans avoir à redémarrer les conteneurs Traefik et Authelia. Les logs continuent d’être écrits dans le même fichier (maintenant vide).

Test de la configuration :

# Test de la configuration logrotate (dry-run)
sudo logrotate -d /etc/logrotate.d/frontend-stack

# Force une rotation manuelle (pour tester)
sudo logrotate -f /etc/logrotate.d/frontend-stack

Monitoring avancé (optionnel)
#

Pour un monitoring professionnel, intégrez une stack Prometheus + Grafana :

  1. Traefik : Exposez les métriques sur un endpoint dédié
  2. Redis : Utilisez redis_exporter
  3. CrowdSec : Utilisez les métriques intégrées
  4. Authelia : Exposez les métriques Prometheus (expérimental)
  5. Proxmox : Exportez les métriques LXC vers Prometheus

Exemple de dashboard Grafana : https://grafana.com/grafana/dashboards/17346

🔍 Troubleshooting
#

Arbre de décision diagnostique
#

Utilisez ce diagramme pour diagnostiquer rapidement les problèmes courants :

flowchart TD
    Start([Problème détecté]) --> CheckContainers{Tous les conteneurs
sont Up?} CheckContainers -->|Non| CheckLogs[Vérifier logs
docker compose logs] CheckContainers -->|Oui| CheckSSL{Certificats SSL
valides?} CheckLogs --> DockerIssue{Erreur Docker?} DockerIssue -->|Permissions| FixPerms[Corriger permissions
chown 1000:1000] DockerIssue -->|Redis| FixRedis[Vérifier mot de passe
Redis] DockerIssue -->|Network| FixNetwork[Recréer réseau
frontend] CheckSSL -->|Non| CheckCreds[Vérifier credentials
API DNS .env] CheckSSL -->|Oui| CheckAuth{Authelia
fonctionne?} CheckAuth -->|Non| CheckAuthConfig[Vérifier configuration.yml
et secrets] CheckAuth -->|Oui| CheckCrowdSec{CrowdSec
bloque?} CheckCrowdSec -->|Oui| UnbanIP[Débannir IP
cscli decisions delete] CheckCrowdSec -->|Non| CheckTraefik[Vérifier routes Traefik
dashboard :8080] FixPerms --> Restart[Redémarrer services] FixRedis --> Restart FixNetwork --> Restart CheckCreds --> RestartTraefik[Redémarrer Traefik] CheckAuthConfig --> RestartAuthelia[Redémarrer Authelia] UnbanIP --> TestAgain[Retester l'accès] CheckTraefik --> TestAgain Restart --> Resolved{Problème
résolu?} RestartTraefik --> Resolved RestartAuthelia --> Resolved TestAgain --> Resolved Resolved -->|Oui| Success([✓ Production]) Resolved -->|Non| Support[Consulter FAQ
et/ou recherche Internet] style Start fill:#e1f5ff,color:#000 style Success fill:#d4edda,color:#000 style Support fill:#fff3cd,color:#000 style Resolved fill:#f8d7da,color:#000

Problème 1 : Le conteneur LXC ne peut pas exécuter Docker
#

Symptômes :

  • Erreur au démarrage de Docker : Failed to start docker.service
  • Erreur : cgroup mountpoint does not exist
  • Docker démarre mais les conteneurs échouent

Cause probable :

  • Fonctionnalités nesting et keyctl non activées sur le conteneur LXC
  • Conteneur créé en mode privilégié (incompatible avec Docker)

Solution :

  1. Arrêtez le conteneur LXC :
# Depuis le serveur Proxmox
pct stop 110
  1. Vérifiez et modifiez la configuration :
# Éditez la configuration du conteneur
vi /etc/pve/lxc/110.conf

Vérifiez que ces lignes sont présentes :

unprivileged: 1
features: nesting=1,keyctl=1
  1. Redémarrez le conteneur :
pct start 110
  1. Vérifiez Docker :
pct enter 110
docker --version
systemctl status docker

Comment éviter ce problème :

  • Toujours créer les conteneurs LXC pour Docker avec --unprivileged 0 --features nesting=1,keyctl=1
  • Utilisez le template Debian 13 officiel de Proxmox

Problème 2 : Traefik ne génère pas les certificats SSL
#

Symptômes :

  • Erreur SSL dans le navigateur (“Connexion non sécurisée”)
  • Fichier /opt/docker/frontend-stack/traefik/certs/acme-cloudflare.json vide ou avec erreurs
  • Logs Traefik : unable to generate a certificate for domains

Cause probable :

  • Credentials API DNS incorrects ou manquants
  • Propagation DNS trop lente
  • Rate limit Let’s Encrypt atteint (5 certificats par domaine/semaine)
  • Domaine ne pointe pas vers l’IP correcte

Solution :

  1. Vérifiez les credentials dans /opt/docker/frontend-stack/.env :
# Affichez les variables (masquez si nécessaire)
cat /opt/docker/frontend-stack/.env | grep CF_DNS_API_TOKEN
cat /opt/docker/frontend-stack/.env | grep OVH_
  1. Testez manuellement l’API Cloudflare :
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
  -H "Authorization: Bearer ${CF_DNS_API_TOKEN}"

Réponse attendue : "status": "active"

  1. Augmentez le délai de propagation DNS dans /opt/docker/frontend-stack/traefik/config.yml :
dnsChallenge:
  provider: cloudflare
  propagation:
    delayBeforeChecks: 120  # Augmentez à 120 secondes
  1. Utilisez d’abord le staging (évite rate limit) dans /opt/docker/frontend-stack/traefik/config.yml :
# Ligne 21
certResolver: cloudflare-staging

Vérifiez que le certificat staging est généré, puis repassez en production.

  1. Redémarrez Traefik et suivez les logs :
cd /opt/docker/frontend-stack
docker compose restart traefik
docker compose logs -f traefik

Comment éviter ce problème :

  • Testez toujours avec le staging avant la production
  • Documentez vos credentials API dans un gestionnaire de secrets
  • Configurez des alertes sur les expirations de certificats (90 jours)

Problème 3 : Permissions refusées sur les fichiers de configuration
#

Symptômes :

  • Authelia ne démarre pas : Permission denied: /config/configuration.yml
  • CrowdSec ne peut pas lire les logs : Permission denied: /var/log/traefik/access.log
  • Erreurs de permissions dans les logs Docker

Cause probable :

  • Les fichiers/dossiers n’appartiennent pas à l’utilisateur 1000:1000
  • Permissions trop restrictives sur les fichiers

Solution :

  1. Corrigez les permissions de toute la stack :
# Donne les droits à l'utilisateur 1000:1000 (myuser)
chown -R 1000:1000 /opt/docker/frontend-stack

# Définit les permissions correctes
chmod -R 755 /opt/docker/frontend-stack
chmod 644 /opt/docker/frontend-stack/.env
chmod 644 /opt/docker/frontend-stack/authelia/configuration.yml
chmod 644 /opt/docker/frontend-stack/authelia/users/config.yml
  1. Vérifiez les permissions :
ls -la /opt/docker/frontend-stack/
ls -la /opt/docker/frontend-stack/authelia/
  1. Redémarrez les services :
cd /opt/docker/frontend-stack
docker compose restart

Comment éviter ce problème :

  • Toujours créer les fichiers en tant qu’utilisateur myuser (UID 1000)
  • Utiliser chown -R 1000:1000 après chaque création de fichiers
  • Vérifier les permissions avant de démarrer la stack

Problème 4 : Redis refuse les connexions (Authelia ou CrowdSec)
#

Symptômes :

  • Authelia : Failed to connect to session provider: dial tcp 172.18.0.X:6379: i/o timeout
  • CrowdSec bouncer : redis connection refused

Cause probable :

  • Mot de passe Redis incorrect
  • Redis non démarré ou crashé
  • Configuration réseau incorrecte

Solution :

  1. Vérifiez que Redis est démarré et healthy :
cd /opt/docker/frontend-stack
docker compose ps redis
# Doit afficher "Up" et "healthy"

Si unhealthy ou Restarting :

docker compose logs redis
  1. Testez la connexion Redis manuellement :
docker exec -it redis redis-cli -a "${REDIS_PASSWORD}" PING

Réponse attendue : PONG

Si erreur NOAUTH → Mot de passe incorrect.

  1. Vérifiez la cohérence des mots de passe :
  • /opt/docker/frontend-stack/.env : REDIS_PASSWORD=...
  • /opt/docker/frontend-stack/authelia/configuration.yml : session.redis.password: "..."
  • /opt/docker/frontend-stack/traefik/rules/00-middlewares.yml : redisCachePassword: "..."

Tous doivent être identiques.

  1. Si Redis ne démarre pas, vérifiez les permissions :
chown -R 999:999 /opt/docker/frontend-stack/redis/data
  1. Redémarrez dans l’ordre :
cd /opt/docker/frontend-stack
docker compose restart redis
# Attendez 10 secondes (healthcheck)
docker compose restart authelia crowdsec traefik

Comment éviter ce problème :

  • Centralisez les mots de passe Redis dans /opt/docker/frontend-stack/.env uniquement
  • Testez Redis avec redis-cli PING après chaque modification
  • Configurez le healthcheck Redis (déjà présent dans la stack)

FAQ
#

Q : Puis-je utiliser cette stack avec Docker Swarm ou Kubernetes ? R : Cette configuration est optimisée pour Docker Compose sur LXC. Pour Swarm, vous devrez adapter les volumes en volumes nommés et les réseaux en overlay. Pour Kubernetes, n’ayant aucune expérience avec cette techno, je vous laisse tester !

Q : Comment sauvegarder le conteneur LXC complet ? R : Depuis Proxmox :

# Crée une sauvegarde complète du conteneur LXC 110
vzdump 110 --dumpdir /var/lib/vz/dump --mode snapshot

Q : Comment migrer la stack vers un autre serveur Proxmox ? R :

  1. Sauvegardez le conteneur LXC avec vzdump
  2. Copiez l’archive vers le nouveau serveur Proxmox
  3. Restaurez le conteneur avec pct restore
  4. Adaptez la configuration réseau si nécessaire

Q : Quelle est la consommation de ressources totale de la stack ? R : À vide (sans charge) :

  • CPU : ~5-10% (2 cœurs)
  • RAM : ~500-700 MB
  • Disque : ~2-3 GB

En production avec trafic modéré :

  • CPU : ~10-20%
  • RAM : ~1-2 GB
  • Disque : ~5-10 GB (avec logs et données)

Q : Puis-je accéder au dashboard Traefik depuis l’extérieur ? R : Par défaut, non (le port 8080 n’est exposé qu’en local). Pour y accéder en sécurité :

  • Option 1 : Tunnel SSH depuis votre poste : ssh -L 8080:localhost:8080 user@proxmox-host
  • Option 2 : Protégez-le avec Authelia en créant une route dans /opt/docker/frontend-stack/traefik/rules/100-frontend.yml

Q : CrowdSec va-t-il me bannir si je me trompe de mot de passe ? R : Oui, après 3 tentatives échouées en 2 minutes (configuré dans /opt/docker/frontend-stack/authelia/configuration.ymlregulation). Pour vous débannir :

docker exec crowdsec cscli decisions delete --ip VOTRE_IP

Q : Comment ajouter un nouveau service derrière Traefik + Authelia ? R : Créez un fichier de routage Traefik au format YAML dans /opt/docker/frontend-stack/traefik/rules/ :

http:
  routers:
    mon-service:
      entryPoints:
        - websecure
      rule: Host(`mon-service.mydomain.com`)
      service: mon-service

  services:
    mon-service:
      loadBalancer:
        servers:
          - url: http://ip-du-service:port

N’oubliez pas d’ajoutez une règle dans /opt/docker/frontend-stack/authelia/configuration.yml pour définir la politique d’accès.

⚡ Optimisations et bonnes pratiques
#

Sécurité
#

1. Gestion des secrets
#

✅ À faire :

  • Ne jamais commiter /opt/docker/frontend-stack/.env ou les fichiers avec clés API
  • Limiter l’accès SSH au conteneur LXC

❌ À éviter :

  • Mettre des mots de passe en clair dans docker-compose.yml
  • Partager .env par email ou chat
  • Utiliser des mots de passe faibles (< 16 caractères)

2. Durcissement du conteneur LXC
#

✅ À faire :

  • Limiter les capabilities dans la configuration LXC
  • Configurer un pare-feu au niveau de Proxmox (firewall) ou de votre routeur qui gère le réseau

3. Mises à jour de sécurité
#

Effectuez les mises à jour sur le serveur régulièrement. Assurez-vous également que les MAJ ne cassent pas la machine LXC comme c’était le cas avec le passage des nouvelles versions de Docker en novembre 2025 pour les conteneurs LXC.

Rappel : Sauvegardez toujours le conteneur LXC avant les mises à jour majeures.

Performance
#

1. Optimisation Redis
#

Pour un environnement de production avec beaucoup de sessions, éditez /opt/docker/frontend-stack/redis/docker-compose.yml :

command: >
  redis-server
  --save 900 1        # Sauvegarde moins fréquente
  --maxmemory 512mb   # Limite mémoire
  --maxmemory-policy allkeys-lru  # Éviction LRU si plein

2. Optimisation du conteneur LXC
#

Allouez plus de ressources si nécessaire :

# Depuis le serveur Proxmox
pct set 110 --memory 8192  # 8 GB de RAM
pct set 110 --cores 4      # 4 cœurs CPU
pct set 110 --rootfs local-lvm:32  # Étend le disque à 32 GB

3. Compression et HTTP/2
#

La compression est déjà activée dans chain-secure. Vérifiez que HTTP/2 est actif :

curl -I --http2 https://mydomain.com | grep HTTP

Réponse attendue : HTTP/2 200

Logs et observabilité
#

Configuration recommandée pour les logs
#

On a déjà limité la taille des fichiers logs via logrotate mais cette fonctionnalité peut-être déployée via docker compose.

Limitez la taille des logs Docker dans chaque docker-compose.yml :

# À ajouter à chaque service
logging:
  driver: "json-file"
  options:
    max-size: "10m"   # Maximum 10 MB par fichier
    max-file: "3"     # Conserve 3 fichiers (30 MB total)

Bonnes pratiques générales
#

✅ À faire :

  • Documenter toutes les modifications dans un fichier CHANGELOG
  • Sauvegarder le conteneur LXC régulièrement
  • Monitorer les métriques (CPU, RAM, logs)
  • Configurer des snapshots LXC avant les mises à jour majeures
  • Tester en staging (clone LXC) avant production

❌ À éviter :

  • Modifier directement en production sans backup
  • Utiliser latest en production (préférez des tags versionnés)
  • Exposer les dashboards et APIs sans authentification
  • Ignorer les mises à jour de sécurité

🎯 Conclusion
#

Vous disposez maintenant d’une stack frontend complète, sécurisée et prête pour la production !

Dans cet article, vous avez appris à :

  • Créer et configurer un conteneur LXC Debian 13 sur Proxmox pour héberger Docker
  • Déployer une infrastructure frontend complète avec Docker Compose dans /opt/docker/frontend-stack
  • Configurer un reverse proxy Traefik avec génération automatique de certificats SSL wildcard
  • Mettre en place une authentification avec double facteur via Authelia
  • Protéger vos services contre les cyberattaques avec CrowdSec et son AppSec WAF
  • Optimiser les performances avec Redis comme cache distribué
  • Gérer les permissions avec un utilisateur dédié (UID 1000)
  • Maintenir et monitorer votre stack en production sur Proxmox LXC

Cette stack est maintenant prête pour un environnement de production en homelab.

Ressources complémentaires
#

Documentation officielle
#

Communautés et support
#

Besoin d’aide ?
#

N’hésitez pas à :

  • Laisser un commentaire ci-dessous avec vos questions ou vos compléments, corrections !

Cet article vous a été utile ? Partagez-le sur vos réseaux sociaux et laissez un commentaire avec vos retours d’expérience ou vos configurations spécifiques !
Perfect Homelab - Cet article fait partie d'une série.
Partie 8: Cet article

Articles connexes