Infrastructure VPS durcie — SSH Ed25519, UFW, Tailscale, Fail2ban
SSH Ed25519, UFW, Tailscale, Fail2ban — durcissement complet d'un VPS Linux pour l'IA personnelle.
Temps estimé : 30 min
Résultat final : VPS Ubuntu 22.04 avec SSH key-only via Tailscale, UFW restrictif, Fail2ban, et mises à jour automatiques de sécurité.
Prérequis : TUTO-01a (Oracle) ou TUTO-01b (Hetzner) — VPS accessible en SSH.
Objectif
Transformer un VPS fraîchement provisionné en un serveur durci :
- Supprimer les vecteurs d’attaque SSH les plus courants
- Passer de l’accès par IP publique à l’accès exclusivement via Tailscale
- Activer la défense en profondeur (Fail2ban + unattended-upgrades)
Différence Oracle / Hetzner :
- Oracle : user par défaut =
ubuntu(sudoer, pas root) → sauter l’étape 1- Hetzner : user par défaut =
root→ ne pas sauter l’étape 1
Étape 1 : Créer un user non-root [Hetzner uniquement]
Oracle : passer directement à l’étape 2.
Sur le VPS Hetzner (connecté en root) :
# Créer le user avec un nom de ton choix (ex: openclaw)
adduser openclaw
Le terminal demande un mot de passe — choisis-en un fort. Ce mot de passe sera désactivé à l’étape 2, mais il faut qu’il existe maintenant.
# Donner les droits sudo
usermod -aG sudo openclaw
# Copier les clés SSH autorisées de root vers le nouveau user
mkdir -p /home/openclaw/.ssh
cp ~/.ssh/authorized_keys /home/openclaw/.ssh/
chown -R openclaw:openclaw /home/openclaw/.ssh
chmod 700 /home/openclaw/.ssh
chmod 600 /home/openclaw/.ssh/authorized_keys
Ouvre un nouveau terminal (sans fermer la session root) et teste :
# En local — test dans un nouveau terminal
ssh -i ~/.ssh/openclaw_hetzner openclaw@IP_PUBLIQUE_HETZNER
ne jamais fermer la session root avant d’avoir confirmé que le nouveau user peut se connecter ET utiliser sudo. Une erreur ici = VPS inaccessible.
# Vérifier sudo fonctionne
sudo whoami
# Doit afficher : root
Checklist :
- User non-root créé et sudoer
- Connexion SSH user non-root confirmée dans nouveau terminal
-
sudo whoami→ root
Étape 2 : Hardening SSH
Connecté en tant que user non-root (ubuntu pour Oracle, openclaw ou équivalent pour Hetzner) :
# Sauvegarder la config SSH d'origine avant modification
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
# Éditer la config SSH
sudo nano /etc/ssh/sshd_config
Modifier ou ajouter ces lignes (chercher avec Ctrl+W dans nano) :
# Désactiver l'authentification par mot de passe
PasswordAuthentication no
# Activer l'authentification par clé publique
PubkeyAuthentication yes
# Interdire la connexion root directe
PermitRootLogin no
# Limiter aux users autorisés (adapter le nom)
# Oracle :
AllowUsers ubuntu
# Hetzner : remplacer ubuntu par ton user
# AllowUsers openclaw
# Désactiver l'authentification par agent Kerberos/GSSAPI (non utilisé)
GSSAPIAuthentication no
UseDNS no
# Timeout session inactive (optionnel mais recommandé)
ClientAliveInterval 300
ClientAliveCountMax 2
Vérifier la config avant de redémarrer :
sudo sshd -t
# Aucune sortie = config valide
# Si erreur : corriger avant de continuer
Redémarrer SSH :
sudo systemctl restart sshd
après le redémarrage, NE PAS fermer la session active. Ouvre un nouveau terminal et teste la connexion SSH immédiatement. Si ça échoue, la session active te permet encore de corriger.
Test dans un nouveau terminal :
ssh -i ~/.ssh/openclaw_oracle ubuntu@IP_PUBLIQUE # Oracle
ssh -i ~/.ssh/openclaw_hetzner openclaw@IP_PUBLIQUE # Hetzner
Checklist :
- sshd_config.bak créé
- PasswordAuthentication = no
- PermitRootLogin = no
- AllowUsers configuré
-
sudo sshd -tsans erreur - Connexion SSH confirmée depuis nouveau terminal
Étape 3 : Configurer UFW
UFW est le firewall au niveau OS. Il s’ajoute au firewall réseau d’Oracle (Security Lists) ou vient en remplacement du Cloud Firewall Hetzner (non configuré).
# Vérifier l'état initial
sudo ufw status
# Devrait afficher : inactive
# Règle de base : tout bloquer en entrée
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Autoriser SSH (nécessaire avant activation — sinon tu te coupes toi-même)
sudo ufw allow 22/tcp
# Autoriser Tailscale UDP (handshake initial)
sudo ufw allow 41641/udp
# Activer UFW
sudo ufw enable
ne jamais faire ufw enable sans avoir ajouté le port 22
au préalable. Si tu t’es bloqué :
Oracle → console OCI “Cloud Shell” pour accès hors SSH
Hetzner → console Hetzner “Console” (accès VNC web)
# Vérifier l'état après activation
sudo ufw status verbose
Sortie attendue :
Status: active
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
41641/udp ALLOW IN Anywhere
Checklist :
- UFW actif
- Port 22/tcp autorisé
- Port 41641/udp autorisé
- Aucun autre port ouvert en entrée
Étape 4 : Installer Tailscale
# Installation Tailscale
curl -fsSL https://tailscale.com/install.sh | sh
# Démarrer Tailscale et s'authentifier
sudo tailscale up
Le terminal affiche une URL de login :
https://login.tailscale.com/a/XXXXX
Ouvre cette URL depuis ton navigateur, connecte-toi à ton compte Tailscale, autorise le device.
Tailscale chiffre le trafic de bout en bout (WireGuard). Les serveurs de coordination Tailscale (login) ne voient jamais le contenu du trafic — uniquement les métadonnées de connexion. Pour souveraineté maximale : Headscale (self-hosted) est l’alternative, documentée dans un tuto avancé futur.
# Récupérer l'IP Tailscale du VPS
tailscale ip -4
# Affiche quelque chose comme : 100.x.x.x
# Vérifier que le VPS est actif sur ton réseau Tailscale
tailscale status
Depuis ton poste local (avec Tailscale installé et connecté) :
# Test de connectivité via Tailscale
ssh -i ~/.ssh/openclaw_oracle ubuntu@100.x.x.x # Oracle
ssh -i ~/.ssh/openclaw_hetzner openclaw@100.x.x.x # Hetzner
si Tailscale n’est pas installé sur ton poste local, installe-le avant : https://tailscale.com/download Ne continue pas tant que la connexion SSH via IP Tailscale ne fonctionne pas.
Checklist :
- Tailscale installé et authentifié
- IP Tailscale récupérée (100.x.x.x)
- Connexion SSH via IP Tailscale OK depuis poste local
Étape 5 : Restreindre SSH à Tailscale uniquement
C’est l’étape clé : après celle-ci, le port 22 public est fermé. L’accès SSH ne passe plus que par le tunnel Tailscale.
# Trouver le nom de l'interface Tailscale
ip addr show | grep tailscale
# Typiquement : tailscale0
sudo nano /etc/ssh/sshd_config
Modifier la ligne ListenAddress :
# Écouter UNIQUEMENT sur l'interface Tailscale
ListenAddress 100.x.x.x
# Remplacer 100.x.x.x par l'IP Tailscale de ton VPS
Vérifier et redémarrer :
sudo sshd -t && sudo systemctl restart sshd
Fermer le port 22 dans UFW :
sudo ufw delete allow 22/tcp
sudo ufw status verbose
avant de fermer le port 22, confirme OBLIGATOIREMENT que la connexion SSH via IP Tailscale fonctionne depuis un terminal séparé. Si tu perds l’accès : Oracle → OCI Cloud Shell | Hetzner → Console web VNC.
Pour Oracle — fermer aussi dans Security Lists :
Console OCI → Networking → VCN → Security Lists → Default Security List
Supprimer la règle ingress port 22/tcp
Checklist :
- ListenAddress = IP Tailscale dans sshd_config
- SSH redémarré sans erreur
- Port 22/tcp supprimé dans UFW
- Oracle uniquement : port 22/tcp supprimé dans Security Lists
- Connexion SSH via IP Tailscale toujours fonctionnelle
Étape 6 : Installer Fail2ban
Fail2ban protège contre les tentatives de brute-force. Même avec SSH sur Tailscale uniquement, c’est une bonne pratique de défense en profondeur.
sudo apt-get update -q
sudo apt-get install -y fail2ban
Créer une config locale (ne jamais modifier /etc/fail2ban/jail.conf directement) :
sudo nano /etc/fail2ban/jail.local
Contenu :
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
backend = systemd
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# Vérifier que fail2ban surveille SSH
sudo fail2ban-client status sshd
Sortie attendue :
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
`- Actions
|- Currently banned: 0
`- Total banned: 0
si tu vois “Currently banned” avec ta propre IP,
tu t’es banni toi-même (trop de tentatives échouées).
sudo fail2ban-client set sshd unbanip TON_IP
Checklist :
- Fail2ban installé et actif
- jail.local configuré (bantime 1h, maxretry 5)
-
fail2ban-client status sshd→ 0 banned, jail actif
Étape 7 : Mises à jour de sécurité automatiques
sudo apt-get install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
# Répondre "Yes" → active les mises à jour de sécurité automatiques
Vérifier la configuration :
cat /etc/apt/apt.conf.d/20auto-upgrades
Sortie attendue :
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
les mises à jour de sécurité automatiques corrigent les CVE critiques sans intervention manuelle. Sans elles, ton VPS accumule des failles connues publiquement. Activer, ne jamais désactiver.
Checklist :
- unattended-upgrades installé et activé
- Vérification : Update-Package-Lists et Unattended-Upgrade = “1”
Étape 8 : Mettre à jour ~/.openclaw-infra.env
# En local sur ton poste — compléter le fichier créé en TUTO-01
nano ~/.openclaw-infra.env
Ajouter :
# IP Tailscale du VPS (remplace l'IP publique pour la suite des tutos)
VPS_IP_TAILSCALE=100.x.x.x
# User SSH final (après hardening)
# Oracle : ubuntu | Hetzner : openclaw (ou ton user)
VPS_SSH_USER=ubuntu
À partir de maintenant, tous les accès SSH se font via l’IP Tailscale :
ssh -i $VPS_SSH_KEY $VPS_SSH_USER@$VPS_IP_TAILSCALE
Dépannage
SSH refusé après ListenAddress Tailscale
- Cause : Tailscale coupé ou IP Tailscale changée après reboot
- Solution :
# Via console web (OCI Cloud Shell ou Hetzner VNC) sudo tailscale up tailscale ip -4 # Vérifier que l'IP n'a pas changé - Prévention : IP Tailscale fixe via Tailscale admin console → Device → “Disable key expiry”
UFW bloqué après activation
- Cause : Port 22 pas ajouté avant
ufw enable - Solution Oracle : Console OCI → Compute → Instance → “Cloud Shell”
- Solution Hetzner : Console Hetzner → Server → “Console” (VNC web)
- Dans les deux cas :
sudo ufw allow 22/tcp && sudo ufw reload
Fail2ban ne démarre pas
sudo journalctl -u fail2ban -n 50
# Chercher l'erreur dans les logs
Erreur fréquente : backend = systemd non supporté → remplacer par backend = auto
Tailscale “Authentication expired”
sudo tailscale up --authkey=NEW_AUTH_KEY
# Ou simplement :
sudo tailscale up
# Suivre le lien d'authentification affiché
Checklist finale TUTO-02
User et accès
- ☐ User non-root sudoer créé et opérationnel [Hetzner]
- ☐ Connexion root directe impossible (
PermitRootLogin no) - ☐ Auth par mot de passe SSH désactivée (
PasswordAuthentication no)
Réseau
- ☐ UFW actif, tout bloqué par défaut
- ☐ Port 22 public fermé (UFW + Security Lists Oracle)
- ☐ Accès SSH exclusivement via IP Tailscale (100.x.x.x)
Protection active
- ☐ Fail2ban actif sur sshd
- ☐ unattended-upgrades actif
Validation finale
- ☐
ssh -i $VPS_SSH_KEY $VPS_SSH_USER@$VPS_IP_TAILSCALE→ OK - ☐
ssh ubuntu@IP_PUBLIQUE→ Connection refused (attendu) - ☐
sudo ufw status→ port 22 absent - ☐
sudo fail2ban-client status sshd→ jail actif
Références
- SSH Hardening Guide : https://stribika.github.io/2015/01/04/secure-secure-shell.html
- Tailscale Ubuntu 22.04 : https://tailscale.com/kb/1027/install-ubuntu-2204
- UFW Ubuntu Docs : https://help.ubuntu.com/community/UFW
- Fail2ban docs : https://www.fail2ban.org/wiki/index.php/MANUAL_0_8
Tuto suivant : TUTO-02b