Kurz gesagt: Am Ende öffnet nur noch dein Schlüssel die Tür zum Server, root darf sich nicht mehr anmelden, und wer Passwörter rät, wird nach fünf Versuchen ausgesperrt. Etwa 30 Minuten, Stufe Einsteiger. Stand: OpenSSH 10.0 (Debian 13) und 10.2 (Ubuntu 26.04 LTS) mit fail2ban 1.1.0, geprüft am 07-09-2026. Auf Debian 12 und Ubuntu 24.04 läuft alles genauso, die zwei Unterschiede stehen bei den Stolpersteinen.
SSH absichern in vier Schritten: Schlüssel erzeugen, Schlüssel hinterlegen, Passwort-Login abschalten, fail2ban davorsetzen
Der ganze Weg auf einen Blick: Schritt 3 ist der, bei dem man sich aussperren kann. Deshalb gibt es dort einen Test, bevor du die alte Tür zumachst.

Auf einem Server, der aus dem Internet erreichbar ist, sieht das Anmelde-Protokoll nach einer Nacht so aus:

Failed password for root from 203.0.113.17 port 41022 ssh2
Failed password for invalid user admin from 198.51.100.8 port 55710 ssh2
Failed password for invalid user ubuntu from 198.51.100.8 port 55934 ssh2

Das sind keine Angreifer, die dich persönlich meinen. Das sind Skripte, die das ganze Internet abklappern und auf jedem Port 22 dieselben zweihundert Passwörter durchprobieren. Steht dein Server nur im Heimnetz hinter dem Router, kommen sie nicht bis zu ihm. Trotzdem würde ich SSH auch dort absichern, aus zwei Gründen: Irgendwann öffnest du doch eine Portfreigabe oder ein VPN, und dann soll die Tür schon zu sein. Und der Schlüssel-Login ist nebenbei bequemer als jedes Passwort.

Das Rezept ist seit Jahren dasselbe und passt auf eine Hand: Schlüssel statt Passwort, root aussperren, einen Wächter davorsetzen. Was sich geändert hat, ist die Stelle, an der man es einträgt. Debian und Ubuntu lesen seit einigen Versionen einen Ordner mit Zusatzdateien, und Ubuntu legt dort seit 24.04 selbst eine ab, die deine Einstellung überstimmt, wenn du sie an der klassischen Stelle machst. Genau darüber stolpern gerade viele. Dazu später mehr.

SSH-Schlüssel? Ein Schlüsselpaar aus zwei Dateien. Die öffentliche ist das Schloss: Die darf jeder sehen, du hängst sie an jede Tür, durch die du willst. Die private ist der Schlüssel dazu: Sie bleibt auf deinem Laptop und verlässt ihn nie. Ein Passwort kann man raten, weil es kurz ist. Einen Ed25519-Schlüssel rät niemand, weil er 256 Bit Zufall ist.

Was du brauchst

  • Einen Server mit Debian 12 oder 13 oder Ubuntu 24.04 oder 26.04, auf dem du dich schon per SSH mit Passwort anmelden kannst.
  • Einen Benutzer, der nicht root ist und sudo darf. Falls du bisher nur als root arbeitest: erst einen anlegen, sonst sperrt dich Schritt 3 aus.
  • Einen Laptop oder PC mit SSH-Client. Linux und macOS haben ihn, Windows 10 und 11 seit ein paar Jahren auch (im PowerShell-Fenster).
  • Einen Weg zum Server, der nicht über SSH geht: die Konsole in Proxmox, ein Monitor am Rechner oder die Webkonsole deines Hosters. Du wirst ihn vermutlich nicht brauchen. Aber wenn, dann dringend.

Ob die Voraussetzungen passen, prüfst du auf dem Server mit drei Befehlen. Die erste Zeile zeigt die Version, die zweite muss active (running) enthalten, die dritte darf nach dem Passwort keine Fehlermeldung bringen.

