Cybersécurité

Sécuriser son serveur Linux : guide pratique

16 min de lecture

Ce que vous saurez faire à la fin

  1. Durcir SSH et le firewall UFW
  2. Activer Fail2ban et les mises à jour auto
  3. Monitorer avec auditd et AIDE

À l’issue de ce tutoriel, vous saurez configurer un VPS Linux durci selon les bonnes pratiques 2026 : utilisateur non-root avec sudo, SSH par clé sans mot de passe, firewall ufw, fail2ban contre les brute-force, mises à jour automatiques de sécurité, sysctl hardening, audit avec auditd et AIDE pour la détection d’intrusion, et sauvegardes hors-serveur. Cette base sécurisée tient 99 % des attaques opportunistes courantes ciblant les VPS exposés sur Internet. Comptez 1-2 heures pour appliquer l’ensemble sur un VPS vierge.

Étape 1 — Utilisateur non-root

sudo adduser aminata
sudo usermod -aG sudo aminata
ssh-copy-id aminata@serveur

Ne JAMAIS travailler en root. Créez un utilisateur dédié : adduser deploy && usermod -aG sudo deploy. Copiez votre clé SSH : rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy. Testez la connexion avec le nouvel utilisateur dans une seconde session SSH AVANT de désactiver root, sinon vous risquez le lock-out. Cette discipline élémentaire bloque 80 % des scripts d’attaque automatiques qui ciblent root@VOTRE_IP.

Étape 2 — SSH durci

# /etc/ssh/sshd_config
Port 2222
PasswordAuthentication no
PermitRootLogin no
MaxAuthTries 3
AllowUsers aminata deploy
sudo sshd -t && sudo systemctl reload sshd

Modifiez /etc/ssh/sshd_config pour durcir SSH. PermitRootLogin no (interdit la connexion root). PasswordAuthentication no (force la clé SSH, refuse le mot de passe). PubkeyAuthentication yes. AllowUsers deploy (limite aux comptes autorisés). Optionnellement Port 2222 (port non-standard, complique le scan). Redémarrez sshd : systemctl restart sshd. Testez immédiatement la connexion dans une nouvelle session avant de fermer la session courante.

Étape 3 — UFW firewall

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2222/tcp
sudo ufw allow 80,443/tcp
sudo ufw limit 2222/tcp
sudo ufw enable

UFW (Uncomplicated Firewall) simplifie iptables. Configurez : ufw default deny incoming && ufw default allow outgoing && ufw allow 2222/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw enable. Cette configuration bloque tout entrant sauf SSH (sur le port custom), HTTP et HTTPS. Vérifiez avec ufw status verbose. Pour des services additionnels (PostgreSQL en accès distant, Mattermost), ajoutez explicitement chaque port avec ufw allow.

Étape 4 — Fail2ban

sudo apt install -y fail2ban

sudo tee /etc/fail2ban/jail.local <<EOF
[DEFAULT]
bantime = 1h
maxretry = 5

[sshd]
enabled = true
port = 2222
EOF

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

Fail2ban scanne les logs SSH et bloque automatiquement les IP qui font des tentatives répétées. Installez : apt install fail2ban -y. Créez /etc/fail2ban/jail.local avec [sshd] enabled = true; maxretry = 3; bantime = 3600. Démarrez : systemctl enable --now fail2ban. Vérifiez avec fail2ban-client status sshd qui affiche les IPs bannies. Sur un VPS exposé, vous bannissez typiquement 50-200 IPs par jour, surtout des bots chinois et russes.

Étape 5 — Mises à jour auto

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

Activez unattended-upgrades pour les patchs de sécurité automatiques : apt install unattended-upgrades -y && dpkg-reconfigure --priority=low unattended-upgrades. Configurez /etc/apt/apt.conf.d/50unattended-upgrades pour appliquer uniquement les security updates (pas les feature updates qui peuvent casser l’app). Vérifiez avec unattended-upgrades --dry-run. Cette discipline applique automatiquement les correctifs critiques (Heartbleed, Log4Shell) sans intervention manuelle, ce qui est crucial pour les VPS qui hébergent des sites en production.

