Sécuriser un serveur Linux Ubuntu 24.04 commence à la seconde où la machine démarre, parce qu'elle démarre sans broncher et qu'elle est aussi grande ouverte, ce que personne ne prend la peine de te dire. Voilà la passe que je fais sur chaque nouveau VPS 24.04 LTS avant de lui confier quoi que ce soit d'important. SSH verrouillé en mode clés uniquement, sur un port où les scanners ne campent pas. UFW avec le moins de règles possible. fail2ban qui chasse les bots de brute-force, mises à jour de sécurité en fond, AppArmor qui applique vraiment, auditd pour répondre dans six mois à qui a touché à quoi sans deviner. 30 commandes que tu colles dans l'ordre, et après chacune la vérif qui prouve qu'elle a pris.
The short answer
Durcis un VPS Ubuntu 24.04 LTS tout neuf en une seule passe : SSH en clés uniquement sur un
port personnalisé (PermitRootLogin no, PasswordAuthentication no), ufw default deny incoming,
fail2ban sur la jail SSH, unattended-upgrades pour les correctifs de sécurité, aa-enforce
sur chaque profil AppArmor, et auditd qui surveille les fichiers qui comptent. Après chaque
commande, tu lances la vérif qui prouve qu'elle a pris.
Une machine Ubuntu toute fraîche démarre sans broncher. Elle est aussi grande ouverte, ce que personne ne prend la peine de te dire. Voilà donc la passe que je fais sur chaque nouveau VPS 24.04 LTS avant de lui confier quoi que ce soit d'important. SSH verrouillé en mode clés uniquement, sur un port où les scanners ne campent pas. UFW avec le moins de règles possible. fail2ban qui chasse les bots de brute-force, les mises à jour de sécurité automatiques qui tournent en fond, AppArmor qui applique vraiment au lieu de bouder en mode complain, et auditd pour que, dans six mois, je puisse répondre à "qui a touché à quoi" sans deviner. Ça fait 30 commandes. Tu les colles dans l'ordre, et après chacune je te file la vérif qui prouve qu'elle a pris. Bloque 30 à 45 minutes. À la fin, le bourdonnement permanent des attaques automatisées rebondit dessus sans laisser de trace.
Avant de commencer. Je pars du principe que tu as un VPS Ubuntu 24.04 LTS tout neuf (OVH, Hetzner, Scaleway, Contabo, AWS Lightsail) et que tu pilotes tout en SSH depuis ton portable. Ne ferme pas ta session SSH avant d'avoir terminé l'étape 3. Je me suis verrouillé dehors exactement comme ça, une fois. Un sshd_config saisi de travers, pas de second terminal ouvert, et ça m'a valu une heure bien marrante sur la console de secours. Garde cette première session en vie. C'est ta bouée de sauvetage.
Premier accès root et création de l'utilisateur admin
Connecte-toi en root, juste cette fois. Ensuite, fabrique-toi un utilisateur normal pour le quotidien et glisse-le dans le groupe sudo. Vivre en root à plein temps ? C'est comme ça qu'une faute de frappe efface la mauvaise chose pendant que tu tends encore la main vers le café.
# On your local machine
ssh root@YOUR_IP
# On the server (as root)
adduser admin # create the admin user
usermod -aG sudo admin # add to sudo group
mkdir -p /home/admin/.ssh
chmod 700 /home/admin/.ssh
cp /root/.ssh/authorized_keys /home/admin/.ssh/
chown -R admin:admin /home/admin/.ssh
Vérifie que ça a pris :
su - admin
sudo whoami # must print: root
exit
Premières mises à jour système
Un serveur tout neuf débarque en général avec 20 à 60 paquets déjà périmés. Patche-moi tout ça avant d'installer la moindre de tes propres affaires. Tu ne veux pas construire par-dessus des trous qui ont déjà des exploits publics.
apt update
apt upgrade -y
apt dist-upgrade -y
apt autoremove -y
apt autoclean
Vérifie que ça a pris :
apt list --upgradable
# Must print: Listing... Done (and nothing else)
Tu vois un message "Pending kernel upgrade" ? Redémarre tout de suite (reboot), attends qu'il revienne, puis continue. Persister sur l'ancien kernel ne fait que te mettre de côté un problème bizarre pour plus tard.
Durcissement SSH (clés, port personnalisé, pas de login root)
C'est l'étape majeure. C'est aussi celle qui te verrouillera dehors net si tu la bâcles. Quelques modifs dans /etc/ssh/sshd_config : on tue le login root direct, on coupe complètement l'auth par mot de passe pour que ce soit clés ou rien, puis on déplace SSH du port 22 vers un endroit où les scanners ne tapent pas en boucle 24 h/24.
# Backup the config before editing
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
# Edit the config
nano /etc/ssh/sshd_config
# Lines to set or add:
Port 2222 # custom port (pick any 1024-65535)
PermitRootLogin no # no more direct root login
PasswordAuthentication no # SSH keys only
PubkeyAuthentication yes
MaxAuthTries 3 # 3 attempts max per connection
ClientAliveInterval 300 # auto-disconnect after 5 min
ClientAliveCountMax 2
LoginGraceTime 30
AllowUsers admin # restrict to the admin user only
Valide la syntaxe avant de relancer sshd. Toujours. Une seule ligne foireuse dans ce fichier et le redémarrage te jette dehors sans porte de retour :
sshd -t
# No output means OK; if there is one, fix it before continuing
# Restart SSH
systemctl restart ssh
Critique. Ouvre une toute nouvelle session SSH sur le nouveau port et prouve qu'elle te connecte vraiment avant de fermer la session root dans laquelle tu es assis. Si la nouvelle session rebondit, l'ancienne est encore là, juste sous la main, pour annuler la modif. Ce terminal ouvert est la seule chose qui te sépare d'une console de secours à 2 h du matin.
ssh admin@YOUR_IP -p 2222 Vérifie que ça a pris :
whoami # must print: admin
sudo -i # must prompt for your admin password and elevate to root
Pare-feu UFW avec des règles minimales
UFW n'est qu'une façade plus sympa collée par-dessus nftables/iptables. C'est celui vers lequel je me tourne sur quasiment chaque machine. L'idée tient en une phrase : claque la porte sur tout ce qui entre, puis n'entrouvre que les quelques ports dont tu as vraiment besoin, un par un, à la main.
apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
# Open the custom SSH port (mandatory before enabling)
ufw allow 2222/tcp comment 'SSH custom port'
# Open application ports as needed
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
# Enable the firewall
ufw enable # answer y
Vérifie que ça a pris :
ufw status verbose
# Must show "Status: active" and the rules above
Une base de données derrière l'appli ? Postgres, MySQL, un cache Redis, peu importe. Jamais tu ne laisses traîner 5432, 3306 ou 6379 sur l'internet ouvert. Un Redis non authentifié passe de "public" à "compromis" en quelques heures, parfois moins, et je l'ai vu se produire. Tunnelise-toi dedans en SSH depuis le côté appli, ou monte un lien WireGuard. Mais garde-le hors de l'interface publique.
fail2ban contre le brute-force SSH
Le SSH en clés uniquement n'empêche pas les bots d'essayer. Ils continuent de frapper par milliers, et chaque tentative rejetée brûle quand même un brin de CPU tout en encrassant tes logs. fail2ban guette toute IP qui échoue trop souvent dans une fenêtre donnée, puis lui colle un bannissement pare-feu sans que tu lèves le petit doigt. Tu règles les seuils une fois et tu n'y reviens quasiment jamais.
apt install -y fail2ban
# Create the local config (jail.local takes precedence over jail.conf)
cat > /etc/fail2ban/jail.local <<'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
ignoreip = 127.0.0.1/8 ::1
[sshd]
enabled = true
port = 2222
backend = systemd
EOF
systemctl enable --now fail2ban
Vérifie que ça a pris :
fail2ban-client status sshd
# Must show "Currently failed", "Total failed" and "Currently banned"
Tu as banni ta propre IP après avoir raté la connexion deux-trois fois ? Ça nous arrive à tous. Libère-la avec fail2ban-client set sshd unbanip 1.2.3.4.
Mises à jour automatiques (unattended-upgrades)
Ubuntu sort des correctifs de sécurité deux-trois fois par semaine, et personne de sensé ne se connecte en SSH pour lancer apt upgrade à la main un jour sur deux. Du coup, tu le laisses patcher la partie sécurité tout seul, pendant que les grosses montées de version, celles qui cassent vraiment des choses, restent hors jeu. Honnêtement, je trouve que c'est le truc avec le meilleur rendement par minute de toute la liste. Je me convaincs peut-être tout seul parce que ça demande si peu d'effort, mais le calcul tient la route pour moi depuis des années de machines.
apt install -y unattended-upgrades apt-listchanges
# Enable Ubuntu's default config
dpkg-reconfigure -plow unattended-upgrades
# Answer Yes to the question
# Verify the config file
nano /etc/apt/apt.conf.d/50unattended-upgrades
Ouvre 50unattended-upgrades et revérifie que les sources de sécurité sont bien activées :
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
Vérifie que ça a pris :
unattended-upgrade --dry-run --debug 2>&1 | head -20
# Must list the packages that would be updated
AppArmor en mode enforce
Sur Ubuntu, le Mandatory Access Control passe par AppArmor. Chaque service reçoit un profil qui dit exactement quels fichiers et quels appels système il a le droit de toucher, et tout ce qui sort du cadre se fait recadrer sec. Il est livré sur la 24.04 et il tourne déjà. Le piège que personne ne mentionne : une partie de ces profils restent en mode "complain", qui journalise la violation puis hausse les épaules et la laisse passer quand même. Donc on les bascule en "enforce" et on leur donne des dents.
apt install -y apparmor apparmor-utils apparmor-profiles apparmor-profiles-extra
# Current status
aa-status
# Switch all profiles to enforce
aa-enforce /etc/apparmor.d/*
Vérifie que ça a pris :
aa-status | head -5
# The line "profiles are in enforce mode" must show a number > 30
Quelque chose se casse la figure dès que l'enforce s'enclenche ? Ne va pas arracher tout le sous-système, c'est démesuré. Sors journalctl -u apparmor et il te dira précisément ce qui a été refusé. À partir de là, soit tu corriges ce profil-là, soit, si tu es pressé, tu repasses uniquement ce profil en complain le temps de régler ça : aa-complain /etc/apparmor.d/usr.sbin.service-name.
Journaux d'audit avec auditd
auditd, c'est la boîte noire. Il journalise discrètement les trucs sensibles : les lectures de fichiers critiques et chaque commande sudo, plus les changements de config que tu n'attraperais jamais autrement. Tu n'y penseras pas une seconde jusqu'au jour où quelqu'un demande "qui a édité /etc/passwd hier à 14 h ?" et, au lieu de hausser les épaules, tu sors la réponse exacte.
apt install -y auditd audispd-plugins
# Minimal rules: watch critical files
cat > /etc/audit/rules.d/hardening.rules <<'EOF'
# User account modifications
-w /etc/passwd -p wa -k user_modification
-w /etc/shadow -p wa -k user_modification
-w /etc/group -p wa -k user_modification
-w /etc/sudoers -p wa -k sudoers_modification
-w /etc/sudoers.d/ -p wa -k sudoers_modification
# SSH modifications
-w /etc/ssh/sshd_config -p wa -k ssh_config
# Abnormal network egress
-a always,exit -F arch=b64 -S socket -F a0=10 -k network_socket
# Lock the rules (no modification without reboot)
-e 2
EOF
systemctl enable --now auditd
systemctl restart auditd
Vérifie que ça a pris :
auditctl -l | head
# Must list the rules above
Besoin de relire ce qui s'est passé ? ausearch -k user_modification sort les événements par tag. Ou aureport -au si tu veux juste le résumé d'authentification.
Synchronisation de l'heure et NTP
Les gens zappent celle-ci, puis passent un après-midi à se demander, dépités, pourquoi rien ne marche. Laisse l'horloge dériver de quelques secondes et, d'un coup, les certificats TLS sont lus comme invalides, donc tes propres appels HTTPS sortants se font jeter. En plus, essayer d'aligner ces logs sur tes autres machines devient un jeu de devinettes. Bonne nouvelle : Ubuntu 24.04 fait déjà tourner systemd-timesyncd, donc ça revient surtout à le pointer sur le bon fuseau et à confirmer qu'il est réveillé.
timedatectl set-timezone Europe/Paris # or your time zone
timedatectl set-ntp true
# Verify
timedatectl status
Vérifie que ça a pris :
timedatectl status | grep -E "(synchronized|NTP)"
# Must show "System clock synchronized: yes" and "NTP service: active"
Vérification finale et snapshot
Avant de valider cette machine comme prête pour la prod, balance tout le lot d'un coup et lis vraiment la sortie, de haut en bas :
# Consolidated checks (";" separator so everything runs even if one command fails)
echo "=== SSH ===" ; grep -E "^(Port|PermitRoot|PasswordAuth)" /etc/ssh/sshd_config
echo "=== UFW ===" ; ufw status numbered | head -10
echo "=== fail2ban ===" ; fail2ban-client status sshd
echo "=== unattended-upgrades ===" ; systemctl is-active unattended-upgrades
echo "=== AppArmor ===" ; aa-status | head -3
echo "=== auditd ===" ; systemctl is-active auditd
echo "=== Updates ===" ; apt list --upgradable 2>/dev/null | wc -l
echo "=== Uptime ===" ; uptime
Une fois que chaque ligne dit ce qu'elle doit dire, va chercher un snapshot du serveur chez ton hébergeur (OVH l'appelle "Backup snapshot", Hetzner juste "Snapshot", AWS "AMI", Scaleway "Snapshot" lui aussi). Deux minutes, grand maximum. Ce que tu récupères, c'est une image propre et saine sur laquelle revenir le jour où tu finiras forcément par casser quelque chose plus tard. J'en prends un ici même, à chaque fois.
Et si cette machine compte vraiment en prod, ce n'est pas la ligne d'arrivée. Greffe-y du monitoring d'uptime (SecurityWatch ou UptimeRobot) plus quelque chose qui garde un œil sur l'appli et sur l'hôte en dessous (Netdata, Grafana Cloud Free, ou Prometheus + node_exporter). Durcis un serveur puis ne le regarde plus jamais, et tu apprendras qu'il est mort par un utilisateur furieux, des jours après les faits.
Maintenance de routine après le durcissement
Personne n'a envie d'entendre cette partie : tout ça pourrit si tu t'en vas. Voilà le rythme que je tiens sur une machine 24.04 LTS en 2026. Chaque semaine, un coup d'œil rapide à fail2ban-client status sshd et journalctl -p err -b. Chaque mois, je vérifie aa-status, ufw status et apt list --upgradable. Chaque trimestre, je passe /etc/passwd au crible pour repérer des utilisateurs que je ne reconnais pas. Je survole /etc/cron.d/ à la recherche de jobs que je n'ai jamais planifiés. Je lance last -n 50 et je scrute tout login qui me semble louche. Tout ce qui est bizarre sur cette liste n'est pas un "rappelle-le-moi le mois prochain". C'est un "je lâche tout et je creuse aujourd'hui".
Sources et pour aller plus loin
Questions fréquentes
Pourquoi changer le port SSH si j'utilise déjà des clés ?
Ce n'est pas l'un ou l'autre. Le déplacement de port s'empile par-dessus tes clés, il ne les remplace pas. Les bots qui balaient toute la plage IPv4 envoient quelque chose comme 90 pour cent de leurs tentatives droit sur le port 22, donc faire grimper SSH sur un port haut fait passer mes logs de dix mille échecs par jour à une poignée, et sshd arrête de brûler des cycles à dire non. C'est de la sécurité par l'obscurité ? Ouais, totalement. Mais greffé sur les clés, ça ne me coûte rien et ça marche tranquillement, alors j'embarque ça à chaque fois.
UFW ou nftables directement, lequel choisir ?
UFW, pour quasiment tout. La config se lit clair et la syntaxe est vraiment dure à louper, et ça couvre un serveur applicatif normal avec de la marge. Descends jusqu'au nftables brut seulement quand tu as réellement besoin des trucs sophistiqués que UFW ne sait pas exprimer, comme le port knocking, le filtrage GeoIP ou du rate limiting bien serré. Et honnêtement tu n'as pas à choisir : balance des règles brutes dans /etc/ufw/before.rules et tu étends UFW sans l'arracher.
Les mises à jour automatiques peuvent-elles casser mon serveur ?
Ça peut. Ça arrive très rarement. Par défaut, unattended-upgrades ne tire que des sources -security, donc tu reçois les correctifs critiques et aucun des gros sauts de version qui cassent vraiment tout. Sur une LTS, les chances que ça te morde sont vraiment minuscules. Le seul bouton que je tourne sur tout ce qui est important : je tue le redémarrage automatique et je redémarre la chose moi-même dans une fenêtre de maintenance, pour qu'elle ne tombe pas en plein milieu d'après-midi avec des utilisateurs encore dessus.
AppArmor ou SELinux ?
Sur Ubuntu ? AppArmor, sans débat. Pourrais-tu mettre SELinux à la place ? Bien sûr, techniquement. Mais il faudrait d'abord arracher AppArmor et réécrire chaque profil depuis zéro, et pour la plupart des installations c'est une montagne d'efforts qui ne t'apporte rien de concret. SELinux mérite son salaire du côté RHEL du monde (CentOS Stream, Rocky, et compagnie), où c'est le choix natif et où toute la distrib est déjà câblée autour. Prends simplement ce que ta distrib embarque et prévoit nativement.
Comment auditer le serveur 6 mois après le durcissement ?
Une poignée d'outils gratuits assurent ça. Lynis (apt install lynis; lynis audit system) te file un score de durcissement plus une liste de tout ce qui est encore mou. OpenSCAP ne sort que quand tu es dans une boîte réglementée et qu'il te faut la trace écrite. Pour renifler les rootkits, c'est chkrootkit et rkhunter. Je lance Lynis une fois par trimestre, et les scanners de rootkits restent dans le tiroir tant que rien ne cloche vraiment.