# Guide pas-à-pas — Administration serveur Xrencontre

Public visé : administrateur système qui déploie et maintient Xrencontre sur un VPS dédié (Ubuntu 22.04 LTS ou plus récent). Chaque étape est numérotée et indépendante : vous pouvez vous arrêter à la fin de chacune.

Notation utilisée : `# commande` = à exécuter en root (ou via `sudo`), `$ commande` = en tant qu'utilisateur normal.

---

## Étape 0 — Pré-requis

Avant de commencer, vous devez avoir :

- Un **VPS Ubuntu 22.04 LTS** avec 2 vCPU minimum, 2 Go RAM, 20 Go disque, IP publique fixe.
- Un **nom de domaine** pointant vers cette IP (enregistrement A et AAAA).
- Une **clé SSH publique ed25519** (côté poste admin : `ssh-keygen -t ed25519`).
- Un compte **SMTP** (Mailgun, Postmark, SendGrid, OVH, etc.) pour les emails de vérification.
- Optionnel : un compte **hCaptcha** (gratuit) et **Twilio Verify** pour la vérification téléphone.

---

## Étape 1 — Provisionner et sécuriser le compte root

Connectez-vous une première fois en root avec le mot de passe fourni par votre hébergeur :

```bash
ssh root@VOTRE_IP
```

Mettez à jour le système :

```bash
# apt update && apt full-upgrade -y
# reboot
```

Reconnectez-vous, puis créez l'utilisateur applicatif et l'utilisateur administrateur :

```bash
# adduser admin                          # mot de passe fort, à conserver
# usermod -aG sudo admin
# useradd -m -s /bin/bash xrencontre     # compte applicatif, sans sudo
```

Copiez votre clé SSH publique sur le compte `admin` :

```bash
# mkdir -p /home/admin/.ssh
# nano /home/admin/.ssh/authorized_keys  # coller la clé publique
# chown -R admin:admin /home/admin/.ssh
# chmod 700 /home/admin/.ssh && chmod 600 /home/admin/.ssh/authorized_keys
```

Testez la connexion **depuis un autre terminal** (sans fermer la session root) :

```bash
$ ssh admin@VOTRE_IP
$ sudo -i      # doit demander le mot de passe d'admin
```

Si ça fonctionne, on continue. Sinon, ne fermez surtout pas la session root.

---

## Étape 2 — Durcir SSH

Éditez `/etc/ssh/sshd_config` :

```bash
# nano /etc/ssh/sshd_config
```

Mettez ces valeurs :

```
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitEmptyPasswords no
AllowUsers admin
MaxAuthTries 3
LoginGraceTime 20
```

Rechargez SSH **dans une session de secours** :

```bash
# systemctl restart ssh
```

Confirmez que vous pouvez toujours vous connecter en tant que `admin` avant de fermer la session root.

---

## Étape 3 — Pare-feu UFW

```bash
# ufw default deny incoming
# ufw default allow outgoing
# ufw allow OpenSSH
# ufw allow 80/tcp
# ufw allow 443/tcp
# ufw --force enable
# ufw status verbose
```

Vérification : seuls 22, 80, 443 doivent apparaître en autorisés.

---

## Étape 4 — Installer fail2ban

```bash
# apt install -y fail2ban
# systemctl enable --now fail2ban
# fail2ban-client status
```

Plus tard (étape 11) vous ajouterez les jails spécifiques à Nginx.

---

## Étape 5 — Mises à jour automatiques de sécurité

```bash
# apt install -y unattended-upgrades
# dpkg-reconfigure -plow unattended-upgrades       # répondre "Yes"
# nano /etc/apt/apt.conf.d/50unattended-upgrades   # vérifier "security" activé
```

---

## Étape 6 — Installer Node.js 20 LTS

```bash
# curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
# apt install -y nodejs
# node -v && npm -v   # doit afficher v20.x et npm 10.x
```

---

## Étape 7 — Installer MongoDB 7 (NoSQL, en local uniquement)

