L'ancienne fiche datait de Debian 11 et s'arrêtait à une liste de commandes : rien sur les clés SSH, le pare-feu, fail2ban, les mises à jour automatiques ni la sauvegarde. Elle portait aussi deux erreurs qui mordent — une locale écrite avec un underscore, et l'ordre des noms sur la ligne 127.0.1.1 qui décide de ce que renvoie « hostname -f ». La nouvelle page couvre les quinze étapes, du DNS à la sauvegarde testée, avec les pièges propres à Trixie : sources deb822, SSH activé par socket, /tmp en tmpfs. Elle reste générique — aucun service particulier n'y est déployé. Deux extensions Markdown sont activées pour elle : les listes de tâches (la checklist récapitulative) et mermaid (l'ordre des opérations). Aucune dépendance nouvelle : le thème Material embarque déjà mermaid. Les deux sont documentées dans la page Markdown du wiki. L'adresse change, donc l'ancienne reste servie par une page de renvoi. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BE4rvHVETRoWnYNDTGssdo
1192 lines
43 KiB
Markdown
1192 lines
43 KiB
Markdown
---
|
|
description: Préparer un serveur Debian 13 « Trixie » livré par un hébergeur — DNS, nom d'hôte, sources deb822, comptes, SSH par clé, pare-feu, fail2ban, mises à jour automatiques, supervision et sauvegarde.
|
|
---
|
|
|
|
# Préparation d'un serveur Debian 13 (Trixie)
|
|
|
|
!!! info "État du document"
|
|
Rédigé le **19/09/2026** pour **Debian 13 « Trixie »**. Il remplace l'ancienne fiche
|
|
Debian 11 : ce qui a changé est résumé en fin de page.
|
|
|
|
## Avant de commencer
|
|
|
|
Cette procédure part d'une installation minimale de Debian 13 « Trixie » fraîchement livrée par un hébergeur, et s'arrête au moment où le serveur est prêt à recevoir ses services. Comptez 30 à 45 minutes.
|
|
|
|
**Règle d'or** : tant que vous touchez à SSH ou au pare-feu, gardez une **deuxième session SSH ouverte** sur le serveur et ne la fermez jamais. Elle est votre filet de sécurité si une modification vous verrouille dehors.
|
|
|
|
Vérifiez avant de commencer que vous disposez d'un **accès de secours hors SSH** : console KVM/VNC, console série ou mode rescue de l'hébergeur. Sans lui, une erreur de pare-feu signifie une réinstallation.
|
|
|
|
### Variables utilisées dans ce document
|
|
|
|
Remplacez systématiquement ces valeurs par les vôtres.
|
|
|
|
| Variable | Exemple | Signification |
|
|
| --- | --- | --- |
|
|
| `SRV` | `web01` | Nom court du serveur (sans domaine) |
|
|
| `FQDN` | `web01.exemple.fr` | Nom complet, celui du DNS et du reverse |
|
|
| `IPV4` | `203.0.113.10` | Adresse IPv4 publique |
|
|
| `IPV6` | `2001:db8::10` | Adresse IPv6 publique, si fournie |
|
|
| `USER` | `alix` | Votre futur compte d'administration |
|
|
| `VENDOR` | `debian` | Compte créé par l'hébergeur, à neutraliser |
|
|
| `SSHPORT` | `2222` | Port SSH final, si vous le déplacez |
|
|
|
|
### Ordre des opérations
|
|
|
|
L'ordre compte : le DNS se propage pendant que vous travaillez, et le pare-feu ne se ferme qu'une fois le nouvel accès SSH prouvé.
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
A[DNS + reverse] --> B[Identité<br/>hostname, hosts]
|
|
B --> C[Système<br/>MAJ, paquets, locale]
|
|
C --> D[Compte admin<br/>+ sudo]
|
|
D --> E[SSH<br/>clés + durcissement]
|
|
E --> F[Pare-feu<br/>+ fail2ban]
|
|
F --> G[Automatismes<br/>MAJ, supervision]
|
|
G --> H[Sauvegarde<br/>+ instantané]
|
|
```
|
|
|
|
## Étape 1 — DNS direct et reverse DNS
|
|
|
|
Faites cette étape en premier : la propagation DNS prend de quelques minutes à quelques heures, et elle tournera pendant que vous configurez le reste. Un reverse DNS cohérent conditionne l'acceptation de vos mails et la lisibilité de vos journaux.
|
|
|
|
### 1.1 Enregistrements directs (zone DNS du domaine)
|
|
|
|
Dans l'interface DNS de votre registrar ou de votre hébergeur, créez :
|
|
|
|
| Type | Nom | Valeur | TTL |
|
|
| --- | --- | --- | --- |
|
|
| `A` | `web01` | `203.0.113.10` | 300 pendant la mise en place, puis 3600 |
|
|
| `AAAA` | `web01` | `2001:db8::10` | idem, si IPv6 fournie |
|
|
|
|
Un TTL court (300 s) pendant l'installation vous laisse corriger une erreur sans attendre. Remontez-le une fois le serveur stabilisé.
|
|
|
|
### 1.2 Reverse DNS (PTR)
|
|
|
|
Le PTR ne se déclare pas dans la zone du domaine, mais **chez le propriétaire de l'adresse IP**, c'est-à-dire votre hébergeur. Cherchez dans son panneau une entrée nommée « reverse », « rDNS » ou « PTR », sur la fiche de l'IP et non sur celle du domaine.
|
|
|
|
La valeur doit être **exactement le FQDN** déclaré en 1.1 : `web01.exemple.fr`. Faites-le pour l'IPv4 **et** pour l'IPv6 ; un reverse IPv6 manquant est une cause classique de mails rejetés.
|
|
|
|
### 1.3 Vérification
|
|
|
|
Depuis votre poste, une fois la propagation faite :
|
|
|
|
```bash
|
|
dig +short web01.exemple.fr A
|
|
dig +short web01.exemple.fr AAAA
|
|
dig +short -x 203.0.113.10
|
|
dig +short -x 2001:db8::10
|
|
```
|
|
|
|
Les quatre réponses doivent se refermer sur elles-mêmes : le A pointe vers l'IP, le PTR de cette IP renvoie le même FQDN. C'est ce qu'on appelle un FCrDNS valide (*forward-confirmed reverse DNS*).
|
|
|
|
> Si `dig` n'est pas installé sur votre poste : `sudo apt install dnsutils` sous Debian/Ubuntu, `brew install bind` sous macOS.
|
|
|
|
## Étape 2 — Première connexion
|
|
|
|
Connectez-vous avec le compte fourni par l'hébergeur. Sur les images Debian officielles, c'est `debian` ; d'autres utilisent `admin`, `ubuntu` ou `root`.
|
|
|
|
```bash
|
|
ssh debian@203.0.113.10
|
|
```
|
|
|
|
Utilisez l'IP et non le FQDN pour cette première connexion : le DNS n'est peut-être pas encore propagé.
|
|
|
|
### Vérifier ce qu'on a vraiment reçu
|
|
|
|
Avant toute modification, prenez trois minutes pour constater l'état initial.
|
|
|
|
```bash
|
|
cat /etc/os-release # confirme Debian 13 (trixie)
|
|
uname -r # version du noyau
|
|
ip -brief address # interfaces et adresses
|
|
lsblk # disques et partitions
|
|
free -h # RAM et swap
|
|
sudo systemctl list-units --type=service --state=running
|
|
sudo ss -tulpn # ce qui écoute déjà sur le réseau
|
|
```
|
|
|
|
La dernière commande est la plus instructive : elle montre les services exposés dès la livraison. Tout ce qui écoute sur `0.0.0.0` ou `::` et que vous ne reconnaissez pas mérite une décision explicite — désactiver ou garder.
|
|
|
|
### Si la connexion est refusée
|
|
|
|
| Symptôme | Cause fréquente |
|
|
| --- | --- |
|
|
| `Permission denied (publickey)` | La clé publique n'a pas été injectée à la commande, ou mauvais nom d'utilisateur |
|
|
| `Connection refused` | Le serveur n'a pas fini de démarrer, ou SSH écoute sur un autre port |
|
|
| `Connection timed out` | Pare-feu amont côté hébergeur (*security group*, *firewall network*) |
|
|
| `REMOTE HOST IDENTIFICATION HAS CHANGED` | Réinstallation ou réattribution d'IP → `ssh-keygen -R 203.0.113.10` |
|
|
|
|
## Étape 3 — Nom d'hôte et /etc/hosts
|
|
|
|
### 3.1 Définir le nom d'hôte
|
|
|
|
Debian attend ici le **nom court**, pas le FQDN. Le FQDN est reconstitué via `/etc/hosts`.
|
|
|
|
```bash
|
|
sudo hostnamectl set-hostname web01
|
|
```
|
|
|
|
Vous pouvez aussi renseigner deux champs purement informatifs, utiles quand on gère plusieurs machines :
|
|
|
|
```bash
|
|
sudo hostnamectl set-hostname "Front web — Paris" --pretty
|
|
sudo hostnamectl set-chassis vm # ou: server, desktop
|
|
```
|
|
|
|
### 3.2 Corriger /etc/hosts
|
|
|
|
C'est ce fichier, et non `hostnamectl`, qui donne au système son FQDN. La règle : sur la ligne `127.0.1.1`, **le FQDN vient en premier, le nom court ensuite**.
|
|
|
|
```bash
|
|
sudo nano /etc/hosts
|
|
```
|
|
|
|
Ciblez ce résultat :
|
|
|
|
```
|
|
127.0.0.1 localhost
|
|
127.0.1.1 web01.exemple.fr web01
|
|
|
|
# The following lines are desirable for IPv6 capable hosts
|
|
::1 localhost ip6-localhost ip6-loopback
|
|
ff02::1 ip6-allnodes
|
|
ff02::2 ip6-allrouters
|
|
```
|
|
|
|
Certains hébergeurs pré-remplissent la ligne `127.0.1.1` avec le nom d'usine de la machine. Deux options : le supprimer, ou le laisser **après** vos deux entrées — la ligne compte alors quatre références.
|
|
|
|
```
|
|
127.0.1.1 web01.exemple.fr web01 vps-1a2b3c.exemple-hebergeur.net vps-1a2b3c
|
|
```
|
|
|
|
Les deux formes fonctionnent. Supprimer l'ancien nom est plus propre ; le conserver évite de casser un script de l'hébergeur qui s'y référerait encore.
|
|
|
|
> ⚠️ Ne touchez jamais à la ligne `127.0.0.1 localhost`. Et n'associez pas le FQDN à l'IP publique dans `/etc/hosts` : sur une machine à IP dynamique ou derrière NAT, cela crée des résolutions fantomatiques.
|
|
|
|
### 3.3 Vérifier
|
|
|
|
```bash
|
|
hostname # → web01
|
|
hostname -f # → web01.exemple.fr
|
|
hostname -d # → exemple.fr
|
|
hostnamectl status
|
|
```
|
|
|
|
Si `hostname -f` répond autre chose que le FQDN attendu, la ligne `127.0.1.1` est mal ordonnée. Le changement est immédiat, mais reconnectez-vous pour que l'invite de commande l'affiche.
|
|
|
|
> Sur certaines images cloud, `cloud-init` réécrit le nom d'hôte à chaque redémarrage. Si votre nom revient à sa valeur d'origine après un `reboot` :
|
|
>
|
|
> ```bash
|
|
> sudo sed -i 's/^preserve_hostname:.*/preserve_hostname: true/' /etc/cloud/cloud.cfg
|
|
> grep preserve_hostname /etc/cloud/cloud.cfg
|
|
> ```
|
|
>
|
|
> Ajoutez la ligne si elle est absente.
|
|
|
|
## Étape 4 — Sources APT et mise à jour
|
|
|
|
### 4.1 Passer les sources au format deb822
|
|
|
|
Debian 13 introduit le format deb822 pour les dépôts. L'ancien format une-ligne est officiellement déprécié, même s'il restera supporté par Debian 14 « Forky » ([détail du changement](https://dev.to/r3m8/debian-13-trixie-adoptez-le-nouveau-format-deb822-1ml6)). Autant partir sur le bon format tout de suite.
|
|
|
|
```bash
|
|
sudo apt modernize-sources
|
|
```
|
|
|
|
La commande convertit `/etc/apt/sources.list` vers `/etc/apt/sources.list.d/debian.sources` et laisse au passage des sauvegardes `/etc/apt/sources.list.bak` et `/etc/apt/sources.list.save`, ce qui permet de revenir en arrière ([procédure détaillée](https://ostechnix.com/migrate-to-deb822-format-debian-13-trixie/)).
|
|
|
|
Vérifiez le résultat :
|
|
|
|
```bash
|
|
cat /etc/apt/sources.list.d/debian.sources
|
|
```
|
|
|
|
Vous devez y trouver trois blocs : `trixie`, `trixie-updates` et `trixie-security`, chacun avec un champ `Signed-By`.
|
|
|
|
```
|
|
Types: deb
|
|
URIs: http://deb.debian.org/debian/
|
|
Suites: trixie trixie-updates
|
|
Components: main contrib non-free-firmware
|
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
|
|
|
Types: deb
|
|
URIs: http://security.debian.org/debian-security/
|
|
Suites: trixie-security
|
|
Components: main contrib non-free-firmware
|
|
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
|
```
|
|
|
|
> Si le dépôt `trixie-security` manque, ajoutez-le à la main : sans lui, vous ne recevez aucun correctif de sécurité. C'est l'erreur la plus coûteuse de toute cette procédure.
|
|
|
|
`non-free-firmware` est nécessaire sur matériel physique (cartes réseau, RAID). `contrib` et `non-free` sont optionnels ; ne les ajoutez que si un paquet précis l'exige.
|
|
|
|
### 4.2 Mettre à jour
|
|
|
|
```bash
|
|
sudo apt update
|
|
sudo apt full-upgrade -y
|
|
sudo apt autoremove --purge -y
|
|
sudo apt clean
|
|
```
|
|
|
|
`full-upgrade` et non `upgrade` : le premier accepte d'installer ou de retirer des paquets quand une dépendance a changé, ce qui est exactement ce qu'on veut sur une machine neuve. `upgrade` bloquerait sur ces cas.
|
|
|
|
### 4.3 Redémarrer si le noyau a changé
|
|
|
|
```bash
|
|
ls /var/run/reboot-required 2>/dev/null && echo "Redémarrage nécessaire"
|
|
sudo reboot
|
|
```
|
|
|
|
Après redémarrage, reconnectez-vous et vérifiez que tout est remonté :
|
|
|
|
```bash
|
|
systemctl is-system-running # attendu : running
|
|
systemctl --failed # attendu : 0 loaded units listed
|
|
uptime
|
|
```
|
|
|
|
Un état `degraded` signale au moins un service en échec ; `systemctl --failed` vous dit lequel.
|
|
|
|
## Étape 5 — Paquets de base
|
|
|
|
```bash
|
|
sudo apt install -y \
|
|
vnstat iftop htop nano git \
|
|
curl wget ca-certificates gnupg \
|
|
dnsutils net-tools lsof tcpdump \
|
|
rsync tree zip unzip \
|
|
ncdu sysstat needrestart
|
|
```
|
|
|
|
| Paquet | À quoi il sert |
|
|
| --- | --- |
|
|
| `vnstat` | Compteur de trafic réseau historisé, léger (`vnstat -d`, `vnstat -m`) |
|
|
| `iftop` | Trafic en temps réel par connexion |
|
|
| `htop` | Processus, CPU, mémoire, en interactif |
|
|
| `ncdu` | Trouve ce qui remplit le disque, en navigation |
|
|
| `sysstat` | `sar`, `iostat`, `pidstat` : historique de charge et d'E/S |
|
|
| `needrestart` | Signale après chaque `apt` les services à redémarrer |
|
|
| `dnsutils` | `dig`, `nslookup` pour déboguer la résolution |
|
|
| `lsof` / `tcpdump` | Qui tient un fichier, que passe-t-il sur le réseau |
|
|
|
|
### Activer vnstat
|
|
|
|
```bash
|
|
sudo systemctl enable --now vnstat
|
|
vnstat --iflist # vérifie l'interface détectée
|
|
```
|
|
|
|
Il faut attendre quelques heures avant que `vnstat -d` affiche des données utiles : le compteur démarre à zéro.
|
|
|
|
### Ce que vous ne voulez probablement pas
|
|
|
|
Sur un serveur, allez au plus maigre. Chaque paquet installé est une surface d'attaque et une mise à jour de plus. Évitez les méta-paquets `task-*`, les environnements de bureau, et tout serveur (`apache2`, `nginx`, `mariadb`) tant que vous n'êtes pas à l'étape de déploiement des services.
|
|
|
|
```bash
|
|
sudo apt-mark showmanual | head -50 # ce qui a été installé explicitement
|
|
```
|
|
|
|
## Étape 6 — Locale, fuseau horaire et clavier
|
|
|
|
### 6.1 Locale
|
|
|
|
Attention à l'orthographe : c'est `fr_FR.UTF-8` avec un **tiret**, pas `fr_FR.UTF_8`. Un underscore produit une locale invalide, silencieusement ignorée.
|
|
|
|
Générez d'abord la locale, puis déclarez-la comme défaut système :
|
|
|
|
```bash
|
|
sudo sed -i 's/^# *\(fr_FR.UTF-8\)/\1/' /etc/locale.gen
|
|
sudo locale-gen
|
|
sudo localectl set-locale LANG=fr_FR.UTF-8
|
|
```
|
|
|
|
Variante non interactive, adaptée à un script :
|
|
|
|
```bash
|
|
echo "locales locales/locales_to_be_generated multiselect fr_FR.UTF-8 UTF-8, en_US.UTF-8 UTF-8" | sudo debconf-set-selections
|
|
echo "locales locales/default_environment_locale select fr_FR.UTF-8" | sudo debconf-set-selections
|
|
sudo rm -f /etc/locale.gen
|
|
sudo dpkg-reconfigure --frontend=noninteractive locales
|
|
```
|
|
|
|
> `LANG=fr_FR.UTF-8` seul dans un terminal ne change que la session en cours. `localectl` écrit dans `/etc/default/locale`, lu par tous les services et toutes les futures connexions.
|
|
|
|
**Recommandation** : gardez les **messages en anglais** même avec une interface en français. Les messages d'erreur anglais sont cherchables et correspondent à la documentation ; les scripts qui parsent une sortie de commande cassent en français.
|
|
|
|
```bash
|
|
sudo localectl set-locale LANG=fr_FR.UTF-8 LC_MESSAGES=C.UTF-8
|
|
```
|
|
|
|
Reconnectez-vous, puis vérifiez :
|
|
|
|
```bash
|
|
locale # aucune ligne "Cannot set LC_*"
|
|
localectl status
|
|
```
|
|
|
|
### 6.2 Fuseau horaire
|
|
|
|
```bash
|
|
sudo timedatectl set-timezone Europe/Paris
|
|
timedatectl list-timezones | grep Paris # pour trouver un autre fuseau
|
|
```
|
|
|
|
> Sur un parc international ou pour simplifier la lecture des journaux entre machines, `UTC` reste un choix défendable. Le seul vrai critère : que toutes vos machines aient **le même** fuseau.
|
|
|
|
### 6.3 Synchronisation de l'heure
|
|
|
|
Debian 13 utilise `systemd-timesyncd` par défaut. Une heure décalée casse TLS, les tokens et la corrélation des journaux.
|
|
|
|
```bash
|
|
sudo timedatectl set-ntp true
|
|
timedatectl status
|
|
```
|
|
|
|
Attendu : `System clock synchronized: yes` et `NTP service: active`.
|
|
|
|
Pour utiliser les serveurs français :
|
|
|
|
```bash
|
|
sudo mkdir -p /etc/systemd/timesyncd.conf.d
|
|
printf '[Time]\nNTP=0.fr.pool.ntp.org 1.fr.pool.ntp.org\nFallbackNTP=2.fr.pool.ntp.org 3.fr.pool.ntp.org\n' \
|
|
| sudo tee /etc/systemd/timesyncd.conf.d/pool-fr.conf
|
|
sudo systemctl restart systemd-timesyncd
|
|
timedatectl timesync-status
|
|
```
|
|
|
|
### 6.4 Clavier (console uniquement)
|
|
|
|
Utile seulement si vous passez par la console KVM de l'hébergeur ; sans effet sur SSH.
|
|
|
|
```bash
|
|
sudo localectl set-keymap fr
|
|
sudo localectl set-x11-keymap fr
|
|
```
|
|
|
|
## Étape 7 — Compte administrateur et sudo
|
|
|
|
### 7.1 Créer l'utilisateur
|
|
|
|
```bash
|
|
sudo adduser alix
|
|
```
|
|
|
|
Choisissez un mot de passe long et unique. Les champs « Nom complet », « N° de bureau », etc. peuvent rester vides : validez avec Entrée.
|
|
|
|
### 7.2 Accorder les droits sudo
|
|
|
|
Sous Debian, l'appartenance au groupe `sudo` suffit. Nul besoin d'éditer les sudoers pour un administrateur standard.
|
|
|
|
```bash
|
|
sudo usermod -aG sudo alix
|
|
id alix # vérifie que "sudo" apparaît dans les groupes
|
|
```
|
|
|
|
> Le `-a` de `usermod -aG` est obligatoire : sans lui, l'utilisateur est **retiré de tous ses autres groupes**. C'est une erreur classique et difficile à diagnostiquer.
|
|
|
|
Si vous avez besoin d'une règle spécifique — par exemple autoriser un redémarrage de service sans mot de passe — n'éditez **jamais** `/etc/sudoers` directement. Créez un fichier dédié dans `/etc/sudoers.d/`, ce qui isole la panne en cas d'erreur de syntaxe :
|
|
|
|
```bash
|
|
sudo visudo -f /etc/sudoers.d/10-alix
|
|
```
|
|
|
|
```
|
|
# Redémarrage de nginx sans mot de passe
|
|
alix ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx
|
|
```
|
|
|
|
```bash
|
|
sudo chmod 0440 /etc/sudoers.d/10-alix
|
|
sudo visudo -c # contrôle global de la syntaxe
|
|
```
|
|
|
|
> ⚠️ `visudo` valide la syntaxe avant d'écrire, ce que `nano /etc/sudoers` ne fait pas. Une erreur dans les sudoers non validée rend `sudo` inutilisable pour tout le monde, y compris vous.
|
|
>
|
|
> Évitez `NOPASSWD: ALL` : cela transforme toute exécution de code sous votre compte en accès root immédiat.
|
|
|
|
### 7.3 Tester avant de couper quoi que ce soit
|
|
|
|
Depuis **une nouvelle session** (en gardant l'ancienne ouverte) :
|
|
|
|
```bash
|
|
ssh alix@203.0.113.10
|
|
sudo -v # doit demander VOTRE mot de passe et rendre la main
|
|
sudo whoami # → root
|
|
```
|
|
|
|
Tant que ces trois commandes ne fonctionnent pas, n'allez pas plus loin : les étapes suivantes retirent votre accès actuel.
|
|
|
|
### 7.4 Confort de connexion (optionnel)
|
|
|
|
```bash
|
|
# Depuis votre poste : alias de connexion
|
|
cat >> ~/.ssh/config <<'EOF'
|
|
Host web01
|
|
HostName web01.exemple.fr
|
|
User alix
|
|
Port 22
|
|
IdentityFile ~/.ssh/id_ed25519
|
|
EOF
|
|
```
|
|
|
|
Vous vous connecterez ensuite avec `ssh web01`. Adaptez `Port` après l'étape 8 si vous le déplacez.
|
|
|
|
## Étape 8 — Clés SSH et durcissement
|
|
|
|
C'est l'étape la plus risquée. Gardez une session ouverte du début à la fin.
|
|
|
|
### 8.1 Créer une paire de clés (sur votre poste, pas sur le serveur)
|
|
|
|
```bash
|
|
ssh-keygen -t ed25519 -C "alix@poste-bureau" -f ~/.ssh/id_ed25519
|
|
```
|
|
|
|
Ed25519 est le bon choix par défaut : court, rapide, sûr. Mettez une passphrase — elle protège la clé si votre poste est compromis, et `ssh-agent` évite de la retaper.
|
|
|
|
### 8.2 Déposer la clé publique
|
|
|
|
```bash
|
|
ssh-copy-id -i ~/.ssh/id_ed25519.pub alix@203.0.113.10
|
|
```
|
|
|
|
En manuel si `ssh-copy-id` n'est pas disponible :
|
|
|
|
```bash
|
|
ssh alix@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
|
|
cat ~/.ssh/id_ed25519.pub | ssh alix@203.0.113.10 "cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
|
|
```
|
|
|
|
Testez dans une **nouvelle** session : `ssh alix@203.0.113.10` doit passer sans demander le mot de passe du compte.
|
|
|
|
### 8.3 Configurer sshd par fichier drop-in
|
|
|
|
Debian 13 lit `/etc/ssh/sshd_config.d/*.conf`. Écrivez votre configuration là plutôt que dans `sshd_config` : vos choix survivent aux mises à jour du paquet et se retirent en supprimant un seul fichier.
|
|
|
|
```bash
|
|
sudo nano /etc/ssh/sshd_config.d/99-durcissement.conf
|
|
```
|
|
|
|
```
|
|
# Authentification
|
|
PermitRootLogin no
|
|
PasswordAuthentication no
|
|
KbdInteractiveAuthentication no
|
|
PubkeyAuthentication yes
|
|
AuthenticationMethods publickey
|
|
MaxAuthTries 3
|
|
MaxSessions 5
|
|
LoginGraceTime 30
|
|
|
|
# Limiter qui peut se connecter
|
|
AllowUsers alix
|
|
|
|
# Réduire la surface
|
|
X11Forwarding no
|
|
AllowAgentForwarding no
|
|
AllowTcpForwarding no
|
|
PermitTunnel no
|
|
PermitUserEnvironment no
|
|
|
|
# Sessions mortes
|
|
ClientAliveInterval 300
|
|
ClientAliveCountMax 2
|
|
```
|
|
|
|
> `AllowUsers alix` remplace avantageusement un `DenyUsers debian` : la liste blanche est explicite et couvre aussi les comptes que vous n'avez pas anticipés. Pensez à l'étendre si vous ajoutez un administrateur.
|
|
|
|
> `PasswordAuthentication no` vous verrouille dehors si la clé de 8.2 ne fonctionne pas. Ne l'activez qu'après avoir vérifié la connexion par clé.
|
|
|
|
Deux précautions : le premier fichier qui définit une directive gagne, et `sshd_config` charge souvent ses drop-ins **en première ligne**. Vérifiez donc la configuration réellement appliquée, jamais le fichier seul.
|
|
|
|
```bash
|
|
sudo sshd -t # syntaxe ; silence = OK
|
|
sudo sshd -T | grep -Ei 'permitrootlogin|passwordauth|allowusers|^port'
|
|
```
|
|
|
|
Puis rechargez et testez depuis une nouvelle session :
|
|
|
|
```bash
|
|
sudo systemctl reload ssh
|
|
```
|
|
|
|
### 8.4 Changer le port : la spécificité Debian 13
|
|
|
|
Depuis Debian 12, SSH est démarré par **activation à la demande via systemd** (`ssh.socket`). Conséquence : une directive `Port` dans `sshd_config` **peut rester sans effet**, car c'est le socket systemd qui décide de l'écoute.
|
|
|
|
D'abord, constatez votre situation :
|
|
|
|
```bash
|
|
systemctl is-active ssh.socket # active → c'est le socket qui commande
|
|
systemctl is-active ssh.service
|
|
ss -tlpn | grep -E 'ssh|:22'
|
|
```
|
|
|
|
**Si `ssh.socket` est actif**, modifiez le socket :
|
|
|
|
```bash
|
|
sudo systemctl edit ssh.socket
|
|
```
|
|
|
|
```
|
|
[Socket]
|
|
ListenStream=
|
|
ListenStream=0.0.0.0:2222
|
|
ListenStream=[::]:2222
|
|
```
|
|
|
|
La ligne `ListenStream=` vide est indispensable : elle efface le port 22 hérité. Sans elle, vous ajoutez 2222 sans retirer 22.
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl restart ssh.socket
|
|
ss -tlpn | grep 2222
|
|
```
|
|
|
|
**Alternative** — revenir au modèle classique, où `sshd_config` reprend la main :
|
|
|
|
```bash
|
|
sudo systemctl disable --now ssh.socket
|
|
sudo systemctl enable --now ssh.service
|
|
```
|
|
|
|
### 8.5 Faut-il vraiment changer de port ?
|
|
|
|
Ce n'est pas une mesure de sécurité, seulement de réduction du bruit : elle élimine les scans automatisés des journaux, pas un attaquant ciblé qui scannera vos 65 535 ports. Avec `PasswordAuthentication no` et fail2ban, le port 22 est déjà très défendable. Un port non standard complique en revanche le pare-feu, les sondes de supervision et les collaborateurs.
|
|
|
|
### 8.6 Vérification finale
|
|
|
|
Ouvrez une session neuve, sans fermer l'ancienne :
|
|
|
|
```bash
|
|
ssh -p 2222 alix@web01.exemple.fr
|
|
ssh -p 2222 debian@web01.exemple.fr # doit être refusé
|
|
ssh -p 2222 root@web01.exemple.fr # doit être refusé
|
|
```
|
|
|
|
## Étape 9 — Neutraliser le compte fournisseur
|
|
|
|
Le compte `debian` livré par l'hébergeur est connu de tous et ciblé en premier par les scans. Une fois votre accès personnel prouvé, retirez-lui l'accès SSH.
|
|
|
|
### 9.1 Choisir le niveau de neutralisation
|
|
|
|
| Niveau | Commande | Effet | Quand |
|
|
| --- | --- | --- | --- |
|
|
| SSH bloqué | `AllowUsers alix` (étape 8.3) | Le compte existe, ne peut plus se connecter par SSH | Cas général |
|
|
| Mot de passe verrouillé | `sudo passwd -l debian` | Plus d'authentification par mot de passe | À combiner avec le précédent |
|
|
| Shell retiré | `sudo usermod -s /usr/sbin/nologin debian` | Plus aucune session interactive | Compte purement technique |
|
|
| Compte supprimé | `sudo deluser --remove-home debian` | Disparu | Seulement si rien ne dépend de lui |
|
|
|
|
La combinaison recommandée est la plus conservatrice :
|
|
|
|
```bash
|
|
sudo passwd -l debian
|
|
sudo usermod -s /usr/sbin/nologin debian
|
|
sudo rm -f /home/debian/.ssh/authorized_keys
|
|
```
|
|
|
|
> ⚠️ Ne supprimez pas le compte avant d'avoir vérifié qu'aucun processus ne tourne sous son identité (`ps -u debian`) et qu'il n'est pas utilisé par l'outillage de l'hébergeur (agent de sauvegarde, `cloud-init`, console de secours). Certains hébergeurs recréent le compte à chaque redémarrage.
|
|
|
|
### 9.2 Le cas de root
|
|
|
|
```bash
|
|
sudo passwd -l root # verrouille le mot de passe root
|
|
sudo rm -f /root/.ssh/authorized_keys
|
|
```
|
|
|
|
Sur Debian, root n'a généralement pas de mot de passe utilisable en SSH dès lors que `PermitRootLogin no` est posé. Le verrouillage est une ceinture en plus des bretelles.
|
|
|
|
> N'utilisez pas `usermod -s /usr/sbin/nologin root` : vous perdriez l'accès par la console de secours de l'hébergeur, votre dernier recours.
|
|
|
|
### 9.3 Inventaire des comptes
|
|
|
|
```bash
|
|
# Comptes capables de se connecter
|
|
awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $7}' /etc/passwd
|
|
|
|
# Membres du groupe sudo
|
|
getent group sudo
|
|
|
|
# Comptes sans mot de passe (doit être vide)
|
|
sudo awk -F: '$2 == "" {print $1}' /etc/shadow
|
|
|
|
# Clés SSH autorisées sur toute la machine
|
|
sudo find /home /root -name authorized_keys -exec ls -l {} \; -exec cat {} \;
|
|
```
|
|
|
|
La dernière commande mérite un passage attentif : une clé publique inconnue dans un `authorized_keys` est une porte dérobée.
|
|
|
|
## Étape 10 — Pare-feu
|
|
|
|
Debian 13 utilise **nftables** comme moteur de filtrage. Deux approches : `nftables` directement, ou `ufw` qui l'utilise en coulisse avec une syntaxe plus simple.
|
|
|
|
### 10.1 Option A — ufw (recommandé si vous débutez)
|
|
|
|
```bash
|
|
sudo apt install -y ufw
|
|
|
|
# Politique par défaut : tout entrant bloqué, tout sortant autorisé
|
|
sudo ufw default deny incoming
|
|
sudo ufw default allow outgoing
|
|
|
|
# SSH EN PREMIER — sinon vous vous coupez l'accès à l'activation
|
|
sudo ufw limit 2222/tcp comment 'SSH'
|
|
|
|
# Services web, à n'ouvrir que le jour où vous les déployez
|
|
# sudo ufw allow 80/tcp comment 'HTTP'
|
|
# sudo ufw allow 443/tcp comment 'HTTPS'
|
|
|
|
sudo ufw enable
|
|
sudo ufw status verbose
|
|
```
|
|
|
|
`limit` plutôt que `allow` pour SSH : ufw bloque une IP qui dépasse six tentatives de connexion en 30 secondes. C'est une première barrière avant fail2ban.
|
|
|
|
### 10.2 Option B — nftables directement
|
|
|
|
Plus verbeux, mais sans couche intermédiaire et lisible d'un seul coup d'œil.
|
|
|
|
```bash
|
|
sudo nano /etc/nftables.conf
|
|
```
|
|
|
|
```
|
|
#!/usr/sbin/nft -f
|
|
flush ruleset
|
|
|
|
table inet filter {
|
|
chain input {
|
|
type filter hook input priority filter; policy drop;
|
|
|
|
ct state established,related accept
|
|
ct state invalid drop
|
|
iif lo accept
|
|
|
|
ip protocol icmp accept
|
|
ip6 nexthdr icmpv6 accept
|
|
|
|
tcp dport 2222 ct state new limit rate 6/minute accept
|
|
# tcp dport { 80, 443 } accept
|
|
|
|
counter
|
|
}
|
|
|
|
chain forward {
|
|
type filter hook forward priority filter; policy drop;
|
|
}
|
|
|
|
chain output {
|
|
type filter hook output priority filter; policy accept;
|
|
}
|
|
}
|
|
```
|
|
|
|
```bash
|
|
sudo nft -c -f /etc/nftables.conf # vérifie la syntaxe sans appliquer
|
|
sudo systemctl enable --now nftables
|
|
sudo nft list ruleset
|
|
```
|
|
|
|
> ⚠️ Ne laissez jamais `policy drop` sur `input` sans règle SSH au-dessus. Testez toujours avec `nft -c -f` avant d'appliquer.
|
|
|
|
### 10.3 Filet de sécurité pendant les tests
|
|
|
|
Programmez une désactivation automatique du pare-feu dans 10 minutes. Si vous vous verrouillez dehors, l'accès revient seul ; si tout va bien, vous annulez la tâche.
|
|
|
|
```bash
|
|
# Avant d'activer les règles
|
|
sudo systemd-run --on-active=10min --unit=ufw-panic systemctl stop ufw
|
|
|
|
# Une fois la connexion reconfirmée depuis une nouvelle session
|
|
sudo systemctl stop ufw-panic.timer
|
|
```
|
|
|
|
### 10.4 Le pare-feu de l'hébergeur
|
|
|
|
Beaucoup d'hébergeurs interposent leur propre filtrage en amont (*security group*, « firewall network »). Un port ouvert sur la machine et fermé chez eux reste inaccessible — et l'inverse est vrai. Tenez les deux couches alignées, et documentez-les ensemble.
|
|
|
|
```bash
|
|
# Depuis un autre poste : ce qui est réellement joignable
|
|
nmap -Pn -p- web01.exemple.fr
|
|
```
|
|
|
|
## Étape 11 — fail2ban
|
|
|
|
fail2ban lit les journaux et bannit temporairement les IP qui échouent trop souvent. Avec `PasswordAuthentication no`, son utilité sur SSH est surtout de nettoyer les journaux ; elle redevient essentielle dès que vous exposez un service authentifié par mot de passe.
|
|
|
|
```bash
|
|
sudo apt install -y fail2ban
|
|
```
|
|
|
|
### Configuration
|
|
|
|
Ne modifiez jamais `jail.conf` : il est écrasé aux mises à jour. Créez `jail.local`.
|
|
|
|
```bash
|
|
sudo nano /etc/fail2ban/jail.local
|
|
```
|
|
|
|
```ini
|
|
[DEFAULT]
|
|
bantime = 1h
|
|
findtime = 10m
|
|
maxretry = 4
|
|
backend = systemd
|
|
banaction = nftables-multiport
|
|
# Ne bannissez jamais votre propre IP fixe
|
|
ignoreip = 127.0.0.1/8 ::1 198.51.100.7
|
|
|
|
[sshd]
|
|
enabled = true
|
|
port = 2222
|
|
mode = aggressive
|
|
```
|
|
|
|
`backend = systemd` est important sous Debian 13 : les journaux passent par `journald`, pas par un fichier `/var/log/auth.log` garanti. `banaction = nftables-multiport` évite un conflit avec le moteur nftables du système.
|
|
|
|
> Si vous avez choisi ufw à l'étape 10, utilisez plutôt `banaction = ufw`.
|
|
|
|
```bash
|
|
sudo systemctl enable --now fail2ban
|
|
sudo systemctl restart fail2ban
|
|
```
|
|
|
|
### Exploitation au quotidien
|
|
|
|
```bash
|
|
sudo fail2ban-client status # prisons actives
|
|
sudo fail2ban-client status sshd # IP bannies
|
|
sudo fail2ban-client set sshd unbanip 198.51.100.7 # débannir
|
|
sudo fail2ban-client set sshd banip 203.0.113.99 # bannir à la main
|
|
```
|
|
|
|
> ⚠️ Mettez votre IP fixe dans `ignoreip` **avant** de démarrer le service. Sinon, une passphrase mal tapée quatre fois vous bannit une heure de votre propre serveur.
|
|
|
|
## Étape 12 — Mises à jour de sécurité automatiques
|
|
|
|
Un serveur non mis à jour devient vulnérable en quelques semaines. `unattended-upgrades` applique les correctifs de sécurité sans intervention.
|
|
|
|
```bash
|
|
sudo apt install -y unattended-upgrades apt-listchanges
|
|
sudo dpkg-reconfigure -plow unattended-upgrades
|
|
```
|
|
|
|
### Configuration
|
|
|
|
```bash
|
|
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
|
|
```
|
|
|
|
Lignes à vérifier ou décommenter :
|
|
|
|
```
|
|
Unattended-Upgrade::Origins-Pattern {
|
|
"origin=Debian,codename=${distro_codename},label=Debian-Security";
|
|
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
|
|
};
|
|
|
|
Unattended-Upgrade::Mail "alix@exemple.fr";
|
|
Unattended-Upgrade::MailReport "on-change";
|
|
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
|
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
|
Unattended-Upgrade::Automatic-Reboot "false";
|
|
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
|
|
```
|
|
|
|
Le choix structurant est `Automatic-Reboot` :
|
|
|
|
| Valeur | Conséquence |
|
|
| --- | --- |
|
|
| `"false"` | Les correctifs noyau attendent un redémarrage manuel. Le serveur reste vulnérable en attendant, mais ne tombe jamais seul. |
|
|
| `"true"` | Redémarrage automatique à 04:00 si nécessaire. Correctifs réellement actifs, au prix d'une coupure imprévisible. |
|
|
|
|
Pour un serveur de production isolé, `"true"` avec une heure creuse est souvent le meilleur compromis. Pour un serveur critique sans redondance, gardez `"false"` et redémarrez lors d'une fenêtre planifiée.
|
|
|
|
### Vérifier que ça tourne
|
|
|
|
```bash
|
|
sudo unattended-upgrade --dry-run --debug # simulation détaillée
|
|
systemctl list-timers | grep -E 'apt|unattended'
|
|
cat /var/log/unattended-upgrades/unattended-upgrades.log
|
|
```
|
|
|
|
Deux minuteries doivent apparaître : `apt-daily.timer` (rafraîchissement des index) et `apt-daily-upgrade.timer` (installation).
|
|
|
|
### Savoir quand redémarrer
|
|
|
|
```bash
|
|
cat /var/run/reboot-required.pkgs 2>/dev/null # paquets concernés
|
|
sudo needrestart -b # services à relancer
|
|
```
|
|
|
|
Pensez à intégrer cette vérification à votre routine hebdomadaire.
|
|
|
|
## Étape 13 — Swap, /tmp et paramètres noyau
|
|
|
|
### 13.1 Swap
|
|
|
|
Beaucoup de VPS sont livrés sans swap. Un peu de swap évite qu'un pic de mémoire déclenche le tueur de processus du noyau (OOM killer).
|
|
|
|
```bash
|
|
free -h # vérifier ce qui existe déjà
|
|
swapon --show
|
|
```
|
|
|
|
Si la ligne Swap est à zéro :
|
|
|
|
```bash
|
|
sudo fallocate -l 2G /swapfile
|
|
sudo chmod 600 /swapfile
|
|
sudo mkswap /swapfile
|
|
sudo swapon /swapfile
|
|
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
|
|
```
|
|
|
|
Dimensionnement raisonnable : 2 Go jusqu'à 4 Go de RAM, puis 4 Go au-delà. Inutile d'aller au-delà sur un serveur : si vous swappez beaucoup, il faut de la RAM, pas du disque.
|
|
|
|
```bash
|
|
# Réduire l'agressivité du swap sur un serveur
|
|
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf
|
|
```
|
|
|
|
> Sur SSD NVMe, le swap est peu coûteux. Sur un disque réseau facturé aux IOPS, il peut coûter cher et ralentir fortement.
|
|
|
|
### 13.2 /tmp est désormais en RAM
|
|
|
|
Changement notable de Debian 13 : `/tmp` est monté en **tmpfs**, donc en mémoire, et vidé à chaque redémarrage ([note de version](https://www.debian.org/releases/trixie/release-notes/issues.en.html)).
|
|
|
|
```bash
|
|
df -h /tmp
|
|
findmnt /tmp
|
|
```
|
|
|
|
Deux conséquences à connaître :
|
|
|
|
1. Écrire un gros fichier dans `/tmp` consomme de la RAM. Les traitements volumineux doivent utiliser `/var/tmp`, qui reste sur disque.
|
|
2. Sur une machine migrée depuis Debian 12, les anciens fichiers de `/tmp` sont toujours sur le disque, masqués par le montage. Ils occupent de l'espace invisible.
|
|
|
|
```bash
|
|
# Retrouver et nettoyer l'ancien /tmp masqué
|
|
sudo mkdir -p /mnt/racine
|
|
sudo mount --bind / /mnt/racine
|
|
ls -lha /mnt/racine/tmp/
|
|
# ... supprimez ce qui doit l'être ...
|
|
sudo umount /mnt/racine && sudo rmdir /mnt/racine
|
|
```
|
|
|
|
Pour repasser `/tmp` sur disque si votre usage le demande :
|
|
|
|
```bash
|
|
sudo systemctl mask tmp.mount
|
|
sudo reboot
|
|
```
|
|
|
|
### 13.3 Paramètres réseau et noyau
|
|
|
|
```bash
|
|
sudo nano /etc/sysctl.d/99-durcissement.conf
|
|
```
|
|
|
|
```
|
|
# Anti-usurpation d'adresse
|
|
net.ipv4.conf.all.rp_filter = 1
|
|
net.ipv4.conf.default.rp_filter = 1
|
|
|
|
# Ignorer le routage par la source et les redirections ICMP
|
|
net.ipv4.conf.all.accept_source_route = 0
|
|
net.ipv6.conf.all.accept_source_route = 0
|
|
net.ipv4.conf.all.accept_redirects = 0
|
|
net.ipv6.conf.all.accept_redirects = 0
|
|
net.ipv4.conf.all.send_redirects = 0
|
|
|
|
# Journaliser les paquets manifestement usurpés
|
|
net.ipv4.conf.all.log_martians = 1
|
|
|
|
# Résistance aux SYN flood
|
|
net.ipv4.tcp_syncookies = 1
|
|
|
|
# Limiter la lecture des informations noyau
|
|
kernel.dmesg_restrict = 1
|
|
kernel.kptr_restrict = 2
|
|
|
|
# Protection des liens en répertoires partagés
|
|
fs.protected_hardlinks = 1
|
|
fs.protected_symlinks = 1
|
|
```
|
|
|
|
```bash
|
|
sudo sysctl --system
|
|
sudo sysctl -a --pattern 'tcp_syncookies|rp_filter' # contrôle
|
|
```
|
|
|
|
> N'appliquez pas `net.ipv4.ip_forward = 0` sans réfléchir : Docker, les conteneurs et les VPN en ont besoin.
|
|
|
|
## Étape 14 — Journaux, supervision et alertes
|
|
|
|
### 14.1 Plafonner les journaux
|
|
|
|
Par défaut, `journald` peut occuper jusqu'à 10 % du système de fichiers. Sur un petit VPS, c'est une cause classique de disque plein.
|
|
|
|
```bash
|
|
sudo nano /etc/systemd/journald.conf.d/00-limites.conf
|
|
```
|
|
|
|
```
|
|
[Journal]
|
|
Storage=persistent
|
|
SystemMaxUse=500M
|
|
SystemMaxFileSize=50M
|
|
MaxRetentionSec=1month
|
|
```
|
|
|
|
```bash
|
|
sudo mkdir -p /etc/systemd/journald.conf.d
|
|
sudo systemctl restart systemd-journald
|
|
journalctl --disk-usage
|
|
```
|
|
|
|
### 14.2 Commandes de lecture utiles
|
|
|
|
```bash
|
|
journalctl -p err -b # erreurs depuis le démarrage
|
|
journalctl -u ssh --since "1 hour ago" # un service, une fenêtre de temps
|
|
journalctl -f # en direct
|
|
journalctl --since yesterday | grep -i "failed password"
|
|
last -20 # dernières connexions réussies
|
|
lastb -20 # dernières tentatives échouées
|
|
```
|
|
|
|
### 14.3 Recevoir les alertes par mail
|
|
|
|
Sans MTA, les rapports de `unattended-upgrades`, `cron` et `fail2ban` sont écrits mais jamais lus. Un relais léger suffit — n'installez pas un serveur de mail complet.
|
|
|
|
```bash
|
|
sudo apt install -y msmtp-mta bsd-mailx
|
|
sudo nano /etc/msmtprc
|
|
```
|
|
|
|
```
|
|
defaults
|
|
auth on
|
|
tls on
|
|
tls_trust_file /etc/ssl/certs/ca-certificates.crt
|
|
logfile /var/log/msmtp.log
|
|
|
|
account default
|
|
host smtp.exemple.fr
|
|
port 587
|
|
from web01@exemple.fr
|
|
user web01@exemple.fr
|
|
password VOTRE_MOT_DE_PASSE
|
|
```
|
|
|
|
```bash
|
|
sudo chmod 600 /etc/msmtprc
|
|
echo "Test depuis web01" | mail -s "Test alerte" alix@exemple.fr
|
|
```
|
|
|
|
> Le fichier contient un mot de passe en clair : `chmod 600` est obligatoire. Préférez un mot de passe d'application dédié, révocable, plutôt que votre mot de passe principal.
|
|
|
|
Redirigez ensuite le courrier de root vers vous :
|
|
|
|
```bash
|
|
echo "root: alix@exemple.fr" | sudo tee -a /etc/aliases
|
|
sudo newaliases 2>/dev/null || true
|
|
```
|
|
|
|
### 14.4 Surveiller l'essentiel
|
|
|
|
```bash
|
|
# Trafic réseau
|
|
vnstat -d # par jour
|
|
vnstat -m # par mois, utile face à un quota
|
|
|
|
# Disque
|
|
df -h
|
|
sudo ncdu / # exploration interactive
|
|
|
|
# Charge et E/S
|
|
uptime
|
|
iostat -x 2 5
|
|
sar -u 1 5
|
|
```
|
|
|
|
Une alerte simple sur le disque, via cron, vaut mieux qu'une supervision compliquée jamais installée :
|
|
|
|
```bash
|
|
sudo tee /etc/cron.daily/alerte-disque >/dev/null <<'EOF'
|
|
#!/bin/sh
|
|
SEUIL=85
|
|
USAGE=$(df / --output=pcent | tail -1 | tr -dc '0-9')
|
|
[ "$USAGE" -ge "$SEUIL" ] && echo "Disque / à ${USAGE}% sur $(hostname -f)" \
|
|
| mail -s "ALERTE disque $(hostname)" root
|
|
exit 0
|
|
EOF
|
|
sudo chmod +x /etc/cron.daily/alerte-disque
|
|
```
|
|
|
|
## Étape 15 — Sauvegarde et instantané de référence
|
|
|
|
### 15.1 Instantané immédiat
|
|
|
|
Vous venez de construire une base propre. Prenez-en un instantané (*snapshot*) chez votre hébergeur **maintenant**, avant de déployer le moindre service. C'est votre point de retour : une mauvaise manipulation plus tard se résoudra en trois minutes au lieu d'une réinstallation complète.
|
|
|
|
### 15.2 Archiver la configuration
|
|
|
|
```bash
|
|
sudo tar czf /root/config-initiale-$(date +%F).tar.gz \
|
|
/etc/ssh/sshd_config.d /etc/hosts /etc/hostname \
|
|
/etc/apt/sources.list.d /etc/sudoers.d \
|
|
/etc/fail2ban/jail.local /etc/nftables.conf \
|
|
/etc/sysctl.d /etc/default/locale 2>/dev/null
|
|
```
|
|
|
|
Récupérez l'archive sur votre poste :
|
|
|
|
```bash
|
|
scp -P 2222 alix@web01.exemple.fr:/root/config-initiale-*.tar.gz ./
|
|
```
|
|
|
|
> Mieux encore : versionnez ces fichiers dans un dépôt Git privé — sans les secrets. `git` est déjà installé à l'étape 5.
|
|
|
|
### 15.3 Mettre en place une vraie sauvegarde
|
|
|
|
Une sauvegarde qu'on n'a jamais restaurée n'est pas une sauvegarde. Principe des 3-2-1 : trois copies, deux supports, une hors site.
|
|
|
|
```bash
|
|
sudo apt install -y restic
|
|
```
|
|
|
|
```bash
|
|
# Initialisation vers un stockage distant (une seule fois)
|
|
export RESTIC_REPOSITORY="sftp:sauvegarde@stockage.exemple.fr:/backups/web01"
|
|
export RESTIC_PASSWORD_FILE="/root/.restic-pass"
|
|
sudo restic init
|
|
|
|
# Sauvegarde
|
|
sudo restic backup /etc /home /var/www --exclude-caches
|
|
|
|
# Vérification et purge
|
|
sudo restic snapshots
|
|
sudo restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
|
|
```
|
|
|
|
Automatisez avec une minuterie systemd plutôt qu'un cron : les échecs remontent dans `journalctl`.
|
|
|
|
```bash
|
|
sudo systemd-run --on-calendar="*-*-* 03:00:00" --unit=sauvegarde \
|
|
/usr/bin/restic backup /etc /home /var/www
|
|
```
|
|
|
|
### 15.4 Tester la restauration
|
|
|
|
À faire une fois, tout de suite, puis tous les trimestres :
|
|
|
|
```bash
|
|
sudo restic restore latest --target /tmp/test-restauration --include /etc/hosts
|
|
cat /tmp/test-restauration/etc/hosts
|
|
```
|
|
|
|
Notez la date du dernier test réussi quelque part de visible. C'est la seule métrique qui compte vraiment.
|
|
|
|
## Checklist récapitulative
|
|
|
|
### Préparatifs
|
|
|
|
- [ ] Accès de secours hors SSH vérifié (console KVM, mode rescue)
|
|
- [ ] Enregistrement A (et AAAA) créé vers le FQDN
|
|
- [ ] Reverse DNS (PTR) aligné sur le FQDN, IPv4 et IPv6
|
|
- [ ] `dig` confirme la correspondance dans les deux sens
|
|
|
|
### Identité et système
|
|
|
|
- [ ] Première connexion réussie, état initial relevé (`ss -tulpn`)
|
|
- [ ] Nom d'hôte court défini avec `hostnamectl set-hostname`
|
|
- [ ] `/etc/hosts` corrigé : FQDN avant nom court sur la ligne `127.0.1.1`
|
|
- [ ] `hostname -f` renvoie bien le FQDN
|
|
- [ ] Sources APT converties en deb822, `trixie-security` présent
|
|
- [ ] `apt full-upgrade` passé, machine redémarrée si le noyau a changé
|
|
- [ ] `systemctl --failed` ne renvoie rien
|
|
- [ ] Paquets de base installés, `vnstat` activé
|
|
- [ ] Locale `fr_FR.UTF-8` générée et définie (avec un tiret)
|
|
- [ ] Fuseau horaire posé, `timedatectl` indique l'horloge synchronisée
|
|
|
|
### Accès
|
|
|
|
- [ ] Compte administrateur créé et ajouté au groupe `sudo` (avec `-aG`)
|
|
- [ ] `sudo -v` et `sudo whoami` fonctionnent depuis le nouveau compte
|
|
- [ ] Clé Ed25519 générée et déposée, connexion par clé vérifiée
|
|
- [ ] Drop-in `sshd_config.d` créé : root refusé, mot de passe désactivé, `AllowUsers` posé
|
|
- [ ] `sudo sshd -T` confirme la configuration réellement appliquée
|
|
- [ ] Port SSH vérifié côté `ssh.socket` si vous l'avez changé
|
|
- [ ] Compte fournisseur verrouillé, ses clés SSH retirées
|
|
- [ ] Aucune clé inconnue dans les `authorized_keys` de la machine
|
|
|
|
### Protection
|
|
|
|
- [ ] Pare-feu actif, SSH autorisé **avant** activation
|
|
- [ ] Ports ouverts alignés entre la machine et le pare-feu de l'hébergeur
|
|
- [ ] fail2ban actif, votre IP fixe dans `ignoreip`
|
|
- [ ] `unattended-upgrades` actif, politique de redémarrage décidée
|
|
- [ ] Paramètres sysctl appliqués (`sysctl --system`)
|
|
- [ ] Swap présent si la RAM est limitée
|
|
|
|
### Exploitation
|
|
|
|
- [ ] Journaux plafonnés (`journalctl --disk-usage`)
|
|
- [ ] Envoi de mail testé, courrier de root redirigé
|
|
- [ ] Sauvegarde configurée **et restauration testée une fois**
|
|
- [ ] Instantané de référence pris chez l'hébergeur
|
|
- [ ] Archive de configuration récupérée hors du serveur
|
|
- [ ] TTL DNS remonté à sa valeur normale
|
|
|
|
### Vérification finale d'un seul bloc
|
|
|
|
```bash
|
|
hostname -f; echo '---'
|
|
localectl status | head -3; echo '---'
|
|
timedatectl | grep -E 'Time zone|synchronized'; echo '---'
|
|
sudo sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|allowusers)'; echo '---'
|
|
sudo ufw status verbose 2>/dev/null || sudo nft list ruleset | head -20; echo '---'
|
|
sudo fail2ban-client status; echo '---'
|
|
systemctl --failed; echo '---'
|
|
free -h; df -h /
|
|
```
|
|
|
|
## Ce qui change par rapport à l'ancienne fiche Debian 11
|
|
|
|
L'ancienne fiche couvrait l'essentiel de la mise en route. Voici ce qui y était inexact ou
|
|
incomplet, et pourquoi c'est corrigé ici.
|
|
|
|
| Ancienne fiche | Correction | Pourquoi |
|
|
| --- | --- | --- |
|
|
| `LANG=fr_FR.UTF_8` | `fr_FR.UTF-8` | Tiret et non underscore ; sinon la locale est invalide. Et `LANG=` seul ne dure que le temps de la session : utilisez `localectl set-locale` |
|
|
| Ordre dans `/etc/hosts` « avant les noms déjà renseignés » | FQDN puis nom court, dans cet ordre | `hostname -f` prend le **premier** nom de la ligne. Inversé, il renvoie le nom court |
|
|
| `adduser nom` | `sudo adduser nom` | La création d'utilisateur demande les privilèges root |
|
|
| Droits supplémentaires via `visudo` | `usermod -aG sudo` d'abord ; `visudo -f /etc/sudoers.d/10-nom` si besoin spécifique | L'appartenance au groupe suffit dans 95 % des cas. Un fichier dédié isole une erreur de syntaxe au lieu de casser `sudo` pour tout le monde |
|
|
| `apt upgrade -y` | `apt full-upgrade -y` | `upgrade` refuse d'installer ou de retirer des paquets, donc bloque sur des transitions courantes d'une machine neuve |
|
|
| « Désactiver ssh pour l'utilisateur `debian` » | `AllowUsers` en liste blanche + verrouillage du compte | Une liste blanche couvre aussi les comptes non anticipés ; le verrouillage ferme les autres voies que SSH |
|
|
|
|
### Ce que l'ancienne fiche ne couvrait pas
|
|
|
|
1. **Les clés SSH avant la désactivation du mot de passe.** C'est la seule séquence qui ne pardonne pas l'inversion.
|
|
2. **Le pare-feu.** Sans lui, chaque service déployé est exposé par défaut.
|
|
3. **Les mises à jour automatiques.** Un serveur à jour le jour de l'installation ne l'est plus trois semaines après.
|
|
4. **La sauvegarde.** Y compris le test de restauration, qui est la partie qu'on saute toujours.
|
|
|
|
### Pièges spécifiques à Debian 13
|
|
|
|
| Piège | Symptôme | Solution |
|
|
| --- | --- | --- |
|
|
| SSH en activation par socket | `Port 2222` dans `sshd_config` ignoré, SSH reste sur 22 | `systemctl edit ssh.socket` avec un `ListenStream=` vide puis le nouveau port (étape 8.4) |
|
|
| `/tmp` en tmpfs | Espace disque « disparu » après migration ; gros fichiers qui saturent la RAM | Nettoyer l'ancien `/tmp` masqué, utiliser `/var/tmp` pour le volumineux (étape 13.2) |
|
|
| Sources au format deb822 | Un script qui écrit dans `/etc/apt/sources.list` semble sans effet | Écrire dans `/etc/apt/sources.list.d/*.sources` |
|
|
| `cloud-init` | Le nom d'hôte revient à sa valeur d'origine après redémarrage | `preserve_hostname: true` (étape 3.3) |
|
|
|
|
## Sources
|
|
|
|
- [Format deb822 sous Trixie — dev.to](https://dev.to/r3m8/debian-13-trixie-adoptez-le-nouveau-format-deb822-1ml6)
|
|
- [Migration vers deb822 — OSTechNix](https://ostechnix.com/migrate-to-deb822-format-debian-13-trixie/)
|
|
- [Changer le port SSH sous Debian 13 — IONOS](https://www.ionos.com/help/server-cloud-infrastructure/getting-started/important-security-information-for-your-server/changing-the-ssh-port/)
|
|
- [Notes de publication de Debian 13 — problèmes connus](https://www.debian.org/releases/trixie/release-notes/issues.en.html)
|