Étape 6 — sysctl hardening

# /etc/sysctl.d/99-secu.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
kernel.randomize_va_space = 2
kernel.kptr_restrict = 2
sudo sysctl --system

Modifiez /etc/sysctl.d/99-hardening.conf avec des paramètres réseau durcis. net.ipv4.conf.all.rp_filter=1 (anti-spoofing). net.ipv4.tcp_syncookies=1 (anti-SYN-flood). net.ipv4.conf.all.accept_redirects=0 (refuse les redirections ICMP malveillantes). net.ipv4.conf.all.send_redirects=0. Appliquez avec sysctl --system. Ces paramètres ne cassent rien et bloquent plusieurs vecteurs d’attaque réseau.

Étape 7 — auditd

sudo apt install -y auditd
sudo systemctl enable --now auditd

sudo tee /etc/audit/rules.d/itsc.rules <<EOF
-w /etc/passwd -p wa -k passwd
-w /etc/sudoers -p wa -k sudoers
-a always,exit -F arch=b64 -S execve -F euid=0 -k root_exec
EOF

sudo augenrules --load
sudo systemctl restart auditd

Auditd enregistre les appels système sensibles dans un journal séparé du journal système. Installez : apt install auditd -y. Configurez /etc/audit/rules.d/audit.rules avec des règles de surveillance des fichiers critiques (passwd, shadow, sudoers) et des actions admin (su, sudo). Démarrez : systemctl enable --now auditd. Le log /var/log/audit/audit.log devient votre source de vérité pour l’investigation forensique post-incident. Centralisez-le vers un SIEM (Wazuh, ELK) pour la rétention longue durée.

Étape 8 — AIDE

sudo apt install -y aide
sudo aideinit
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db

echo "0 3 * * * root /usr/bin/aide --check | mail -s 'AIDE' admin@example.sn" \
  | sudo tee /etc/cron.d/aide

AIDE (Advanced Intrusion Detection Environment) génère un hash de tous les fichiers système et alerte si quelque chose change. Installez : apt install aide -y && aideinit && mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db. Programmez un check quotidien via cron : 0 5 * * * /usr/bin/aide --check | mail -s 'AIDE report' admin@example.sn. Toute modification non attendue de /etc, /bin, /sbin déclenche une alerte. Détecte les rootkits qui auraient modifié des binaires système.

Étape 9 — Audit hebdo script

sudo tee /usr/local/bin/secu-hebdo.sh <<'SCRIPT'
#!/bin/bash
{
echo "=== Audit $(hostname) $(date) ==="
apt list --upgradable 2>/dev/null | head -20
journalctl -u ssh --since "7 days ago" | grep -c "Failed"
ss -tulpn | grep LISTEN
fail2ban-client status sshd | grep Currently
} | mail -s "[Secu] $(hostname)" admin@example.sn
SCRIPT

sudo chmod +x /usr/local/bin/secu-hebdo.sh
echo "0 6 * * 1 root /usr/local/bin/secu-hebdo.sh" | sudo tee /etc/cron.d/secu

Checklist

✓ SSH clés uniquement, port custom
✓ UFW deny incoming par défaut
✓ Fail2ban actif
✓ Unattended-upgrades
✓ UID 0 = root seul
✓ sysctl hardening
✓ auditd règles critiques
✓ AIDE baseline
✓ Email audit hebdo

Pour appliquer ce tutoriel sur un vrai serveur

Hostinger reste l’option la plus simple pour démarrer. Lien partenaire — votre achat soutient le blog sans surcoût.

Réserver un VPS Hostinger →

Lien d affiliation. Si vous achetez via ce lien, le blog reçoit une petite commission sans surcoût pour vous.

Pourquoi durcir un VPS Linux dès la première heure

Un VPS fraîchement provisionné chez Hetzner, Contabo ou OVH (entre 4 et 10 EUR par mois soit 2624 à 6560 FCFA) est scanné en moins de cinq minutes par les bots du monde entier. SSH sur le port 22 avec mot de passe est attaqué des centaines de fois par jour. Ce tutoriel applique en moins d’une heure les contrôles essentiels qui couvrent 95 % des risques pour une PME tech à Dakar, Abidjan, Lomé ou Cotonou : SSH par clé, pare-feu UFW, fail2ban, mises à jour automatiques, monitoring de base, sauvegardes hors-serveur.