```bash
# curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor
# echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" > /etc/apt/sources.list.d/mongodb-org-7.0.list
# apt update && apt install -y mongodb-org
# systemctl enable --now mongod
```

**Important — verrouiller MongoDB :**

```bash
# nano /etc/mongod.conf
```

Vérifiez ces lignes :

```yaml
net:
  port: 27017
  bindIp: 127.0.0.1     # JAMAIS 0.0.0.0
security:
  authorization: enabled
```

Avant d'activer `authorization`, créez les utilisateurs MongoDB :

```bash
$ mongosh
> use admin
> db.createUser({ user: "root", pwd: "MOT_DE_PASSE_FORT_ROOT", roles: ["root"] })
> use xrencontre
> db.createUser({ user: "app_user", pwd: "MOT_DE_PASSE_APP", roles: [{ role: "readWrite", db: "xrencontre" }] })
> db.createUser({ user: "backup_user", pwd: "MOT_DE_PASSE_BACKUP", roles: [{ role: "read", db: "xrencontre" }] })
> exit
```

Activez l'authentification puis redémarrez :

```bash
# systemctl restart mongod
$ mongosh -u app_user -p --authenticationDatabase xrencontre   # doit fonctionner
```

---

## Étape 8 — Installer Nginx + certbot

```bash
# apt install -y nginx certbot python3-certbot-nginx
# systemctl enable --now nginx
```

Testez que le port 80 répond : ouvrez `http://votre-domaine.tld` dans un navigateur, vous devez voir la page par défaut Nginx.

---

## Étape 9 — Déployer le code Xrencontre

Préparez les dossiers :

```bash
# mkdir -p /opt/xrencontre /etc/xrencontre /var/log/xrencontre
# chown -R xrencontre:xrencontre /opt/xrencontre /var/log/xrencontre
# chmod 700 /etc/xrencontre
```

Copiez le code (au choix : `scp`, `rsync`, ou `git clone`).

```bash
$ sudo -u xrencontre -i
$ cd /opt/xrencontre
$ git clone https://votre-depot.git .         # ou scp depuis votre poste
$ npm ci --omit=dev
$ exit
```

---

## Étape 10 — Configurer les variables d'environnement

Générez les secrets :

```bash
$ node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"   # JWT_SECRET
$ node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"   # JWT_REFRESH_SECRET
$ node -e "console.log(require('crypto').randomBytes(32).toString('base64'))" # AES_KEY
```

Créez `/etc/xrencontre/.env` :

```bash
# cp /opt/xrencontre/.env.example /etc/xrencontre/.env
# nano /etc/xrencontre/.env
```

Remplissez **toutes** les valeurs (MONGO_URI avec `app_user`, JWT_SECRET, JWT_REFRESH_SECRET, AES_KEY, SMTP, hCaptcha, Twilio, CORS_ORIGIN, COOKIE_DOMAIN).

Verrouillez le fichier :

```bash
# chown xrencontre:xrencontre /etc/xrencontre/.env
# chmod 600 /etc/xrencontre/.env
```

---

## Étape 11 — Installer le service systemd

```bash
# cp /opt/xrencontre/deploy/xrencontre.service /etc/systemd/system/
# systemctl daemon-reload
# systemctl enable --now xrencontre
# systemctl status xrencontre        # doit afficher "active (running)"
# journalctl -u xrencontre -n 50 -f  # tail des logs
```

Si ça plante, lisez les logs — c'est presque toujours une variable d'environnement manquante.

Test local :

```bash
$ curl http://127.0.0.1:3000/api/v1/health
{"ok":true,"ts":1736...}
```

---

## Étape 12 — Configurer Nginx + TLS

```bash
# cp /opt/xrencontre/deploy/nginx.conf /etc/nginx/sites-available/xrencontre
# nano /etc/nginx/sites-available/xrencontre   # remplacer xrencontre.example.com par votre domaine
# ln -s /etc/nginx/sites-available/xrencontre /etc/nginx/sites-enabled/
# rm /etc/nginx/sites-enabled/default
# nginx -t        # vérification syntaxe
# systemctl reload nginx
```

