# Audit serveur — fail2ban / Nginx / UFW / Docker

Stack : **Ubuntu + Nginx (hôte) → Next.js (Docker, non exposé)**, pare-feu **UFW**, **pas de CDN** devant Nginx.

Objectif : rapatrier localement les fichiers de conf + coller la sortie des commandes d'état pour avoir une vue d'ensemble avant de durcir `jail.local`.

---

## 0. Variables (adapte si besoin)

```bash
# Sur ta machine (macOS)
SRV=monserver@3.172.71.169
DST="/Users/humperdoo/Documents/seo insight/serveur/fail2ban"
```

> Astuce : garde le `"..."` autour du chemin local à cause de l'espace dans « seo insight ».

---

## 1. Rapatrier les fichiers de conf en local (scp)

À lancer **depuis ton Mac**. Crée un sous-dossier `snapshot/` pour ne pas écraser tes fichiers de travail.

```bash
mkdir -p "$DST/snapshot"

# --- fail2ban ---
scp $SRV:/etc/fail2ban/jail.local        "$DST/snapshot/"
scp $SRV:/etc/fail2ban/jail.conf         "$DST/snapshot/"       # défauts de référence (lecture seule)
scp -r $SRV:/etc/fail2ban/jail.d         "$DST/snapshot/jail.d" 2>/dev/null
scp -r $SRV:/etc/fail2ban/filter.d       "$DST/snapshot/filter.d"
scp -r $SRV:/etc/fail2ban/action.d       "$DST/snapshot/action.d"

# --- Nginx ---
scp $SRV:/etc/nginx/nginx.conf           "$DST/snapshot/"
scp -r $SRV:/etc/nginx/sites-enabled     "$DST/snapshot/nginx-sites-enabled"
scp -r $SRV:/etc/nginx/conf.d            "$DST/snapshot/nginx-conf.d" 2>/dev/null
```

> Certains fichiers sous `/etc` sont en `root:root 600`. Si un `scp` échoue avec *Permission denied*, copie-les d'abord en zone lisible côté serveur puis rapatrie :
> ```bash
> ssh $SRV 'sudo tar czf /tmp/etc-snapshot.tgz \
>   /etc/fail2ban/jail.local /etc/fail2ban/jail.d /etc/fail2ban/filter.d \
>   /etc/nginx/nginx.conf /etc/nginx/sites-enabled /etc/nginx/conf.d 2>/dev/null; \
>   sudo chown $USER /tmp/etc-snapshot.tgz'
> scp $SRV:/tmp/etc-snapshot.tgz "$DST/snapshot/"
> ssh $SRV 'rm /tmp/etc-snapshot.tgz'
> tar xzf "$DST/snapshot/etc-snapshot.tgz" -C "$DST/snapshot"
> ```

---

## 1bis. Script tout-en-un (recommandé) — `audit.sh`

Le plus simple : le script `audit.sh` fait **tout** (état système -> `outputs.txt` **+** rapatriement des confs via `tar`, robuste aux permissions root).

```fish
cd "/Users/humperdoo/Documents/seo insight/serveur/fail2ban"
./audit.sh                          # hôte par défaut (monserver@3.172.71.169)
./audit.sh autreuser@1.2.3.4        # ou override l'hôte
```

Résultat :
- `snapshot/outputs.txt` — sortie de toutes les commandes d'état
- `snapshot/etc/...` — copies de `jail.local`, confs Nginx, filtres, etc.

Le script est en **bash** (via son shebang), pas besoin qu'il soit lancé depuis fish — `./audit.sh` suffit.

---

## 1ter. Variante one-liner (si tu préfères sans script)

Exécute uniquement les blocs d'état et écrit dans `snapshot/outputs.txt` (affiché en direct + sauvegardé). **Shell fish** (le tien). Hôte codé en dur — édite-le si besoin.

```fish
mkdir -p "/Users/humperdoo/Documents/seo insight/serveur/fail2ban/snapshot"; and ssh monserver@3.172.71.169 '
  echo "########## OS ##########"; lsb_release -a 2>/dev/null; uname -r
  echo "########## SSH CONFIG ##########"; sudo grep -E "^#?Port|^#?PermitRootLogin|^#?PasswordAuthentication" /etc/ssh/sshd_config
  echo "########## AUTH.LOG vs JOURNALD ##########"; ls -l /var/log/auth.log 2>/dev/null || echo "pas de auth.log -> SSH dans journald (backend=systemd)"
  echo "########## UFW ##########"; sudo ufw status verbose; sudo ufw status numbered
  echo "########## FAIL2BAN VERSION ##########"; fail2ban-client version
  echo "########## FAIL2BAN TEST CONF ##########"; sudo fail2ban-client -t
  echo "########## FAIL2BAN JAILS ##########"; sudo fail2ban-client status
  for j in sshd nginx-botsearch nginx-http-auth nginx-limit-req recidive; do echo "----- jail: $j -----"; sudo fail2ban-client status $j 2>/dev/null || echo "(absent)"; done
  echo "########## FAIL2BAN CONF EFFECTIVE ##########"; sudo fail2ban-client -d 2>/dev/null | grep -E "add|set" | head -n 120
  echo "########## NGINX TEST ##########"; sudo nginx -t
  echo "########## NGINX LOGS ##########"; ls -lh /var/log/nginx/access.log /var/log/nginx/error.log
  echo "########## NGINX real_ip / limit_req ##########"; sudo grep -R "log_format\|access_log\|limit_req\|real_ip" /etc/nginx/ 2>/dev/null
  echo "########## DOCKER PS ##########"; sudo docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}"
  echo "########## LISTEN HÔTE (ss) ##########"; sudo ss -tlnp
  echo "########## TOP IP access.log ##########"; sudo awk "{print \$1}" /var/log/nginx/access.log 2>/dev/null | sort | uniq -c | sort -rn | head
  echo "########## TOP 404 paths ##########"; sudo grep " 404 " /var/log/nginx/access.log 2>/dev/null | awk "{print \$7}" | sort | uniq -c | sort -rn | head
  echo "########## Échecs SSH récents ##########"; sudo journalctl -u ssh --no-pager 2>/dev/null | grep -i "failed\|invalid" | tail
' 2>&1 | tee "/Users/humperdoo/Documents/seo insight/serveur/fail2ban/snapshot/outputs.txt"
```

