VPS Security Setup
Bevor newwaves.dev auf meinem VPS gelandet ist, wollte ich den Server nicht einfach offen ins Internet stellen. Also habe ich zuerst eine kleine Basis-Härtung gemacht: weniger Angriffsfläche, kein Root-Login per SSH, keine Passwort-Logins und nur die Ports offen, die wirklich gebraucht werden.
Das ist keine perfekte Security-Architektur und ersetzt kein professionelles Hardening. Für meinen kleinen Ubuntu-VPS war es aber ein sinnvoller Mindeststandard, bevor die Website live ging.
Erst aktualisieren, dann bauen
Direkt nach dem Einrichten des VPS habe ich das System aktualisiert. Das ist unspektakulär, aber wichtig: bevor Website, SSH-Konfiguration und Webserver dazukommen, möchte ich nicht auf einem alten Paketstand weiterarbeiten.
sudo apt update
sudo apt upgrade -y
Danach war der VPS technisch noch nicht fertig, aber bereit für die nächsten Schritte. Erst auf dieser Basis habe ich SSH und Firewall sauber eingerichtet.
Nicht dauerhaft als Root arbeiten
Der erste echte Schritt war ein eigener Admin-User. Root ist praktisch, aber als täglicher Login unnötig riskant. Deshalb bekommt der normale User sudo-Rechte und arbeitet nur dann administrativ, wenn es wirklich gebraucht wird.
adduser USERNAME
usermod -aG sudo USERNAME
Wichtig war danach, den SSH-Key sauber für den neuen User zu hinterlegen und die Dateirechte zu setzen. Gerade bei SSH sind falsche Rechte schnell der Grund, warum ein Login nicht funktioniert.
mkdir -p /home/USERNAME/.ssh
cp /root/.ssh/authorized_keys /home/USERNAME/.ssh/
chown -R USERNAME:USERNAME /home/USERNAME/.ssh
chmod 700 /home/USERNAME/.ssh
chmod 600 /home/USERNAME/.ssh/authorized_keys
SSH absichern
Danach habe ich den direkten Root-Login per SSH deaktiviert und Passwort-Logins abgeschaltet. Der Server soll per SSH-Key erreichbar sein, aber nicht per Passwort durchprobiert werden können.
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
Nach Änderungen an der SSH-Konfiguration prüfe ich die Config, bevor der Dienst neu geladen wird. Das ist wichtig, weil man sich sonst im schlechtesten Fall selbst aussperrt.
sudo sshd -t
sudo systemctl reload ssh
sudo sshd -T | grep -Ei 'permitrootlogin|passwordauthentication|pubkeyauthentication|kbdinteractiveauthentication'
Zusätzlich läuft SSH nicht mehr auf dem Standardport 22, sondern auf einem eigenen Port. Das ist keine echte Sicherheitsmaßnahme wie SSH-Key-only, aber es reduziert stumpfes Bot-Rauschen auf Port 22.
Port <SSH_PORT>
Firewall aktivieren
Danach kam UFW. Die Grundregel ist simpel: eingehend wird alles blockiert, ausgehend ist erlaubt. Danach werden nur die Ports freigegeben, die der Server wirklich braucht.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow <SSH_PORT>/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
sudo ufw enable
Beim Kontrollblick zwei Wochen später sah der relevante Teil weiterhin so aus:
Status: active
Default: deny (incoming), allow (outgoing), disabled (routed)
<SSH_PORT>/tcp ALLOW IN Anywhere # SSH
80/tcp ALLOW IN Anywhere # HTTP
443/tcp ALLOW IN Anywhere # HTTPS
Automatische Sicherheitsupdates
Ich möchte nicht daran denken müssen, jede kleine Security-Aktualisierung sofort manuell einzuspielen. Dafür läuft unattended-upgrades. Es ersetzt keine regelmäßige Kontrolle, aber es reduziert das Risiko vergessener Sicherheitsupdates.
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades
sudo systemctl status unattended-upgrades --no-pager
Beim späteren Check lief der Dienst aktiv und es gab keine offenen Paketupdates:
unattended-upgrades.service: active (running)
apt list --upgradable
Listing... Done
Fail2ban als Zusatzschutz
Fail2ban ist für SSH ein sinnvoller zusätzlicher Schutz. Wenn eine IP wiederholt an der Anmeldung scheitert, kann sie automatisch gebannt werden. Bei SSH-Key-only sollte das im Normalfall kaum passieren, aber als zweite Schicht ist es trotzdem nützlich.
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
backend = systemd
[sshd]
enabled = true
port = <SSH_PORT>
Der aktuelle Status war unauffällig: ein aktives Jail für SSH, keine aktuell fehlgeschlagenen Logins und keine gebannten IPs.
Number of jail: 1
Jail list: sshd
Currently failed: 0
Currently banned: 0
Offene Ports prüfen
Nach Firewall und SSH-Konfiguration reicht es nicht, nur die Regeln anzuschauen. Ich will auch sehen, welche Dienste wirklich lauschen. Dafür ist ss -tulpn praktisch.
ss -tulpn
Beim Check waren die erwarteten Dienste sichtbar: Webserver auf 80 und 443, SSH auf dem eigenen Port und lokale DNS-Resolver auf 127.0.0.53 bzw. 127.0.0.54. Keine unerwarteten offenen Dienste.
Kontrolle nach zwei Wochen
Einige Zeit nach dem Setup habe ich den Server nochmal geprüft. Das war kein Pentest, sondern ein einfacher Reality Check: läuft die Firewall, sind Dienste kaputt, gibt es Updates, und arbeitet Fail2ban noch?
sudo ufw status verbose
sudo systemctl --failed
ss -tulpn
sudo fail2ban-client status sshd
sudo systemctl status unattended-upgrades --no-pager
apt list --upgradable
- UFW war aktiv.
- Es gab keine fehlgeschlagenen systemd-Units.
- Fail2ban lief mit dem SSH-Jail.
- Automatische Sicherheitsupdates liefen.
- Es gab keine offenen Paketupdates.
- Die sichtbaren Ports passten zum geplanten Setup.
Meine Checkliste
Für zukünftige VPS-Setups bleibt für mich diese kleine Reihenfolge hängen:
- System direkt aktualisieren.
- Eigenen Admin-User statt Root nutzen.
- SSH-Key für den Admin-User einrichten.
- Root-Login per SSH deaktivieren.
- Passwort-Login per SSH deaktivieren.
- Firewall aktivieren und nur nötige Ports öffnen.
- Automatische Sicherheitsupdates aktivieren.
- Fail2ban für SSH einrichten.
- Offene Ports und fehlerhafte Dienste regelmäßig prüfen.
Das Setup macht den VPS nicht unangreifbar, aber es nimmt die offensichtlichsten Risiken aus dem Weg. Für meine kleine statische Website ist das genau der richtige Startpunkt: erst eine saubere Basis, dann deployen.