Prérequis : un VPS Debian 12 ou Ubuntu 24.04 LTS avec accès root, une clé SSH générée localement (ssh-keygen -t ed25519), un nom de domaine optionnel pointant vers l’IP.

Étape 1 — Mettre à jour le système immédiatement

Avant toute autre opération, appliquez les correctifs de sécurité. Une image VPS provisionnée la veille peut déjà accumuler plusieurs correctifs critiques.

apt update
apt upgrade -y
apt autoremove -y

La commande apt upgrade peut prendre cinq minutes selon la latence vers les mirrors et l’âge de l’image. Si un noyau est mis à jour, redémarrez avec reboot pour activer la nouvelle version. Vérifiez ensuite avec uname -r que vous tournez bien sur le dernier noyau disponible.

Étape 2 — Créer un utilisateur sudo non-root

Travailler en root permanent est une mauvaise pratique. Créez un utilisateur dédié, ajoutez-le au groupe sudo, et utilisez-le pour toutes les opérations futures.

adduser deploy
usermod -aG sudo deploy
mkdir -p /home/deploy/.ssh
cp /root/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys

Testez la connexion depuis votre poste local : ssh deploy@ip-vps doit fonctionner sans demander de mot de passe. Si la connexion échoue, vérifiez les permissions du dossier .ssh et du fichier authorized_keys avant de désactiver root.

Étape 3 — Désactiver l’accès root SSH et l’authentification par mot de passe

Une fois la connexion deploy validée, fermez la porte d’entrée principale. Éditez /etc/ssh/sshd_config et imposez trois directives.

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

Rechargez le démon avec systemctl reload ssh. Gardez impérativement la session courante ouverte ; ouvrez un nouveau terminal et testez une nouvelle connexion ssh deploy@ip-vps. Si elle réussit, vous pouvez fermer la session root sans risque. En cas d’échec, la session root toujours ouverte vous permet de revenir en arrière.

Étape 4 — Changer le port SSH (option utile)

Déplacer SSH du port 22 vers un port aléatoire haut (par exemple 52822) ne renforce pas réellement la sécurité face à un attaquant déterminé, mais réduit drastiquement le bruit dans les logs et la charge CPU consommée par les bots. Modifiez Port 52822 dans sshd_config, ouvrez le port côté pare-feu (étape suivante), puis rechargez. Documentez ce changement dans le wiki de l’équipe — un nouveau membre qui tente le port 22 sera dérouté.

Étape 5 — Configurer UFW comme pare-feu de base

UFW (Uncomplicated Firewall) est l’interface conviviale d’iptables. Configurez-la en mode deny par défaut.

ufw default deny incoming
ufw default allow outgoing
ufw allow 52822/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

Confirmez avec y à l’invite. Vérifiez ensuite avec ufw status numbered que les règles sont bien actives. Tout port non listé est désormais bloqué côté noyau, ce qui ferme les services écoutant par erreur sur 0.0.0.0.

Étape 6 — Installer fail2ban contre le brute force

fail2ban scanne les logs et bannit automatiquement les IP qui multiplient les échecs d’authentification. Installation et configuration minimale :

apt install -y fail2ban
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Éditez /etc/fail2ban/jail.local pour activer le jail SSH avec un maxretry = 3 et bantime = 1h. Redémarrez avec systemctl restart fail2ban. Vérifiez l’état du jail avec fail2ban-client status sshd ; vous y verrez le nombre d’IP bannies, qui grimpe rapidement les premiers jours.

Étape 7 — Activer les mises à jour de sécurité automatiques

Les correctifs de sécurité sortent quasi quotidiennement. Sur Debian/Ubuntu, le paquet unattended-upgrades applique automatiquement les patchs critiques sans intervention humaine.

apt install -y unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades

