Aller au contenu principal
Dépannage 10 min de lecture

Réparer sshd cassé par une mise à jour automatique sur Ubuntu 24.04 (mars 2026)

Comment réparer openssh-server cassé après unattended-upgrades sur Ubuntu 24.04. Couvre le répertoire /run/sshd manquant, l'état half-configured de dpkg, ssh.socket en échec et un script de réparation automatisé complet.

Réparer sshd cassé par une mise à jour automatique sur Ubuntu 24.04 (mars 2026)

Le 16 mars 2026, une mise à jour défectueuse d'openssh-server (1:9.6p1-3ubuntu13.14 vers .15) a cassé SSH sur les serveurs Ubuntu 24.04 utilisant unattended-upgrades. La cause semble être un répertoire /run/sshd manquant qui a provoqué l'échec du script postinst, laissant dpkg à moitié configuré et ssh.socket dans un état d'échec. La solution consiste à recréer le répertoire, tuer le processus sshd orphelin, réinitialiser systemd et reconfigurer le paquet.

TL;DR - Correction rapide (à exécuter en tant que root)

mkdir -p /run/sshd && chmod 0755 /run/sshd
systemctl reset-failed ssh.socket ssh.service && systemctl start ssh.socket
dpkg --configure openssh-server

Si l'ancien processus sshd bloque le port, tuez-le d'abord : kill $(pgrep -f '/usr/sbin/sshd' | xargs -I{} sh -c 'ps -o ppid= -p {} | tr -d " "' | grep '^1$'). Lisez la suite pour le script automatisé complet.

Ce qui s'est passé

La mise à jour du paquet openssh-server de 1:9.6p1-3ubuntu13.14 vers 1:9.6p1-3ubuntu13.15 semble avoir été livrée avec un script de maintenance postinst défectueux. Lorsque unattended-upgrades s'est exécuté pendant la nuit et a tenté de configurer le nouveau paquet, le script a échoué. Cela a laissé dpkg dans un état à moitié configuré, le service ssh.socket de systemd dans un état d'échec, et l'ancien processus maître sshd orphelin -- toujours en cours d'exécution, mais plus géré par systemd.

Le serveur reste accessible tant que ce processus sshd orphelin continue de fonctionner. S'il s'arrête ou que le serveur redémarre, l'accès SSH est complètement perdu. Dans Laravel Forge, les serveurs affectés apparaissent comme "Déconnectés" car Forge ne peut plus les atteindre via SSH.

Comment nous l'avons diagnostiqué

Sur l'un de nos systèmes affectés, voici ce que nous avons trouvé lors de l'investigation.

dpkg: error processing package openssh-server

Vérification de l'état du paquet :

$ dpkg -s openssh-server | grep Status
Status: install ok half-configured

Cela confirme que le paquet est bloqué en cours de mise à jour. En examinant ce qu'unattended-upgrades a fait :

$ cat /var/log/unattended-upgrades/unattended-upgrades-dpkg.log
...
Setting up openssh-server (1:9.6p1-3ubuntu13.15) ...
dpkg: error processing package openssh-server (--configure):
 installed openssh-server package post-installation script subprocess returned error exit status 1

ssh.socket: Failed with result 'service-start-limit-hit'

Vérification de systemd :

$ systemctl status ssh.socket
Active: failed (Result: service-start-limit-hit)

$ journalctl -u ssh.socket
ssh.socket: Failed with result 'service-start-limit-hit'.
Failed to start ssh.socket - OpenBSD Secure Shell server socket.

$ journalctl -u ssh.service
ssh.service: Failed with result 'exit-code'.

L'activation par socket est complètement cassée. Mais nous pouvions toujours nous connecter en SSH, ce qui signifiait que quelque chose écoutait encore. Vérification du processus orphelin :

$ ps -eo pid,ppid,cmd | grep sshd
1234     1  sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups

PPID 1 -- c'est l'ancien processus maître sshd, orphelin après que systemd en a perdu la trace lors de la mise à jour échouée. Il accepte toujours les connexions, c'est pourquoi SSH fonctionne encore, mais il est en sursis.

fatal: Missing privilege separation directory: /run/sshd

Le fichier auth.log a révélé ce qui semble être la cause profonde :

$ grep sshd /var/log/auth.log
2026-03-18T18:20:19.201354+00:00 sshd[3115043]: fatal: Missing privilege separation directory: /run/sshd

Le répertoire d'exécution était bien manquant :

$ ls -la /run/sshd
ls: cannot access '/run/sshd': No such file or directory

