Security Stack : Caddy + CrowdSec
1. Quoi ? — Définition et contexte
Section intitulée « 1. Quoi ? — Définition et contexte »La Security Stack est la couche de protection qui se place entre Internet et tous les services de l’infrastructure. Elle combine deux composants :
| Composant | Rôle | Port |
|---|---|---|
| Caddy | Reverse proxy avec TLS automatique et HTTP/3 | 80, 443, 443/udp |
| CrowdSec | WAF comportemental et threat intelligence collaborative | 8080 (LAPI), 7422 (AppSec) |
| Trivy | Scanner CVE pour images Docker, appelé via docker exec | aucun port exposé |
Architecture visuelle
Section intitulée « Architecture visuelle »2. Pourquoi ? — Enjeux et motivations
Section intitulée « 2. Pourquoi ? — Enjeux et motivations »Pourquoi Caddy plutôt que Nginx ou Traefik ?
Section intitulée « Pourquoi Caddy plutôt que Nginx ou Traefik ? »| Critère | Caddy | Nginx | Traefik |
|---|---|---|---|
| TLS automatique | Natif (Let’s Encrypt) | Certbot externe | Natif |
| HTTP/3 QUIC | Natif | Module expérimental | Non |
| Configuration | Caddyfile simple | nginx.conf verbeux | YAML/Labels |
| Rechargement | Sans interruption | Reload graceful | Sans interruption |
| CrowdSec | Module bouncer officiel | Module lua | Plugin tiers |
Critères de décision :
- Simplicité — La syntaxe Caddyfile est lisible et concise
- TLS zéro-config — Certificats Let’s Encrypt automatiques, pas de cron Certbot
- Intégration CrowdSec native — Module bouncer officiel, pas de workaround
Qu’est-ce que CrowdSec apporte ?
Section intitulée « Qu’est-ce que CrowdSec apporte ? »| Fonction | Bénéfice |
|---|---|
| Threat intelligence collaborative | Les IPs malveillantes détectées par d’autres instances CrowdSec sont partagées |
| Scénarios de détection | Règles prêtes pour HTTP, SSH, CVE connus |
| Bouncer temps réel | Les IPs bannies sont bloquées avant d’atteindre le backend |
| Whitelists automatiques | Bots légitimes (Googlebot, etc.) ne sont pas bloqués |
3. Comment ? — Mise en œuvre technique
Section intitulée « 3. Comment ? — Mise en œuvre technique »Configuration Caddyfile
Section intitulée « Configuration Caddyfile »{ # Options globales email admin@guigpap.com
# Module CrowdSec crowdsec { api_url http://crowdsec:8080 api_key {env.CROWDSEC_API_KEY} ticker_interval 15s }}
# Redirection www → apexwww.guigpap.com { redir https://guigpap.com{uri} permanent}
# Site principalguigpap.com { crowdsec
header { Strict-Transport-Security "max-age=31536000; includeSubDomains" X-Content-Type-Options "nosniff" X-Frame-Options "DENY" Referrer-Policy "strict-origin-when-cross-origin" }
reverse_proxy blog:4321}
# N8N avec webhooks protégésn8n.guigpap.com { crowdsec
# Bloquer les webhooks internes depuis l'extérieur @blocked_webhooks { path /webhook/notify/* path /webhook/prometheus/* path /webhook/claude/* path /webhook/claude-simple-chat path /webhook/docker-controller path /webhook/odoo/* } respond @blocked_webhooks 403
reverse_proxy n8n:5678}
# Autres servicesgrafana.guigpap.com { crowdsec reverse_proxy grafana:3000}
odoo.guigpap.com { crowdsec reverse_proxy odoo:8069}Collections CrowdSec installées
Section intitulée « Collections CrowdSec installées »# Lister les collections activesdocker exec crowdsec cscli collections list| Collection | Rôle |
|---|---|
crowdsecurity/caddy | Parser des logs Caddy |
crowdsecurity/base-http-scenarios | Détection attaques HTTP courantes |
crowdsecurity/http-cve | Exploits CVE connus |
crowdsecurity/appsec-virtual-patching | Patching virtuel |
crowdsecurity/linux | Scénarios système Linux |
crowdsecurity/sshd | Détection brute force SSH |
crowdsecurity/whitelist-good-actors | Liste blanche bots légitimes |
Comment fonctionne le bouncer
Section intitulée « Comment fonctionne le bouncer »- Caddy reçoit une requête
- Le module bouncer interroge l’API CrowdSec (cache local)
- Si l’IP est dans la liste de décisions → 403 Forbidden
- Sinon → requête transmise au backend
Protection des webhooks internes
Section intitulée « Protection des webhooks internes »| Webhook | Appelé par | Bloqué depuis Internet |
|---|---|---|
/webhook/notify/* | DIUN | Oui |
/webhook/prometheus/* | Alertmanager | Oui |
/webhook/claude/* | CLI Ollama | Oui |
/webhook/claude-simple-chat, /webhook/claude-approve, /webhook/claude-reject | N8N | Oui |
/webhook/odoo/* | Odoo internal | Oui |
/webhook/docker-controller | Telegram Orchestrator | Oui |
/webhook/notification-hub | N8N (Execute Workflow) | Oui |
Les services internes appellent ces webhooks via http://n8n:5678 (réseau Docker), pas via le domaine public.
Rate limiting et AppSec WAF
Section intitulée « Rate limiting et AppSec WAF »Les routes webhooks de n8n.guigpap.com sont rate-limitées à 30 requêtes/minute par IP via le module caddy-ratelimit. Cela complète l’auth (Bearer / Header / HMAC) en empêchant le brute-force sur les endpoints exposés. CrowdSec AppSec écoute en parallèle sur le port 7422 et rejoue les règles crowdsecurity/appsec-virtual-patching + appsec-generic-rules avant que les requêtes atteignent les backends.
Crawlers IA et llms.txt
Section intitulée « Crawlers IA et llms.txt »Le blog (blog.guigpap.com) sert volontairement deux artefacts pour les crawlers IA (ChatGPT, Gemini, Perplexity, etc.) :
-
/llms.txtet/llms-full.txt— index machine-readable des articles du blog, déclarés via headerLink:header Link "</llms.txt>; rel=\"llms-txt\", </llms-full.txt>; rel=\"llms-full-txt\""header X-Llms-Txt "/llms.txt" -
Mirrors Markdown — chaque article a un jumeau
.mdqui rend la version source. Caddy forceContent-Type: text/plainau lieu detext/markdownparce que les parseurs des crawlers grand public laissent passer plain text mais ignorent souventtext/markdown:@markdown_mirror path_regexp md_ext \.md$header @markdown_mirror {Content-Type "text/plain; charset=utf-8"defer}
La CSP du blog autorise 'wasm-unsafe-eval' (pour Pagefind, le moteur de recherche statique) et les data: URIs côté font-src (pour les sous-ensembles fontsource embarqués) :
header Content-Security-Policy "default-src 'self'; \ script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'; \ style-src 'self' 'unsafe-inline'; \ img-src 'self' data:; \ font-src 'self' data:"CrowdSec : image Debian + détection SSH
Section intitulée « CrowdSec : image Debian + détection SSH »L’engine CrowdSec utilise l’image latest-debian (et non Alpine) car le VPS Debian 13 expose ses logs SSH uniquement via journald — il n’y a pas de /var/log/auth.log. L’image Debian inclut journalctl ; l’image Alpine ne l’a pas. Le container monte /var/log/journal, /run/log/journal et /etc/machine-id du host.
| Layer | Rôle | Application |
|---|---|---|
| CrowdSec + Caddy bouncer | HTTP/HTTPS | Block via Caddy (403) |
| CrowdSec SSH detection | Brute-force SSH | Détection seule (pas de bouncer host) |
| fail2ban | Enforcement SSH | Ban via nftables (inet f2b-table) |
| UFW | Firewall baseline | Ports 22, 80, 443 uniquement |
Commandes d’exploitation
Section intitulée « Commandes d’exploitation »# Gestion CrowdSecdocker exec crowdsec cscli decisions list # IPs banniesdocker exec crowdsec cscli decisions delete --ip 1.2.3.4 # Débannirdocker exec crowdsec cscli alerts list # Alertes récentesdocker exec crowdsec cscli metrics # Statistiques
# Gestion Caddydocker exec caddy caddy validate --config /etc/caddy/Caddyfiledocker exec caddy caddy reload --config /etc/caddy/Caddyfiledocker logs caddy --tail 100
# Trivy : scan d'une imagedocker exec trivy trivy image --format json \ --severity CRITICAL,HIGH --ignore-unfixed postgres:174. Et si ? — Perspectives et limites
Section intitulée « 4. Et si ? — Perspectives et limites »Retour d’expérience actuel
Section intitulée « Retour d’expérience actuel »Limites actuelles
Section intitulée « Limites actuelles »| Limite | Impact | Mitigation |
|---|---|---|
| Pas de HA Caddy | Single point of failure | Monitoring + restart auto |
| CrowdSec non testé en charge | Comportement inconnu sous attaque DDoS | Rate limiting amont possible |
| Faux positifs possibles | IPs légitimes potentiellement bloquées | Whitelist manuelle à prévoir |
Scénarios d’évolution
Section intitulée « Scénarios d’évolution »Si des faux positifs apparaissent :
- Créer des whitelists par IP ou par User-Agent
- Ajuster les seuils des scénarios (
cscli scenarios inspect) - Désactiver des scénarios trop agressifs
Si la charge augmente :
- Activer le mode streaming Caddy pour les gros fichiers
- Ajouter un cache (Varnish) devant certains services
- Considérer un CDN (Cloudflare) pour le contenu statique
Si une attaque DDoS survient :
- CrowdSec détecte mais ne suffit pas seul
- Activer le mode Under Attack de Cloudflare
- Contacter l’hébergeur pour mitigation amont
Métriques à surveiller
Section intitulée « Métriques à surveiller »| Métrique | Source | Seuil d’attention |
|---|---|---|
| IPs bannies/jour | cscli decisions list | > 100 = vérifier les scénarios |
| Alertes HTTP | cscli alerts list | Spike soudain = attaque potentielle |
| 403 responses | Logs Caddy | Taux anormal = faux positifs possibles |
Pages liées
Section intitulée « Pages liées »Infrastructure
Section intitulée « Infrastructure »- Architecture VPS — Vue d’ensemble
- Monitoring Stack — Métriques Caddy
Référence
Section intitulée « Référence »- Glossaire — WAF, Bouncer, TLS, Reverse Proxy