So liest du diese Anleitung: Alles, was du selbst tun sollst, steht in einem farbigen Kasten. [ per klick ] heißt: Das erledigst du mit der Maus in einer Web-Oberfläche, hier kommt das nicht vor, diese Anleitung läuft komplett im Terminal. [ über die shell ] heißt: Den Befehl kopieren, ins Terminal einfügen, Enter. Stehen beide Kästen direkt untereinander, führen sie zum selben Ergebnis. Du gehst EINEN davon, nicht beide.
grep PRETTY_NAME /etc/os-release
systemctl status ssh | head -3
sudo -v

Der zweite Befehl heißt auf beiden Systemen ssh, nicht sshd. Das ist auf Debian und Ubuntu seit jeher so und verwirrt jeden, der von CentOS kommt.

  • Server im Heimnetz: 192.168.178.50
  • Dein Benutzer auf dem Server: sakis
  • Dein Heimnetz: 192.168.178.0/24
  • Name für den Schlüssel: laptop-sakis
  • Die neue Einstellungsdatei: /etc/ssh/sshd_config.d/10-homelab.conf

Alles Weitere läuft in zwei Fenstern: eines auf dem Laptop für die Schlüssel, eines auf dem Server für die Einstellungen. Ich schreibe jeweils dazu, wo du gerade bist.

Schritt 1: Schlüsselpaar auf dem Laptop erzeugen

Auf dem Laptop, nicht auf dem Server. Der Befehl fragt nach einem Speicherort (Enter für den Vorschlag) und zweimal nach einer Passphrase. Die Passphrase ist das Passwort für die Schlüsseldatei selbst: Wer dir den Laptop klaut, hat damit noch keinen Server. Ich würde eine setzen. Die Manpage sagt dazu trocken, dass es keinen Weg gibt, eine vergessene Passphrase wiederherzustellen. Also ab damit in den Passwort-Manager, zum Beispiel deinen eigenen Vaultwarden.

ssh-keygen -t ed25519 -C "laptop-sakis"
ls ~/.ssh/id_ed25519*

-t ed25519 wählt das Verfahren, das OpenSSH seit Version 9.5 ohnehin als Standard nimmt. -C hängt einen Kommentar an, damit du in einem Jahr noch weißt, von welchem Gerät der Schlüssel stammt. Der zweite Befehl ist die Kontrolle: Er muss zwei Dateien zeigen, id_ed25519 und id_ed25519.pub. Die ohne Endung ist die private. Die kopierst du nirgendwohin, auch nicht „nur kurz" auf den Server.

Schritt 2: Öffentlichen Schlüssel auf dem Server hinterlegen

Immer noch auf dem Laptop. ssh-copy-id meldet sich ein letztes Mal mit Passwort an und hängt den öffentlichen Schlüssel auf dem Server an die Datei ~/.ssh/authorized_keys. Ordner und Datei legt es an, wenn sie fehlen.

ssh-copy-id sakis@192.168.178.50
ssh sakis@192.168.178.50

Der zweite Befehl ist der Test: Fragt der Server nur noch nach der Passphrase deines Schlüssels (oder nach gar nichts, wenn du keine gesetzt hast) und nicht mehr nach dem Passwort des Benutzers, ist der Schlüssel drin. Auf dem Server siehst du es auch im Protokoll:

sudo journalctl -u ssh -n 5 --no-pager
Accepted publickey for sakis from 192.168.178.20 port 53522 ssh2: ED25519 SHA256:…

Windows ohne ssh-copy-id: Der Windows-Client bringt das Hilfsprogramm nicht mit. Dann machst du von Hand, was es tun würde: Auf dem Laptop den Inhalt von id_ed25519.pub anzeigen und kopieren (eine Zeile, beginnt mit ssh-ed25519), dann auf dem Server die Datei anlegen und die Zeile einfügen. Speichern in nano: Strg+O, Enter, schließen mit Strg+X.

mkdir -p ~/.ssh && chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Die beiden chmod sind kein Beiwerk. Die sshd-Manpage sagt, dass der Server einen Schlüssel ignoriert, wenn Ordner oder Datei für andere Benutzer schreibbar sind. Das ist die zweithäufigste Ursache für „Schlüssel drin, fragt trotzdem nach Passwort".