Ce répertoire manquant semble être ce qui a provoqué l'échec du script postinst, car sshd en a besoin pour la séparation des privilèges.

Nous avons également trouvé un rapport de crash :

$ ls /var/crash/
openssh-server.0.crash

Les erreurs que vous verrez

Selon où vous regardez, vous pouvez rencontrer certaines ou toutes ces erreurs :

Dans la sortie dpkg / apt

dpkg: error processing package openssh-server (--configure):
 installed openssh-server package post-installation script subprocess returned error exit status 1
Errors were encountered while processing:
 openssh-server
E: Sub-process /usr/bin/dpkg returned an error code (1)

Lors de l'exécution de apt upgrade ou apt install

You might want to run 'apt --fix-broken install' to correct these.
The following packages have unmet dependencies:
 openssh-server : Depends: openssh-sftp-server but it is not going to be installed

État du paquet

Status: install ok half-configured

Erreurs systemd

ssh.socket: Failed with result 'service-start-limit-hit'.
ssh.service: Failed with result 'exit-code'.

Journal auth

sshd[3115043]: fatal: Missing privilege separation directory: /run/sshd

Comment corriger le problème

Nous avons écrit un script qui automatise l'intégralité de la correction. Il est sans danger à exécuter sur des serveurs NON affectés -- il détecte d'abord l'état cassé et se termine proprement si tout va bien. Cela permet de l'exécuter facilement sur tous vos serveurs sans se soucier de savoir lesquels sont réellement défaillants.

Le script :

  1. Lit votre port SSH depuis sshd_config (ne suppose pas le port 22)
  2. Détecte si le serveur est affecté (état dpkg cassé et/ou ssh.socket en échec)
  3. Crée /run/sshd s'il est manquant
  4. Trouve et tue le processus maître sshd orphelin
  5. Attend que le port se libère
  6. Réinitialise et démarre ssh.socket
  7. Exécute dpkg --configure pour corriger l'état du paquet
  8. Vérifie que tout fonctionne
  9. Supprime le fichier de crash

Voici le script complet :

#!/usr/bin/env bash
set -euo pipefail

# Fix broken openssh-server upgrade on Ubuntu 24.04
# Safe to run on unaffected servers -- exits cleanly.

if [[ $EUID -ne 0 ]]; then
    echo "ERROR: Must run as root." >&2
    exit 1
fi

echo "=== openssh-server upgrade fix ==="

# -- 0. Determine SSH port from sshd_config --
SSH_PORT=22
if [[ -f /etc/ssh/sshd_config ]]; then
    configured_port=$(grep -Ei '^\s*Port\s+' /etc/ssh/sshd_config | awk '{print $2}' | tail -1)
    if [[ -n "${configured_port:-}" ]]; then
        SSH_PORT="$configured_port"
    fi
fi
echo "[*] Using SSH port: $SSH_PORT"

# -- 1. Detect if affected --
broken_dpkg=false
failed_socket=false

if dpkg -s openssh-server 2>/dev/null | grep -qE 'Status:.*(half-configured|half-installed|unpacked|triggers-awaited|triggers-pending)'; then
    broken_dpkg=true
    echo "[!] openssh-server dpkg state is broken."
fi

if systemctl is-failed --quiet ssh.socket 2>/dev/null; then
    failed_socket=true
    echo "[!] ssh.socket is in failed state."
fi

if ! $broken_dpkg && ! $failed_socket; then
    echo "[OK] Server is not affected. openssh-server package and ssh.socket are healthy."
    exit 0
fi

echo ""
echo "Server is affected. Proceeding with fix..."
echo ""

# -- 2. Create /run/sshd if missing --
if [[ ! -d /run/sshd ]]; then
    echo "[*] Creating /run/sshd ..."
    mkdir -p /run/sshd
    chmod 0755 /run/sshd
else
    echo "[OK] /run/sshd already exists."
fi

# -- 3. Kill orphaned sshd master process --
orphan_pids=()
while IFS= read -r pid; do
    [[ -z "$pid" ]] && continue
    ppid=$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d ' ') || continue
    if [[ "$ppid" == "1" ]]; then
        orphan_pids+=("$pid")
    fi
done < <(pgrep -f '/usr/sbin/sshd' 2>/dev/null || true)