Répondez Yes à l’invite. Le fichier /etc/apt/apt.conf.d/50unattended-upgrades liste les sources de mise à jour automatique. Par défaut, seules les mises à jour de sécurité sont appliquées. Activez les notifications par email en décommentant Unattended-Upgrade::Mail "admin@exemple.io";.

Étape 8 — Auditer les services en écoute

Listez les services qui écoutent sur le réseau avec ss -tulpn. Chaque ligne affiche le port, l’IP de bind (0.0.0.0 = exposé partout, 127.0.0.1 = local uniquement), et le processus. Tout service qui n’a pas besoin d’être exposé doit être bindé sur 127.0.0.1, voire désactivé : systemctl disable --now nom-du-service. Cette hygiène réduit drastiquement la surface d’attaque.

Étape 9 — Limiter sudo aux commandes nécessaires

Pour un utilisateur qui n’a pas besoin de root absolu, restreignez sudo via visudo -f /etc/sudoers.d/deploy avec une règle ciblée : deploy ALL=(ALL) NOPASSWD: /bin/systemctl restart nginx, /usr/bin/docker compose. Cette granularité protège contre une compromission partielle du compte applicatif.

Au lieu de donner sudo all-powerful à tous les utilisateurs, limitez aux commandes spécifiques. Éditez /etc/sudoers.d/deploy avec deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/systemctl restart php-fpm. Cette restriction empêche un compte compromis de gagner le contrôle total du serveur. Pour les opérations admin lourdes (apt upgrade, modifications réseau), un compte admin séparé avec validation manuelle est plus prudent.

Étape 10 — Sauvegardes hors-serveur

Une compromission ou un crash disque sans sauvegarde est fatal. Configurez restic ou borg avec un cron quotidien vers Backblaze B2 (environ 0,005 USD par Go par mois). Pour explorer plus loin sur le tooling DevOps, lisez notre guide Uptime Kuma et notre workflow Git en équipe.

Un VPS compromis ou disque crashé sans backup hors-serveur = perte totale de données. Configurez Restic ou Borg avec stockage Backblaze B2 (6 USD/To/mois) ou Hetzner Storage Box (2 100 FCFA/mois pour 1 To). Sauvegardez quotidiennement les données critiques (/var/www, /var/lib/postgresql, /etc) en 5 minutes. Testez la restauration mensuellement sur un VPS de staging — sinon vous découvrez en panne réelle que les backups étaient corrompus depuis 6 mois.

Étape 11 — Activer un audit centralisé avec auditd

Le démon auditd trace les appels système sensibles : modifications de /etc/passwd, exécution de binaires sudo, accès aux clés SSH. Ces traces deviennent inestimables après un incident pour reconstituer la chronologie d’une compromission. Installation : apt install -y auditd. La configuration par défaut couvre déjà les fichiers critiques. Pour étoffer le tableau, ajoutez des règles dans /etc/audit/rules.d/custom.rules ciblant les répertoires applicatifs sensibles. Consultez les logs avec ausearch -k mot-cle ou aureport --summary. Conservez ces logs au moins 90 jours, idéalement déportés vers un puits de logs externe (Loki, Graylog, Wazuh).

Étape 12 — Chiffrer les sauvegardes au repos

Une sauvegarde non chiffrée stockée chez Backblaze B2 ou Wasabi protège contre la perte de données mais expose tout votre code et vos bases en cas de compromission du compte de stockage. restic et borg chiffrent par défaut avec une passphrase forte. Stockez cette passphrase dans un coffre-fort hors-serveur (Bitwarden, 1Password, KeePassXC partagé sur un cloud chiffré). Sans la passphrase, les sauvegardes sont inutilisables même par l’attaquant qui aurait volé vos identifiants S3. Documentez la procédure de restauration dans un runbook accessible aux deux ou trois personnes habilitées à restaurer.

Étape 13 — Surveillance d’intégrité avec AIDE

AIDE (Advanced Intrusion Detection Environment) calcule un hash de chaque fichier critique du système et alerte si l’un d’eux est modifié sans cause légitime. Installation : apt install -y aide aide-common, initialisation : aideinit, puis cron quotidien : aide --check. Tout binaire système modifié par un rootkit ressort dans le rapport. Combinée à fail2ban et auditd, cette défense en profondeur rend un compromis silencieux extrêmement difficile.