Laptop: privater Schlüssel→ beweist, dass er zum Schloss passt →sshd auf dem Server→ vergleicht mit →~/.ssh/authorized_keys

Schritt 3: Passwort-Login und root abschalten

Jetzt auf dem Server. Und jetzt der Backup-Tick, du kennst ihn: Lass das Fenster, in dem du gerade angemeldet bist, bis zum Ende dieses Schritts offen. Jeder Test läuft in einem zweiten Fenster. Solange die alte Sitzung lebt, kannst du jede Änderung zurücknehmen.

Die Einstellungen kommen in eine eigene Datei im Ordner /etc/ssh/sshd_config.d/. Debian liest den Ordner seit Version 11, Ubuntu ebenso, und beide haben dafür ganz oben in der Hauptdatei eine Include-Zeile. Warum eine eigene Datei statt der Hauptdatei? Weil das Paket bei Updates die Hauptdatei anfassen darf, deine Datei aber nicht. Und weil der Name zählt.

Warum „10-" im Dateinamen? sshd liest die Dateien im Ordner in alphabetischer Reihenfolge, und für jede Einstellung gilt der erste Wert, den es findet. Spätere Werte werden ignoriert. Der Ordner ist ein Stapel Notizzettel: Wer seinen Zettel ganz oben drauflegt, hat das Sagen. Eine Datei, die mit 10 beginnt, liegt vor allem, was mit 50 beginnt. Das wird gleich wichtig.
sudo nano /etc/ssh/sshd_config.d/10-homelab.conf

Diese vier Zeilen hinein, speichern (Strg+O, Enter), schließen (Strg+X):

PasswordAuthentication no
PermitRootLogin no
KbdInteractiveAuthentication no
MaxAuthTries 3

Zeile eins schaltet den Passwort-Login ab, ab jetzt öffnet nur der Schlüssel. Zeile zwei sperrt root komplett aus; der Standard ist prohibit-password, root dürfte also noch mit Schlüssel, und das brauchst du nicht, du hast sudo. Zeile drei schließt den zweiten Passwort-Weg, den PAM anbietet; Debian und Ubuntu haben ihn zwar schon aus, aber die Hauptdatei kann sich ändern, deine Datei nicht. Zeile vier senkt die Rateversuche pro Verbindung von sechs auf drei. Das erspart dem Bot nichts, aber dem Protokoll die Hälfte der Zeilen.

Bevor du den Dienst neu startest, prüfst du zweimal. Einmal die Syntax: sshd -t sagt bei einer korrekten Datei gar nichts, das ist hier die gute Nachricht. Und einmal die Wirkung: sshd -T zeigt, was der Server nach dem Zusammenlesen aller Dateien wirklich anwendet.

sudo sshd -t
sudo sshd -T | grep -Ei "^(passwordauthentication|permitrootlogin|maxauthtries)"
passwordauthentication no
permitrootlogin no
maxauthtries 3

Steht dort passwordauthentication yes, hat eine andere Datei deine überstimmt. Auf Ubuntu ist das fast immer 50-cloud-init.conf, siehe Stolpersteine. Erst wenn die Ausgabe stimmt, startest du neu. Deine offene Sitzung übersteht das, weil jede Verbindung ihren eigenen Prozess hat.

sudo systemctl restart ssh

Der Test kommt in einem zweiten Fenster auf dem Laptop, und zwar in beide Richtungen. Erst normal anmelden: muss klappen. Dann mit einer Option, die dem Client den Schlüssel verbietet: muss scheitern, und zwar mit genau dieser Meldung.

ssh sakis@192.168.178.50 "echo schluessel ok"
ssh -o PubkeyAuthentication=no sakis@192.168.178.50
sakis@192.168.178.50: Permission denied (publickey).