Obtenez le certificat Let's Encrypt :

```bash
# certbot --nginx -d votre-domaine.tld --email admin@votre-domaine.tld --agree-tos --no-eff-email
```

Certbot ajoute automatiquement les blocs HTTPS et renouvelle tous les 60 jours via timer systemd. Vérifiez :

```bash
# systemctl status certbot.timer
```

Test public : `https://votre-domaine.tld` doit afficher l'accueil Xrencontre avec cadenas vert.

---

## Étape 13 — Activer les jails fail2ban pour Nginx

```bash
# cp /opt/xrencontre/deploy/fail2ban-xrencontre.conf /etc/fail2ban/jail.d/xrencontre.conf
# systemctl restart fail2ban
# fail2ban-client status
# fail2ban-client status nginx-limit-req
```

---

## Étape 14 — Créer le compte administrateur applicatif

Ce compte vous permettra d'accéder aux routes `/api/v1/admin/*`.

```bash
# sudo -u xrencontre bash -c 'cd /opt/xrencontre && \
    ADMIN_EMAIL=admin@votre-domaine.tld \
    ADMIN_PASSWORD="MotDePasseFortAdmin!2026" \
    node backend/scripts/seed-admin.js'
```

Connectez-vous via le frontend ou en API :

```bash
$ curl -X POST https://votre-domaine.tld/api/v1/auth/login \
    -H 'Content-Type: application/json' \
    -d '{"email":"admin@votre-domaine.tld","motDePasse":"MotDePasseFortAdmin!2026"}'
```

Vous obtenez un `accessToken` à utiliser dans `Authorization: Bearer …`.

---

## Étape 15 — Mettre en place les sauvegardes

Créez un script `/usr/local/bin/backup-xrencontre.sh` :

```bash
#!/usr/bin/env bash
set -euo pipefail
DATE=$(date +%F-%H%M)
DEST=/var/backups/xrencontre
mkdir -p "$DEST"
mongodump --uri="mongodb://backup_user:MDP_BACKUP@127.0.0.1:27017/xrencontre?authSource=xrencontre" \
          --gzip --archive="$DEST/dump-$DATE.gz"
# Chiffrer (GPG, destinataire = votre clé publique admin)
gpg --batch --yes --encrypt -r admin@votre-domaine.tld "$DEST/dump-$DATE.gz"
rm "$DEST/dump-$DATE.gz"
# Rétention : 14 jours
find "$DEST" -name 'dump-*.gz.gpg' -mtime +14 -delete
# Optionnel : rsync vers stockage hors site
# rsync -az "$DEST/" backup@hors-site.tld:/backups/xrencontre/
```

```bash
# chmod 700 /usr/local/bin/backup-xrencontre.sh
# crontab -e
```

Ajoutez :

```
0 3 * * * /usr/local/bin/backup-xrencontre.sh >> /var/log/xrencontre/backup.log 2>&1
```

Testez immédiatement : `# /usr/local/bin/backup-xrencontre.sh`.

---

## Étape 16 — Mettre en place le VPN admin (recommandé)

Le panneau d'administration ne doit jamais être joignable depuis l'internet public. Installez WireGuard :

```bash
# apt install -y wireguard
# wg genkey | tee /etc/wireguard/privkey | wg pubkey > /etc/wireguard/pubkey
# chmod 600 /etc/wireguard/privkey
# nano /etc/wireguard/wg0.conf
```

Exemple de config (à adapter) :

```
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contenu de /etc/wireguard/privkey>

[Peer]
PublicKey = <clé publique de votre poste admin>
AllowedIPs = 10.8.0.2/32
```

```bash
# ufw allow 51820/udp
# systemctl enable --now wg-quick@wg0
```

Puis restreignez `/api/v1/admin/` dans `nginx.conf` :

