sshd nach Unattended Upgrade auf Ubuntu 24.04 reparieren (März 2026)
So reparieren Sie openssh-server nach fehlgeschlagenem unattended-upgrades auf Ubuntu 24.04. Behandelt das fehlende /run/sshd-Verzeichnis, den half-configured dpkg-Status, fehlgeschlagenes ssh.socket und ein vollständiges automatisiertes Fix-Skript.
Am 16. März 2026 hat ein fehlerhaftes openssh-server-Upgrade (1:9.6p1-3ubuntu13.14 auf .15) SSH auf Ubuntu-24.04-Servern mit unattended-upgrades zum Absturz gebracht. Die Ursache scheint ein fehlendes /run/sshd-Verzeichnis, das dazu führte, dass das postinst-Skript fehlschlug und dpkg halb konfiguriert sowie ssh.socket in einem fehlerhaften Zustand hinterließ. Die Lösung besteht darin, das Verzeichnis neu zu erstellen, den verwaisten sshd-Prozess zu beenden, systemd zurückzusetzen und das Paket neu zu konfigurieren.
TL;DR - Schnellfix (als root ausführen)
mkdir -p /run/sshd && chmod 0755 /run/sshd
systemctl reset-failed ssh.socket ssh.service && systemctl start ssh.socket
dpkg --configure openssh-server
Falls der alte sshd-Prozess den Port blockiert, erst beenden: kill $(pgrep -f '/usr/sbin/sshd' | xargs -I{} sh -c 'ps -o ppid= -p {} | tr -d " "' | grep '^1$'). Weiter unten folgt das vollständige automatisierte Skript.
Was schiefgelaufen ist
Das openssh-server-Paket-Upgrade von 1:9.6p1-3ubuntu13.14 auf 1:9.6p1-3ubuntu13.15 scheint mit einem fehlerhaften postinst-Maintainer-Skript ausgeliefert worden zu sein. Als unattended-upgrades über Nacht lief und versuchte, das neue Paket zu konfigurieren, schlug das Skript fehl. Dadurch blieb dpkg in einem halb konfigurierten Zustand, systemds ssh.socket in einem fehlerhaften Zustand, und der alte sshd-Masterprozess war verwaist -- er lief noch, wurde aber nicht mehr von systemd verwaltet.
Der Server bleibt nur so lange erreichbar, wie dieser verwaiste sshd-Prozess läuft. Stirbt er ab oder wird der Server neu gestartet, ist der SSH-Zugang vollständig verloren. In Laravel Forge erscheinen betroffene Server als "Disconnected", da Forge sie nicht mehr per SSH erreichen kann.
Wie wir das Problem diagnostiziert haben
Auf einem unserer betroffenen Systeme haben wir bei der Untersuchung Folgendes festgestellt.
dpkg: error processing package openssh-server
Paketstatus prüfen:
$ dpkg -s openssh-server | grep Status
Status: install ok half-configured
Das bestätigt, dass das Paket mitten im Upgrade steckt. Ein Blick darauf, was unattended-upgrades gemacht hat:
$ 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'
systemd prüfen:
$ 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'.
Die Socket-Aktivierung ist vollständig defekt. Wir konnten aber noch per SSH einloggen, was bedeutete, dass noch etwas lauschte. Suche nach dem verwaisten Prozess:
$ ps -eo pid,ppid,cmd | grep sshd
1234 1 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
PPID 1 -- das ist der alte sshd-Masterprozess, der nach dem fehlgeschlagenen Upgrade von systemd nicht mehr verwaltet wird. Er akzeptiert noch Verbindungen, weshalb SSH noch funktioniert, läuft aber auf geborgter Zeit.
fatal: Missing privilege separation directory: /run/sshd
Das auth.log enthüllte die wahrscheinliche Ursache:
$ grep sshd /var/log/auth.log
2026-03-18T18:20:19.201354+00:00 sshd[3115043]: fatal: Missing privilege separation directory: /run/sshd
Das Laufzeitverzeichnis fehlte tatsächlich:
$ ls -la /run/sshd
ls: cannot access '/run/sshd': No such file or directory
Dieses fehlende Verzeichnis dürfte der Grund sein, warum das postinst-Skript fehlschlug, da sshd es für die Privilege Separation benötigt.
Wir haben außerdem einen Crash-Report gefunden:
$ ls /var/crash/
openssh-server.0.crash
Fehlermeldungen, die auftreten können
Je nachdem, wo man nachschaut, können einige oder alle dieser Meldungen auftreten:
In der dpkg / apt-Ausgabe
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)
Bei apt upgrade oder 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
Paketstatus
Status: install ok half-configured
systemd-Fehler
ssh.socket: Failed with result 'service-start-limit-hit'.
ssh.service: Failed with result 'exit-code'.
Auth-Log
sshd[3115043]: fatal: Missing privilege separation directory: /run/sshd
So behebt man das Problem
Wir haben ein Skript geschrieben, das die gesamte Reparatur automatisiert. Es ist sicher, auf Servern auszuführen, die NICHT betroffen sind -- es erkennt den defekten Zustand zuerst und beendet sich sauber, wenn alles in Ordnung ist. Das macht es einfach, das Skript auf allen Servern auszuführen, ohne sich darum kümmern zu müssen, welche tatsächlich betroffen sind.
Das Skript:
- Liest den SSH-Port aus sshd_config (geht nicht von Port 22 aus)
- Erkennt, ob der Server betroffen ist (defekter dpkg-Zustand und/oder fehlgeschlagenes ssh.socket)
- Erstellt
/run/sshd, falls es fehlt - Sucht und beendet den verwaisten sshd-Masterprozess
- Wartet, bis der Port freigegeben wird
- Setzt
ssh.socketzurück und startet es - Führt
dpkg --configureaus, um den Paketstatus zu reparieren - Überprüft, ob alles funktioniert
- Bereinigt die Crash-Datei
Hier ist das vollständige Skript:
#!/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
Auf einem einzelnen Server ausführen:
sudo bash fix-openssh-upgrade.sh
Auf mehrere Server gleichzeitig verteilen:
for server in server1 server2 server3; do
echo "--- $server ---"
ssh root@$server 'bash -s' < fix-openssh-upgrade.sh
done
Vorbeugung für die Zukunft
Wer verhindern möchte, dass unattended-upgrades künftig openssh-server aktualisiert, kann das Paket auf die Blacklist setzen. Dazu die Datei /etc/apt/apt.conf.d/50unattended-upgrades bearbeiten und zum Abschnitt Package-Blacklist hinzufügen:
Unattended-Upgrade::Package-Blacklist {
"openssh-server";
};
So werden SSH-bezogene Pakete nur noch aktualisiert, wenn man es manuell tut und den Vorgang überwachen kann.
Wenn der Zugang vollständig gesperrt ist
Falls der verwaiste sshd-Prozess bereits abgestorben ist oder der Server neu gestartet wurde, ist kein SSH-Login mehr möglich. In diesem Fall kann man über den Konsolenzugang des Hosting-Anbieters die Reparatur durchführen:
- DigitalOcean: Droplet Console (webbasiert)
- AWS: EC2 Serial Console oder Session Manager
- Hetzner: VNC-Konsole in der Cloud Console
- Jeder Anbieter: VNC- oder KVM-Zugang über das Control Panel
Zusammenfassung
Das openssh-server-Upgrade vom 16. März 2026 auf Ubuntu 24.04 hat SSH auf Servern mit unattended-upgrades beschädigt. Die Symptome sind ein halb konfigurierter dpkg-Zustand, ein fehlgeschlagenes ssh.socket, ein "fatal: Missing privilege separation directory: /run/sshd"-Fehler im auth.log, ein verwaister sshd-Prozess und Server, die in Laravel Forge als "Disconnected" angezeigt werden. Die Lösung umfasst das Neuerstellen von /run/sshd, das Beenden des verwaisten Prozesses, das Zurücksetzen der systemd-Units und die Neukonfiguration des Pakets. Das obige Skript automatisiert den gesamten Vorgang und kann gefahrlos auf nicht betroffenen Servern ausgeführt werden.