Die zweite Zeile ist die schönste Fehlermeldung des Tages: Der Server nennt nur noch publickey als Möglichkeit, das Wort password fehlt in der Klammer. Jetzt darfst du das alte Fenster schließen.

Schritt 4: fail2ban davorsetzen

fail2ban? Der Türsteher, der mitzählt. Er liest das Anmelde-Protokoll mit, und wer in zehn Minuten fünfmal an der Tür scheitert, kommt für eine Weile auf die Sperrliste der Firewall. Ohne Passwort-Login kann der Bot ohnehin nicht rein. Aber er hört nicht auf zu klopfen, und fail2ban hält das Protokoll lesbar.

Die eigenen Werte kommen nie in jail.conf, die überschreibt das nächste Paket-Update. Ganz oben in dieser Datei steht das sogar in Großbuchstaben. Stattdessen legst du jail.local daneben an.

sudo apt install fail2ban
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 192.168.178.0/24

[sshd]
enabled = true
backend = systemd

Speichern, schließen, Dienst neu starten. Dann fragst du fail2ban selbst, ob es das SSH-Gefängnis bewacht.

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

Die Zeile backend = systemd sagt fail2ban, dass es das Journal lesen soll statt einer Logdatei. Auf Debian 13 bringt das Paket die Zeile schon mit, auf einem frisch installierten Debian 12 nicht, und dort gibt es die Datei /var/log/auth.log gar nicht mehr. Die Zeile schadet nirgends und erspart dir den häufigsten Fehler aus den Stolpersteinen.

Die Einstellungen, die den Unterschied machen

Der Server ist jetzt dicht. Vier Werte in den zwei Dateien würde ich trotzdem noch einmal bewusst anfassen, weil die Voreinstellung jeweils für einen anderen Server gedacht ist als deinen.

  • ignoreip mit deinem Heimnetz. Ohne diese Zeile sperrt fail2ban auch dich, wenn du dich beim Passphrase-Tippen fünfmal vertust oder ein Skript von deinem Laptop mit falschem Benutzernamen anklopft. Genau dafür ist die Liste laut jail.conf gedacht. Mit dem Heimnetz drin zählt der Wächter nur Fremde.
  • bantime auf eine Stunde statt zehn Minuten. Zehn Minuten sind der Wert aus jail.conf. Bots warten die ab und machen weiter. Wer es gründlicher will, setzt zusätzlich bantime.increment = true: Dann wächst die Sperre bei jedem Wiederkommen. Das steht so in der Doku zu jail.conf und ist die Einstellung, die das Protokoll am spürbarsten leert.
  • AllowUsers sakis in deiner Datei. Standardmäßig darf jedes Konto auf dem Server per SSH rein, auch das von Diensten, die du später installierst und die sich selbst ein Konto anlegen. Mit AllowUsers (mehrere Namen durch Leerzeichen) ist die Liste explizit. Vorher in Ruhe überlegen, wer wirklich draufsteht: Wer fehlt, kommt nicht mehr rein, auch mit Schlüssel.
  • Ein zweiter Schlüssel für den zweiten Rechner. Ein Schlüssel pro Gerät, nie die private Datei kopieren. Geht ein Laptop verloren, löschst du auf dem Server nur seine Zeile aus authorized_keys, der Rest arbeitet weiter. Das ist der Grund für den Kommentar aus Schritt 1: Ohne ihn siehst du in der Datei zwei Zeilen Zeichensalat und weißt nicht, welche weg soll.

Nach jeder Änderung an der sshd-Datei dasselbe Ritual wie in Schritt 3: sudo sshd -t, dann sudo systemctl restart ssh, dann der Test aus dem zweiten Fenster. Nach Änderungen an jail.local reicht sudo systemctl restart fail2ban.

Was hier bewusst fehlt: der Port-Wechsel. Er hält nur die dümmsten Bots fern, weil die anderen alle Ports abklopfen, und auf Ubuntu lauscht seit 22.10 systemd auf dem Port statt sshd selbst, sodass die Zeile Port je nach Version einen Umweg über eine Socket-Datei braucht. Das Ubuntu-Forum hat dazu einen eigenen Erklär-Thread. Ich würde die halbe Stunde lieber in fail2ban stecken.