> Si `sudo` demande un mot de passe, ajoute `-t` après `ssh` : `ssh -t monserver@...`. Sinon les commandes `sudo` échoueront silencieusement dans un pipe non-interactif.

---

## 2. Système & OS (colle la sortie)

```bash
ssh $SRV '
  echo "===== OS ====="            ; lsb_release -a 2>/dev/null; uname -r
  echo "===== UPTIME ====="        ; uptime
  echo "===== SSH PORT ====="      ; sudo grep -E "^#?Port|^#?PermitRootLogin|^#?PasswordAuthentication" /etc/ssh/sshd_config
  echo "===== JOURNALD vs auth.log =====" ; ls -l /var/log/auth.log 2>/dev/null || echo "pas de auth.log → SSH loggue dans journald (backend=systemd)"
'
```

---

## 3. UFW — pare-feu (colle la sortie)

```bash
ssh $SRV '
  echo "===== UFW STATUS ====="    ; sudo ufw status verbose
  echo "===== UFW NUMBERED =====" ; sudo ufw status numbered
'
```

Ce qu'on veut vérifier :
- 22 (ou ton port SSH), 80, 443 ouverts ; le reste fermé.
- **Aucun port du conteneur (ex. 3000) ouvert** → confirme que Next.js n'est pas exposé.

> Note UFW + fail2ban : fail2ban insère ses règles de ban **avant** celles d'UFW dans la chaîne `INPUT` (action par défaut `iptables-multiport`) → les bans s'appliquent bien, pas de conflit. On garde l'action par défaut (pas besoin de `action = ufw`).

---

## 4. fail2ban — état & conf (colle la sortie)

```bash
ssh $SRV '
  echo "===== VERSION ====="       ; fail2ban-client version
  echo "===== TEST CONF ====="     ; sudo fail2ban-client -t
  echo "===== JAILS ACTIFS =====" ; sudo fail2ban-client status
'
```

Puis le détail par jail (répète pour chacun listé ci-dessus) :

```bash
ssh $SRV '
  for j in sshd nginx-botsearch recidive; do
    echo "===== $j ====="
    sudo fail2ban-client status $j 2>/dev/null
  done
'
```

Config effective fusionnée (précieux : montre ce que fail2ban lit vraiment, defaults inclus) :

```bash
ssh $SRV 'sudo fail2ban-client -d 2>/dev/null | grep -E "add|set" | head -n 120'
```

---

## 5. Nginx — validité & logs (colle la sortie)

```bash
ssh $SRV '
  echo "===== NGINX -T (test) =====" ; sudo nginx -t
  echo "===== LOGS EXISTENT ? =====" ; ls -lh /var/log/nginx/access.log /var/log/nginx/error.log
  echo "===== FORMAT DE LOG =====" ; sudo grep -R "log_format\|access_log\|limit_req" /etc/nginx/ 2>/dev/null
'
```

On veut confirmer :
- `access.log` et `error.log` existent **et grossissent** (sinon les jails nginx-* ne protègent rien).
- La vraie IP client apparaît bien dans les logs (pas de proxy intermédiaire qui masque — normalement OK puisque pas de CDN).
- Présence ou non de `limit_req` (conditionne l'activation du jail `nginx-limit-req`).

---

## 6. Docker — confirmer que rien n'est exposé (colle la sortie)

```bash
ssh $SRV '
  echo "===== CONTAINERS ====="   ; sudo docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}"
  echo "===== PORTS PUBLIÉS =====" ; sudo docker ps --format "{{.Names}}: {{.Ports}}"
  echo "===== LISTEN HÔTE =====" ; sudo ss -tlnp
'
```

Ce qu'on veut voir :
- Le conteneur Next.js **sans** mapping `0.0.0.0:xxxx->` (idéalement pas de `-p` du tout, ou `127.0.0.1:3000->3000` au pire → seul l'hôte y accède).
- `ss -tlnp` : seuls `sshd`, `nginx` (80/443) écoutent sur `0.0.0.0`/`::`. Si un port Docker écoute sur `0.0.0.0`, **il contourne UFW ET fail2ban** → à corriger.

---

## 7. Aperçu des menaces en cours (optionnel, colle la sortie)

Pour calibrer l'agressivité, un coup d'œil aux attaques réelles :

```bash
ssh $SRV '
  echo "===== TOP IP access.log =====" ; sudo awk "{print \$1}" /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
  echo "===== TOP 404/paths scannés =====" ; sudo grep " 404 " /var/log/nginx/access.log | awk "{print \$7}" | sort | uniq -c | sort -rn | head
  echo "===== Échecs SSH récents =====" ; sudo journalctl -u ssh --no-pager | grep -i "failed\|invalid" | tail
'
```

---

## 8. Après rapatriement

Une fois `snapshot/` rempli et les sorties collées ici (ou dans un fichier `outputs.txt`), je peux :
1. relire la conf réelle vs la version durcie,
2. vérifier la cohérence des `logpath` / backend,
3. ajouter un filtre custom anti-scan 404 (`.env`, `.git`, `wp-*`) si le §7 le justifie.