if [[ ${#orphan_pids[@]} -gt 0 ]]; then
    echo "[*] Found orphaned sshd master process(es): ${orphan_pids[*]}"
    for pid in "${orphan_pids[@]}"; do
        echo "    Killing PID $pid ..."
        kill "$pid" 2>/dev/null || true
    done
else
    echo "[OK] No orphaned sshd master processes found."
fi

# -- 4. Wait for port to free --
echo "[*] Waiting for port $SSH_PORT to free ..."
for i in $(seq 1 30); do
    if ! ss -tlnp | grep -q ":${SSH_PORT} "; then
        echo "    Port $SSH_PORT is free."
        break
    fi
    if [[ $i -eq 30 ]]; then
        echo "WARNING: Port $SSH_PORT still in use after 30s. Continuing anyway."
    fi
    sleep 1
done

# -- 5. Reset and start ssh.socket --
echo "[*] Resetting ssh.socket ..."
systemctl reset-failed ssh.socket 2>/dev/null || true
systemctl reset-failed ssh.service 2>/dev/null || true

echo "[*] Starting ssh.socket ..."
systemctl start ssh.socket

# -- 6. Fix dpkg state --
if $broken_dpkg; then
    echo "[*] Running dpkg --configure openssh-server ..."
    dpkg --configure openssh-server
fi

# -- 7. Verify --
echo ""
echo "=== Verification ==="

errors=0

if systemctl is-active --quiet ssh.socket; then
    echo "[OK] ssh.socket is active."
else
    echo "[FAIL] ssh.socket is NOT active."
    errors=$((errors + 1))
fi

if ss -tlnp | grep -q ":${SSH_PORT} "; then
    echo "[OK] Port $SSH_PORT is listening."
else
    echo "[FAIL] Port $SSH_PORT is NOT listening."
    errors=$((errors + 1))
fi

status=$(dpkg -s openssh-server 2>/dev/null | grep '^Status:' || echo "not found")
if echo "$status" | grep -q 'install ok installed'; then
    echo "[OK] dpkg state is clean: $status"
else
    echo "[FAIL] dpkg state is not clean: $status"
    errors=$((errors + 1))
fi

# -- 8. Clean up crash file --
if [[ -f /var/crash/openssh-server.0.crash ]]; then
    echo "[*] Removing /var/crash/openssh-server.0.crash ..."
    rm -f /var/crash/openssh-server.0.crash
fi

echo ""
if [[ $errors -eq 0 ]]; then
    echo "=== All checks passed. Server is fixed. ==="
else
    echo "=== $errors check(s) failed. Manual investigation needed. ==="
    exit 1
fi

Pour l'exécuter sur un seul serveur :

sudo bash fix-openssh-upgrade.sh

Pour le déployer sur plusieurs serveurs :

for server in server1 server2 server3; do
    echo "--- $server ---"
    ssh root@$server 'bash -s' < fix-openssh-upgrade.sh
done

Prévenir ce problème à l'avenir

Si vous souhaitez empêcher unattended-upgrades de toucher à openssh-server à l'avenir, vous pouvez le mettre sur liste noire. Modifiez /etc/apt/apt.conf.d/50unattended-upgrades et ajoutez à la section Package-Blacklist :

Unattended-Upgrade::Package-Blacklist {
    "openssh-server";
};

Cela garantit que les paquets liés à SSH ne sont mis à jour que lorsque vous le faites manuellement et que vous pouvez surveiller le processus.

Si vous êtes complètement bloqué

Si le processus sshd orphelin est déjà mort ou que le serveur a redémarré, vous ne pourrez pas vous connecter en SSH. Dans ce cas, utilisez l'accès console de votre hébergeur pour exécuter la correction :

  • DigitalOcean : Droplet Console (via navigateur web)
  • AWS : EC2 Serial Console ou Session Manager
  • Hetzner : Console VNC dans la Cloud Console
  • Tout hébergeur : Accès VNC ou KVM depuis votre panneau de contrôle

Résumé

La mise à jour d'openssh-server du 16 mars 2026 sur Ubuntu 24.04 a cassé SSH sur les serveurs utilisant unattended-upgrades. Les symptômes sont un état dpkg à moitié configuré, un ssh.socket en échec, une erreur "fatal: Missing privilege separation directory: /run/sshd" dans auth.log, un processus sshd orphelin, et des serveurs affichés comme "Déconnectés" dans Laravel Forge. La correction consiste à recréer /run/sshd, tuer le processus orphelin, réinitialiser les unités systemd et reconfigurer le paquet. Le script ci-dessus automatise l'ensemble du processus et peut être exécuté sans risque sur des serveurs non affectés.

Surveillez vos propres serveurs

Suivez le CPU, la mémoire, le disque et les processus sur jusqu'à 2 serveurs gratuitement. La configuration prend environ 5 minutes.

Commencer gratuitement

Articles connexes