Stolpersteine aus fremder Praxis

Ubuntu: „Ich habe PasswordAuthentication no gesetzt, und es passiert nichts." Der häufigste Treffer, seit Ubuntu 24.04 draußen ist. Der Installer legt über cloud-init die Datei /etc/ssh/sshd_config.d/50-cloud-init.conf mit PasswordAuthentication yes an. Wer die Einstellung in der Hauptdatei macht, verliert, weil der Ordner vor der Hauptdatei gelesen wird. Auf Launchpad wurde das gemeldet, und die cloud-init-Entwickler haben entschieden, dass das so bleibt; geändert wurde nur der Kommentar in der Hauptdatei. Mit der Datei 10-homelab.conf aus Schritt 3 liegt dein Zettel vor ihrem, deshalb ist die Anleitung so gebaut. Nachsehen kannst du mit ls /etc/ssh/sshd_config.d/, und die Wahrheit sagt immer sudo sshd -T.

Debian 12: „Have not found any log file for sshd jail." fail2ban startet nicht. In den Issues auf GitHub der häufigste Debian-12-Treffer: Bookworm schreibt ohne rsyslog keine auth.log mehr, und die Paketversion 1.0.2 sucht trotzdem danach. Die Zeile backend = systemd aus Schritt 4 löst es. Fehlt danach noch das Modul systemd im Fehlertext, fehlt das Paket python3-systemd: sudo apt install python3-systemd. In Debian 13 ist es eine feste Abhängigkeit, dort tritt beides nicht mehr auf.

„Schlüssel hinterlegt, fragt trotzdem nach Passwort." Fast immer Rechte. Die Manpage von sshd ist da streng: Ist das Home-Verzeichnis, ~/.ssh oder authorized_keys für andere schreibbar, ignoriert der Server die Datei stillschweigend. Die beiden chmod aus Schritt 2 (700 für den Ordner, 600 für die Datei) reparieren das. Der Grund steht im Journal: sudo journalctl -u ssh -n 20 zeigt eine Zeile mit „Authentication refused: bad ownership or modes".

Ausgesperrt. Passiert, wenn man Schritt 3 ohne zweites Fenster durchzieht. Dann bleibt der Weg, der nicht über SSH geht: Proxmox-Konsole, Monitor, Hoster-Konsole. Dort anmelden, die Datei 10-homelab.conf löschen oder PasswordAuthentication yes hineinschreiben, sudo systemctl restart ssh, und von vorn, diesmal mit Testfenster.

Reicht das?

Für einen Homelab-Server, ja. Schlüssel statt Passwort nimmt den Bots ihre einzige Methode, root aussperren nimmt ihnen ihr Lieblingsziel, fail2ban räumt das Protokoll auf. Mehr Härtung, etwa 2FA über PAM oder Anmeldung nur aus dem VPN, bringt für einen Server hinter dem Heimrouter kaum zusätzliche Sicherheit, aber zusätzliche Wege, sich auszusperren. Ich würde es lassen, bis der Server wirklich von außen erreichbar ist. Und wenn du so weit bist, gehört der SSH-Port trotzdem nicht in die Portfreigabe des Routers, sondern hinter ein VPN. Das ist ein eigener Beitrag.

Was mich an dem Thema freut: Die Anleitung ist im Kern seit zehn Jahren gleich, und sie funktioniert immer noch. Es sind nur die Zettel im Ordner dazugekommen. Was hat dich beim Absichern deines ersten Servers am meisten Zeit gekostet, und hast du dich dabei auch schon einmal selbst ausgesperrt? Schreib es in die Kommentare, mit dem Fehler, der dich am Ende weitergebracht hat.

Der Schlüssel liegt jetzt an einer Tür, seine Passphrase gehört in den Passwort-Manager. Wenn du noch keinen eigenen hast: Vaultwarden mit Docker installieren ist der nächste logische Abend.

Quellen