# Déploiement fail2ban durci — dash.seoinsight.app

Cible : `sgwsnlcupaqyxdqux@163.172.71.169` (Ubuntu 26.04, nftables, Nginx, sans CDN).
Fichiers produits par l'audit dans `deploy/` :
- `deploy/jail.local` → `/etc/fail2ban/jail.local`
- `deploy/filter.d/nginx-badscan.conf` → `/etc/fail2ban/filter.d/nginx-badscan.conf`

---

## ⚠️ AVANT TOUT — éviter de te bannir (SANS IP fixe)

Pas d'IP fixe -> on ne compte PAS sur `ignoreip`. `sshd` est en `mode=normal` +
`maxretry=3`, et **ta vraie protection est le SSH par clé** : une connexion par clé
réussie ne matche jamais les règles fail2ban, donc tu ne peux quasi pas t'auto-bannir.

1. **Durcis SSH en clé-only d'abord** (tu te connectes déjà par clé) :
   ```fish
   ./harden-ssh.sh
   ```
   Ça coupe l'auth par mot de passe et teste automatiquement ta reconnexion par clé.
2. Garde sous la main l'accès **console Scaleway** (KVM/rescue) — filet ultime si SSH se ferme.
3. (Optionnel) Si tu veux quand même un whitelist : mets un **nom d'hôte DynDNS**
   (duckdns/no-ip/box) dans `ignoreip` — fail2ban le résout périodiquement.

> Le plus simple : lance `./harden-ssh.sh` puis `./deploy-all.sh` (déploie Nginx + fail2ban
> et refuse de partir si le password SSH est encore actif).

---

## 1. Variables

```fish
set SRV sgwsnlcupaqyxdqux@163.172.71.169
set DEP "/Users/humperdoo/Documents/seo insight/serveur/fail2ban/deploy"
```

## 2. Envoyer les fichiers (dans /tmp, puis mise en place avec sudo)

```fish
scp "$DEP/jail.local"                  $SRV:/tmp/jail.local
scp "$DEP/filter.d/nginx-badscan.conf" $SRV:/tmp/nginx-badscan.conf
```

## 3. Mettre en place, tester, appliquer

```fish
ssh -tt $SRV '
  set -e
  # Sauvegarde de l ancien jail.local (horodatée)
  sudo cp -a /etc/fail2ban/jail.local /etc/fail2ban/jail.local.bak.$(date +%Y%m%d-%H%M%S)

  # Mise en place
  sudo install -m 644 -o root -g root /tmp/jail.local           /etc/fail2ban/jail.local
  sudo install -m 644 -o root -g root /tmp/nginx-badscan.conf   /etc/fail2ban/filter.d/nginx-badscan.conf
  rm -f /tmp/jail.local /tmp/nginx-badscan.conf

  # Vérif : le filtre custom matche bien tes scans .env réels
  echo "===== TEST FILTRE nginx-badscan (doit trouver des matches) ====="
  sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-badscan.conf | grep -E "Failregex|matches|lines"

  # Vérif syntaxe globale
  echo "===== TEST CONF GLOBALE ====="
  sudo fail2ban-client -t
'
```

**Ne continue que si `fail2ban-client -t` affiche `OK` et que le test filtre trouve des matches.**

## 4. Redémarrer (restart, pas reload : on change banaction iptables → nftables)

```fish
ssh -tt $SRV '
  sudo systemctl restart fail2ban
  sleep 2
  sudo systemctl is-active fail2ban
'
```

## 5. Vérifier l'état

```fish
ssh -tt $SRV '
  sudo fail2ban-client status
  for j in sshd nginx-botsearch nginx-badscan recidive; do
    echo "----- $j -----"; sudo fail2ban-client status $j
  done
  echo "===== nftables : table fail2ban créée ? ====="
  sudo nft list tables | grep -i f2b || echo "(pas de table f2b — vérifier banaction)"
'
```

Tu dois voir **4 jails** actifs et une table nftables `f2b-...`.

---

## Rollback (si quelque chose casse)

```fish
ssh -tt $SRV '
  sudo cp -a /etc/fail2ban/jail.local.bak.* /etc/fail2ban/jail.local
  sudo systemctl restart fail2ban
'
```
Si fail2ban refuse de démarrer à cause de `nftables` : édite `/etc/fail2ban/jail.local`, commente les 2 lignes `banaction = nftables...` (fallback iptables), puis `restart`.

## Débannir une IP (dont la tienne)

```fish
ssh -tt $SRV 'sudo fail2ban-client set sshd unbanip TON_IP'
```
Depuis la **console Scaleway** si SSH est coupé : même commande en local sur le serveur.

---

## Recommandations hors fail2ban (fortement conseillées)

1. **Passer SSH en clé uniquement** — `PasswordAuthentication` est actuellement à `yes` (défaut). C'est la vraie faille : les 6000+ tentatives/jour visent des mots de passe.
   ```
   # /etc/ssh/sshd_config.d/99-hardening.conf
   PasswordAuthentication no
   PermitRootLogin prohibit-password
   KbdInteractiveAuthentication no
   ```
   → `sudo systemctl restart ssh` (garde une session ouverte pour tester avant de fermer).
   Une fois fait, le jail sshd devient quasi symbolique : plus aucun mot de passe à brute-forcer.

2. **`named` (bind9) écoute sur `163.172.71.169:53`** — UFW bloque le 53 entrant, donc pas exposé, mais vérifie que c'est intentionnel (DNS autoritaire ?). Si inutile, désactive-le pour réduire la surface.

3. **`limit_req` Nginx** — pour activer le jail `nginx-limit-req` (anti-flood applicatif), ajoute une zone dans `nginx.conf` :
   ```nginx
   limit_req_zone $binary_remote_addr zone=app:10m rate=10r/s;
   ```
   puis `limit_req zone=app burst=20 nodelay;` dans `location /`, et passe le jail à `enabled = true`.