Étape 14 — Désactiver les modules noyau inutiles

Un VPS web n’a pas besoin du module cramfs, freevxfs, jffs2, hfs, hfsplus, squashfs, ni de la pile dccp, sctp, rds, tipc. Chaque module chargé est une surface d’attaque potentielle. Bloquez-les via /etc/modprobe.d/CIS.conf avec des lignes install cramfs /bin/true répétées pour chaque module. Cette mesure suit les recommandations CIS Benchmark Debian/Ubuntu et coûte zéro performance.

Étape 15 — Renforcer les paramètres sysctl réseau

Le noyau Linux expose des dizaines de paramètres réseau qui peuvent atténuer les attaques classiques (SYN flood, ICMP redirects, source routing). Créez /etc/sysctl.d/99-hardening.conf avec les directives net.ipv4.tcp_syncookies = 1, net.ipv4.conf.all.accept_redirects = 0, net.ipv4.conf.all.send_redirects = 0, net.ipv4.conf.all.rp_filter = 1, net.ipv6.conf.all.accept_ra = 0. Appliquez avec sysctl -p /etc/sysctl.d/99-hardening.conf. Vérifiez chaque paramètre avec sysctl net.ipv4.tcp_syncookies.

Étape 16 — Utiliser un VPN privé pour l’administration

Plutôt que d’exposer SSH même sur un port haut, déployez un VPN WireGuard (paquet wireguard) qui n’expose qu’un port UDP. SSH n’écoute alors que sur l’IP interne du tunnel, totalement invisible depuis Internet. Une équipe de cinq devs partage le réseau VPN et accède à l’ensemble du parc serveur via une seule porte d’entrée chiffrée. WireGuard est léger, rapide et négligeable en consommation CPU sur un VPS modeste.

Étape 17 — Plan de réponse à incident écrit

Documentez en une page : qui appeler en premier, comment isoler un serveur compromis (couper le réseau via UFW, garder la machine allumée pour la forensique), où sont les sauvegardes propres, quel domaine de secours basculer en cas de DNS poisoning. Ce runbook doit être accessible hors du serveur compromis lui-même : sur un Notion partagé, un pad CryptPad, un dépôt Git privé répliqué localement par chaque membre de l’équipe.

Étape 18 — Isoler les services applicatifs en conteneurs

Faire tourner Nginx, PHP-FPM, PostgreSQL et Redis directement sur l’hôte expose tout le système à une faille dans n’importe lequel d’entre eux. Encapsuler chaque service dans un conteneur Docker avec un utilisateur non-root, des volumes en lecture seule quand c’est possible, et un réseau Docker isolé limite drastiquement le rayon d’explosion d’une compromission. Ajoutez read_only: true, cap_drop: [ALL], et security_opt: [no-new-privileges:true] dans les services docker-compose.yml qui le supportent. Surveillez les vulnérabilités des images avec docker scout cves ou trivy image nom-image avant chaque mise en production.

Étape 19 — Audit régulier avec Lynis

Lynis est un scanner de sécurité open source qui évalue la posture d’un Linux selon plus de 200 contrôles. Installation : apt install -y lynis, exécution : lynis audit system. Le rapport indique un score (idéalement supérieur à 75 sur 100) et liste les recommandations classées par priorité. Lancez Lynis tous les mois et après chaque changement majeur. Le différentiel entre deux exécutions met en évidence les régressions involontaires introduites par une nouvelle installation de paquet ou un changement de configuration.

Étape 20 — Revue trimestrielle des accès

Tous les trois mois, listez les comptes utilisateurs avec cat /etc/passwd | grep -v nologin, les clés SSH actives dans ~/.ssh/authorized_keys de chaque compte, et les tokens API stockés sur le serveur. Révoquez tout accès lié à un prestataire ou employé qui n’est plus en mission. Cette hygiène évite l’accumulation silencieuse de portes dérobées légitimes qui finissent par former une surface d’attaque opaque même pour le lead technique en place.

Partager