VPS absichern: SSH, Firewall und Fail2ban Guide

Step-by-step guide to securing a VPS with SSH hardening, UFW firewall, Fail2ban, and automatic security updates

VPS absichern: SSH, Firewall und Fail2ban Guide

Kurz nachdem ich meinen ersten eigenen VPS provisioniert hatte, lag /var/log/auth.log in einer Größenordnung, die ich nicht erwartet hatte: über 12.000 fehlgeschlagene SSH-Loginversuche in knapp drei Tagen. Willkommen im öffentlichen Internet. Jede IPv4-Adresse wird permanent gescannt, und zwar vollautomatisch. Das ist keine Ausnahme, das ist der Normalzustand.

Dieser Beitrag ist kein generisches Security-Tutorial, sondern der Auszug dessen, was ich auf meinem eigenen Server tatsächlich eingerichtet habe. Debian 12, aber für Ubuntu 22.04 sind die Schritte nahezu identisch.

SSH zuerst, weil hier das meiste passiert

Port 22 offen mit Passwort-Auth — das ist keine Konfiguration, das ist eine Einladung. Als erstes Key-basiertes Login erzwingen.

Lokal:

ssh-keygen -t ed25519 -C "matti@laptop"
ssh-copy-id root@server

Danach auf dem Server in /etc/ssh/sshd_config:

PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no

Ich nehme absichtlich prohibit-password und nicht no. Root darf sich einloggen, aber nur per Key. Ein separater sudo-User bringt in meinem Setup keinen messbaren Sicherheitsgewinn, nur mehr Klickerei.

Port-Wechsel auf 2222 oder sonstwas? Reine Log-Kosmetik. Massenscanner gucken meist nur auf 22, also wird das Log etwas ruhiger. Seriöse Angreifer finden den Port trotzdem in Sekunden.

Bevor ich SSH neu lade, öffne ich immer eine zweite Session parallel. Beim ersten Mal habe ich mich selbst ausgesperrt und musste über die Hoster-Konsole wieder reinkommen — das passiert einmal, dann nie wieder.

systemctl reload ssh

UFW statt raw iptables

iptables direkt zu schreiben ist was für Leute, die ihren eigenen Kernel kompilieren. Für einen normalen Web- oder Mail-VPS reicht UFW problemlos.

apt install ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow 2222/tcp
ufw allow 80,443/tcp
ufw enable

Mit Mailserver zusätzlich: 25, 465, 587, 993. IMAP ohne TLS (143) und POP3 würde ich heute gar nicht mehr aufmachen — wenn ein Mailclient das braucht, muss er dringend ersetzt werden.

Fail2ban: nützlich, aber bitte keine Wunder erwarten

Fail2ban liest Logs und sperrt IPs nach zu vielen Fehlversuchen. In meinen Logs sehe ich regelmäßig, wie ein Botnet mit 50 unterschiedlichen IPs aus demselben /24 nacheinander probiert. Fail2ban sperrt sie alle, aber die 51. kommt trotzdem. Gegen den allgemeinen Grundrauschen hilft es, gegen gezielte Angriffe kaum.

apt install fail2ban

In /etc/fail2ban/jail.local (nicht jail.conf editieren):

[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5

[sshd]
enabled = true
port = 2222

Wenn du hinter Cloudflare bist und Fail2ban für nginx einsetzt, musst du auf die echten Client-IPs im X-Forwarded-For umschalten, sonst sperrst du irgendwann Cloudflare aus. Ein Fehler, den ich zweimal gemacht habe.

Automatische Security-Updates

Volle unattended-upgrades sind mir zu riskant, Security-Only ist der Kompromiss:

apt install unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades

In /etc/apt/apt.conf.d/50unattended-upgrades nur die Security-Origin aktiv. Reboots triggere ich selbst, wenn ich weiß, dass ich am Rechner bin.

Die zwei Sachen, die fast niemand macht

Logwatch per Mail. Einmal täglich kriege ich eine Zusammenfassung von /var/log/. Zweimal hat das Fehler gezeigt, die mir sonst durchgegangen wären — einmal ein Fail2ban-Syntaxfehler, einmal ein Cron-Job, der auf vollem Volume still weggestorben ist.

Ein zweiter SSH-User als Notfalltür. Nicht für den täglichen Betrieb, sondern für den Fall, dass die SSH-Config kaputtgeht. Eigener Key, eigene Firewall-Regel, sonst nicht in Benutzung.

Security ist keine Checkliste, die man einmal abhakt. Aber nach Key-Auth, Firewall, Fail2ban und Security-Updates ist der Aufwand für die allermeisten Bots so hoch, dass sie weiterziehen. Alles Weitere ist Monitoring — und das ist ein eigener Artikel.