```nginx
location /api/v1/admin/ {
    allow 10.8.0.0/24;
    deny all;
    proxy_pass http://127.0.0.1:3000;
    include /etc/nginx/proxy_params;
}
```

Rechargez Nginx.

---

## Étape 17 — Audit régulier (checklist mensuelle)

Tous les mois, sur le serveur :

```bash
# apt update && apt list --upgradable          # voir patches en attente
# unattended-upgrade --dry-run -v               # vérifier que ça tourne
# fail2ban-client banned                        # IP actuellement bannies
# journalctl -u xrencontre --since "30 days ago" | grep -i "erreur\|error" | tail -50
# du -sh /var/log/xrencontre /var/backups/xrencontre
# ls -lh /var/backups/xrencontre                # dernière sauvegarde < 24 h ?
# systemctl status xrencontre nginx mongod fail2ban wg-quick@wg0
```

Côté application, en tant qu'admin connecté :

```bash
GET /api/v1/admin/audit         # consulter les actions admin récentes
GET /api/v1/reports/admin       # signalements en attente de modération
```

---

## Étape 18 — Procédure de mise à jour applicative

```bash
$ sudo -u xrencontre -i
$ cd /opt/xrencontre
$ git fetch && git checkout TAG_OU_BRANCHE
$ npm ci --omit=dev
$ exit
# systemctl restart xrencontre
# journalctl -u xrencontre -n 50 -f      # vérifier qu'il redémarre proprement
```

En cas de problème, retour en arrière :

```bash
$ cd /opt/xrencontre && git checkout TAG_PRECEDENT && npm ci --omit=dev
# systemctl restart xrencontre
```

---

## Étape 19 — Réponse à incident (résumé)

| Symptôme | Action immédiate |
|----------|------------------|
| 5xx massifs | `journalctl -u xrencontre -n 200` → identifier l'erreur |
| Charge CPU anormale | `top`, `htop`, `iftop` → vérifier processus + trafic |
| Suspicion de compromission | Isoler : `ufw default deny outgoing`, dumper RAM, prévenir l'utilisateur, restaurer depuis sauvegarde |
| Compte admin compromis | Rotation des secrets JWT + AES + révocation tokens (vider `refreshTokenHash` en base) |
| Faille critique annoncée | `apt update && apt upgrade` + redémarrage immédiat des services concernés |

Pour une rotation complète des secrets (en cas de fuite suspectée du `.env`) :

```bash
# nano /etc/xrencontre/.env       # regénérer JWT_SECRET, JWT_REFRESH_SECRET, AES_KEY
# systemctl restart xrencontre
```

Attention : changer `AES_KEY` rend illisibles les messages chiffrés existants. Si la base n'est pas compromise, ne changez pas `AES_KEY`.

---

## Étape 20 — Désactivation propre du service

Pour mettre le site en maintenance temporaire :

```bash
# systemctl stop xrencontre
```

Nginx renverra une 502 — vous pouvez préparer une page statique de maintenance dans `/var/www/maintenance/index.html` et l'activer en commentant le `proxy_pass` dans Nginx.

---

## Annexe — Commandes de diagnostic rapide

| But | Commande |
|-----|----------|
| Voir les logs applicatifs en direct | `journalctl -u xrencontre -f` |
| Voir les logs Nginx | `tail -f /var/log/nginx/access.log /var/log/nginx/error.log` |
| Voir les connexions actives | `ss -tnp` |
| Connexions MongoDB | `mongosh --eval "db.serverStatus().connections"` |
| Tester l'API depuis le serveur | `curl -s http://127.0.0.1:3000/api/v1/health \| jq` |
| Voir les IP bannies | `fail2ban-client banned` |
| Recharger Nginx sans coupure | `nginx -t && systemctl reload nginx` |
| Renouveler manuellement le TLS | `certbot renew --force-renewal` |
| Lister les ports écoutants | `ss -tlnp` |

---

Une fois ces 20 étapes complétées, le serveur est opérationnel, sécurisé et auditable.
