Eine schwarze Server-Blade in einem dunklen Rechenzentrum, umschlossen von einem leuchtenden smaragdgrünen Sechseck-Schild, eintreffende grüne Lichtpartikel zerbrechen an der Barriere
Sicherheitsanleitung

Einen neuen VPS in der ersten Stunde härten

Eine öffentliche IPv4-Adresse wird innerhalb weniger Minuten nach ihrem ersten Paket abgetastet, von Maschinen, die nie von Ihnen gehört haben und das auch nie werden. Das ist eine gute Nachricht: Fast alles, was auf einen neuen Server zielt, ist generisch, und eine bewusst investierte Stunde wehrt fast alles davon ab. Dieselbe Stunde, in der falschen Reihenfolge ausgeführt, sperrt Sie aus einer Maschine aus, in die sich niemand an Ihrer Stelle einloggen kann.

Wir übergeben Ihnen etwa 47 Sekunden nach Zahlungseingang eine Root-Shell und hören dann bewusst auf. Wir installieren keinen Agenten, wir verwalten nicht Ihre Firewall, und wir besitzen keine Kopie Ihrer Zugangsdaten – ein Schlüssel, den wir besitzen, ist ein Schlüssel, zu dessen Herausgabe wir gezwungen werden können, und dieses Prinzip zieht sich durch die gesamte Plattform. Die Konsequenz ist einfach und es lohnt sich, sie klar auszusprechen: Die Sicherheit Ihres Servers ist der Zustand, in dem Sie ihn während der ersten Stunde hinterlassen.

Was folgt, ist genau diese Stunde, in der Reihenfolge, in der wir sie selbst durchführen, auf Debian 13 und Ubuntu 24.04. Zwei Einstellungen erledigen den Großteil der Arbeit. Der Rest dieser Seite existiert wegen dreier Dinge, die korrekt aussehen, jeden abschließenden Tutorial-Check bestehen und trotzdem still und leise falsch sind: eine SSH-Drop-in-Konfiguration, die unbemerkt überschrieben wird, eine Port-Einstellung, die ein socket-aktivierter sshd ignoriert, und eine Container-Runtime, die Ports unterhalb Ihrer Firewall veröffentlicht. Jedes dieser Probleme hat schon jemanden erwischt, der alles andere richtig gemacht hat.

Was da wirklich an die Tür klopft

Beobachten Sie journalctl -u ssh auf einem Server, der seit einer Stunde online ist, und das Volumen wirkt beim ersten Anblick alarmierend. Das sollte es nicht. Was Sie sehen, ist die Hintergrundstrahlung des Internets: eine Handvoll Scan-Operationen, manche akademisch, manche kommerziell, manche kriminell, die den gesamten IPv4-Raum fortlaufend durchzählen und die Ergebnisse an Bots weiterreichen, die Zugangsdaten erraten. Ihre Adresse wurde erreicht, weil sie existiert, in numerischer Reihenfolge, und sie wird in ein paar Stunden erneut erreicht werden, was immer Sie tun.

Das verändert die Form des Problems auf nützliche Weise. Sie verteidigen sich nicht gegen einen Angreifer, der Sie gezielt ausgesucht hat und sich anpassen wird; Sie verteidigen sich gegen ein Skript mit einem festen Repertoire – root, admin, ubuntu, test, git, oracle, postgres und die zwanzigtausend Passwörter, die in Datenlecks aufgetaucht sind. Es hat keine Geduld, keine Kreativität und kein Interesse an einer Maschine, die nicht beim ersten Versuch antwortet. Passwort-Authentifizierung abzuschalten bremst diesen Angreifer nicht etwa nur aus. Es entfernt ihn vollständig vom Spielfeld.

Zwei Details lohnen sich zu wissen. Erstens ist IPv6 dramatisch ruhiger, weil sich ein /64 nicht durchkämmen lässt – aber sobald Ihr AAAA-Eintrag öffentlich ist oder die Adresse Ihrer Maschine in einem Mail-Header oder einem Certificate-Transparency-Log auftaucht, endet die Ruhe. Behandeln Sie IPv6 nie als Versteck; behandeln Sie es als kleineren Heuhaufen. Zweitens hat eine IPv4-Adresse eine Vergangenheit. Sie hatte einen Vormieter, und wenn dieser Vormieter einen Mailserver schlecht betrieben oder etwas gehostet hat, das gelistet wurde, erben Sie den Ruf, bis er verblasst. Wenn Mail für Sie wichtig ist, prüfen Sie die Adresse auf den üblichen Blocklisten, bevor Sie darauf aufbauen – das ist ein Fünf-Minuten-Check, der zwei Wochen Debugging der Zustellbarkeit erspart.

Die zwei Einstellungen, die neunzig Prozent der Arbeit erledigen

Fast jede echte Kompromittierung eines kleinen Servers beginnt an einer von zwei Stellen: einem Passwort, das sich erraten ließ, oder einem Dienst, der lauschte und das nicht hätte tun sollen. Die entsprechenden Abhilfen sind PasswordAuthentication no und eine Firewall mit der Standardregel drop. Sie sind unspektakulär, brauchen zusammen fünfzehn Minuten und sind mehr wert als alle anderen Maßnahmen auf dieser Seite zusammen.

Der Grund ist struktureller, nicht statistischer Natur. Beide sind standardmäßig geschlossen – sie schlagen in Richtung Sicherheit fehl. Ein sshd, der nur Schlüssel akzeptiert, lässt sich durch keine noch so hohe Zahl an Versuchen per Brute-Force knacken, weil es im Code keinen Pfad gibt, der ein Passwort akzeptiert. Eine Default-Deny-Firewall schützt auch Dienste, die Sie noch gar nicht installiert haben, einschließlich der Datenbank, die Sie in drei Monaten hinzufügen und dabei vergessen werden, an localhost zu binden. Alles andere in einer Hardening-Checkliste ist eine Aufzählung von Schlechtem: eine Liste konkreter Dinge, die man abschalten soll, und die immer nur so vollständig ist wie die Liste selbst.

Wenn Sie also nur einen Abschnitt lesen und dann den Tab schließen, lesen Sie diesen, führen Sie die Schritte 2 bis 5 unten aus, und betrachten Sie die Stunde als gut investiert. Der Rest ist wirklich nützlich und wirklich zweitrangig.

Wo die SSH-Konfiguration heute liegt – und die Falle darin

Unter Debian 13 und Ubuntu 24.04 beginnt /etc/ssh/sshd_config mit einer Zeile Include /etc/ssh/sshd_config.d/*.conf, und Cloud-Images liefern in diesem Verzeichnis eine Datei aus – meist 50-cloud-init.conf –, die PasswordAuthentication bereits setzt. Die Hauptdatei zu bearbeiten und eigene Direktiven unten anzuhängen, fühlt sich natürlich an und erzeugt eine Konfiguration, die nicht das tut, was sie zu tun scheint.

Die Regel ist das eine an sshd, das fast jeden überrascht: Für jedes Schlüsselwort gewinnt der zuerst gelesene Wert. Das ist das Gegenteil von fast jedem anderen Config-Merge-System, das Sie bisher benutzt haben. Das Include steht nahe am Anfang der Hauptdatei, sodass ein Drop-in vor dem Rumpf von sshd_config gelesen wird – und unter den Drop-ins entscheidet die alphabetische Reihenfolge. Eine Datei namens 10-hardening.conf schlägt 50-cloud-init.conf. Eine Datei namens 60-hardening.conf verliert dagegen, still und leise, und ein Neustart, der Erfolg meldet, wird Sie das nicht lehren.

Deshalb sollten Sie nie der Datei vertrauen, die Sie gerade geschrieben haben. Fragen Sie den Daemon, was er tatsächlich aufgelöst hat:

sshd -t                 # syntax check — silence means valid
sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|pubkeyauthentication|kbdinteractive|allowusers|port) '

sshd -T gibt die effektive Konfiguration aus, nachdem jedes Include, jeder Override und jeder Default aufgelöst wurde. Wenn diese Ausgabe passwordauthentication yes zeigt, dann ist Passwort-Authentifizierung aktiv, ganz gleich, was irgendeine Datei auf der Platte behauptet. Nichts anderes zählt als Nachweis.

Die zweite Falle gehört zur selben Familie. Ubuntu 24.04 startet sshd über Socket-Aktivierung: ssh.socket besitzt den lauschenden Port, und Port in sshd_config wird vollständig ignoriert. Prüfen Sie das mit systemctl is-enabled ssh.socket; ist es aktiviert und Sie wollen einen anderen Port, ändern Sie ihn mit systemctl edit ssh.socket und einem ListenStream=-Override – nicht in sshd_config, wo die Einstellung richtig aussieht und nichts bewirkt.

Weg von Port 22: Theater, aber billiges Theater

Seien wir ehrlich bei diesem Punkt, denn das Internet ist es nicht. sshd auf Port 2222 oder 47000 zu verschieben, hält null kompetente Angreifer auf. Ein vollständiger TCP-Scan eines einzelnen Hosts dauert Sekunden, der Dienst verrät sich selbst im Banner, und wer beschlossen hat, gezielt Sie anzugreifen, findet ihn, bevor der Kaffee kalt wird.

Was es tatsächlich bewirkt: Es reduziert Ihr Authentifizierungs-Log um etwa fünfundneunzig Prozent, und das hat echten Wert – es ist der Unterschied zwischen Logs, die Sie überfliegen, und Logs, die Sie tatsächlich lesen. Sichtbares Signal schlägt vergrabenes Signal. Wenn Sie überhaupt irgendetwas überwachen, ist ein ruhiges auth.log die mit Abstand billigste Methode, eine Anomalie sichtbar zu machen.

Die Kosten sind klein, aber real, und deshalb nennen wir es optional statt empfohlen. Sie werden den Port vergessen, wenn Sie in acht Monaten zurückkommen. Ein nicht standardmäßiger Port oberhalb von 1024 kann im Prinzip von einem unprivilegierten Prozess belegt werden, falls sshd jemals nicht lauscht. Restriktive ausgehende Firewalls in Kundennetzwerken blockieren ungewöhnliche Ports, sodass Sie gelegentlich Ihren eigenen Server nicht aus einem Büro oder einem Hotel erreichen können. Und auf einem socket-aktivierten System müssen Sie ihn an der richtigen Stelle ändern, wie im vorigen Abschnitt beschrieben. Tun Sie es, wenn Ihnen ruhige Logs wichtig sind. Tun Sie es nicht und fühlen Sie sich dann sicher, und tun Sie es niemals anstelle von SSH nur mit Schlüssel.

Default-Deny – und das Regelwerk, das wir tatsächlich einsetzen

Eine Firewall, die auflistet, was blockiert wird, ist ein Ablagesystem. Eine Firewall, die auflistet, was erlaubt wird, ist eine Sicherheitsmaßnahme. Dieser Unterschied ist das ganze Spiel, denn nur Letztere deckt auch den Dienst ab, den Sie nächsten Monat installieren, den Debug-Port, den Sie an einem Freitag geöffnet haben, und den Container, der sich entschlossen hat, sich selbst offenzulegen.

Auf unserer Plattform haben Sie zwei Schichten, und sie sind unabhängig voneinander. Der Edge-Filter ist optional, wird pro Server im Panel konfiguriert und auf dem Hypervisor durchgesetzt, sodass blockierter Traffic Ihren Gast überhaupt nie erreicht – nützlich für Layer-4-Regeln, die angewendet werden sollen, bevor Ihr Kernel auch nur einen Zyklus dafür aufwendet, und um einen kompromittierten Gast unerreichbar zu halten, während Sie daran arbeiten. Die Gast-Firewall gehört vollständig Ihnen: nftables, iptables, pf, was auch immer Ihr Image mitbringt. Wir fassen sie nie an. Nutzen Sie beide, wenn die Maschine wichtig ist; nutzen Sie zumindest die zweite immer.

Zwei Dinge im Regelwerk aus Schritt 5 verdienen eine Erklärung, weil die meisten kopierten Regelwerke sie falsch machen. Verwerfen Sie nicht das gesamte ICMP. Das fühlt sich ordentlich an und zerstört dabei die Path-MTU-Discovery, was die übelste Klasse von Fehlern überhaupt erzeugt: Kleine Anfragen funktionieren, große Antworten hängen, und nichts in Ihren Logs erwähnt die Firewall. Akzeptieren Sie mindestens destination-unreachable, time-exceeded und parameter-problem. Filtern Sie ICMPv6 nicht nach Typ, außer Sie kennen die Liste genau. IPv6 verlässt sich für Neighbour Discovery und Router Advertisement auf ICMPv6; blockieren Sie es pauschal, stirbt Ihre IPv6-Konnektivität auf eine Weise, die wie ein Routing-Problem aussieht. Das gesamte ICMPv6 auf einem einzelnen Host zu akzeptieren, ist ein vernünftiger Kompromiss, und genau das tut das Regelwerk weiter unten.

Eine Warnung, bevor Sie flush ruleset ausführen: Ist Docker installiert, entfernt diese Zeile auch die NAT- und Filterregeln, die Docker geschrieben hat, und das Container-Networking steht still, bis systemctl restart docker sie zurückbringt. Laden Sie zuerst Ihr Regelwerk, starten Sie danach Docker neu, und lesen Sie den nächsten Abschnitt, bevor Sie auch nur einen einzigen Container-Port veröffentlichen.

Die Ports, von denen Sie nicht wussten, dass sie offen sind

Fragen Sie die Maschine, worauf sie lauscht. Nicht das, von dem Sie glauben, es installiert zu haben – sondern das, was gerade jetzt gebunden ist:

ss -tulpn | grep -vE '127\.0\.0\.1|\[::1\]'

Alles, was diesen Filter übersteht, ist von irgendwo anders als der Maschine selbst erreichbar. Auf einem Standard-Image sind die üblichen Funde rpcbind auf 111 (nichts, was Sie betreiben, braucht das), ein exim4-Listener, der von der Grundinstallation übrig geblieben ist, und ein systemd-resolved-Stub, der auf Loopback harmlos ist und ein offener Resolver, wenn er es nicht ist. Die gefährlichen kommen später hinzu, mit Software, die Sie absichtlich installiert haben: PostgreSQL auf 0.0.0.0:5432, weil ein Tutorial gesagt hat, listen_addresses zu bearbeiten, Redis ohne Passwort, weil Redis den größten Teil seines Bestehens standardmäßig kein Passwort hatte, ein Elasticsearch-Knoten, ein Prometheus-Exporter, ein Jupyter-Notebook. Jedes davon war schon mehrfach der erste Schritt einer echten Kompromittierung.

Jetzt die Falle, die sorgfältige Leute erwischt. Docker fragt Ihre Firewall nicht um Erlaubnis. Wenn Sie -p 5432:5432 schreiben, fügt Docker DNAT-Regeln in die PREROUTING-Chain der nat-Tabelle ein, die der Kernel auswertet, bevor Ihre input-Chain das Paket überhaupt zu sehen bekommt; der Traffic wird dann an den Container weitergeleitet. Ihre Default-Deny-Regel für input wird nicht befragt, ufw status zeigt den Port als geschlossen an, und die Datenbank steht im öffentlichen Internet. Das ist dokumentiertes Docker-Verhalten, das seit einem Jahrzehnt so besteht, und es hat schon eine enorme Zahl an Datenbanken offengelegt.

Die Lösung ist eine einzige Zeichenkette, und es ist die Gewohnheit, die sich zu bilden lohnt:

# wrong — reachable from the entire internet, whatever your firewall says
docker run -p 5432:5432 postgres

# right — bound to loopback, reachable only through an SSH tunnel or a proxy
docker run -p 127.0.0.1:5432:5432 postgres

Holen Sie sich schließlich eine Meinung von außen. Ein Portscan vom Server aus verrät Ihnen, was der Kernel denkt; ein Scan von woanders verrät Ihnen, was die Welt sieht, und das ist die einzige Zahl, die zählt. Führen Sie nmap -Pn -p- <your-ip> von Ihrem Laptop aus aus, nicht von der Maschine, und vergleichen Sie das Ergebnis mit der Liste, die Sie erwartet hatten.

Automatische Updates: einschalten – und zwar wirklich

Das Zeitfenster, in dem kleine Server kompromittiert werden, ist nicht der Zero-Day. Es sind die vier Wochen zwischen der Veröffentlichung einer CVE mit funktionierendem Proof of Concept und dem nächsten Mal, dass Sie sich zufällig einloggen. Angriffs-Tooling nimmt einen neuen Remote-Bug innerhalb von Tagen auf; eine Maschine, die Sie patchen, „wenn Sie dazu kommen“, ist das gesamte Intervall über exponiert, und jeder ehrliche Betreiber weiß, wie lang dieses Intervall in Wirklichkeit ist.

Der Einwand gegen automatische Updates ist die Angst vor Breakage, und es lohnt sich, sie ernst zu nehmen – und dann einzugrenzen. Beschränken Sie die Automatisierung auf das Security-Segment Ihrer Distribution, wo Maintainer Fixes in die paketierte Version zurückportieren, statt neue Upstream-Releases auszuliefern. Ein Debian-Sicherheitsupdate für openssl ist ein gepatchter Build derselben Version, die Sie bereits betreiben; das Risiko, dass es das Verhalten ändert, ist weit kleiner als das Risiko, ein Remote-Loch einen Monat lang offen zu lassen. Feature-Upgrades bleiben manuell, wo sie hingehören.

Der Teil, den Leute überspringen, ist der Neustart. Ein gepatchtes libssl auf der Platte nützt dem Prozess nichts, der die alte Version beim Start eingebunden hat, und ein Kernel-Update bewirkt gar nichts, bis Sie in ihn hineinbooten. Akzeptieren Sie entweder einen unbeaufsichtigten Neustart in einem Fenster, das Sie selbst wählen, oder installieren Sie needrestart und lassen Sie es Ihnen mitteilen, welche Dienste gegen gelöschte Bibliotheken laufen – aber tun Sie eines von beidem. „Automatische Updates sind aktiviert“, während uptime 340 Tage anzeigt, ist eine bequeme Illusion, und es ist die häufigste, die wir sehen.

fail2ban, CrowdSec oder gar nichts

fail2ban liest Ihre Logs, bemerkt wiederholte Fehlschläge von einer Adresse und sperrt sie für eine Weile. CrowdSec macht dasselbe und teilt die Urteile über ein Netzwerk von Teilnehmern, sodass Sie eine Adresse blockieren können, die sich anderswo bereits daneben benommen hat, bevor sie Sie erreicht. Beides ist gute Software. Keines von beiden tut das, was die meisten Leute bei einem SSH-Server mit ausschließlich Schlüssel-Login annehmen.

Sobald PasswordAuthentication auf no steht, kann eine SSH-Brute-Force nicht erfolgreich sein. Nicht „ist unwahrscheinlich“ – es gibt keinen Codepfad dafür. Eine Adresse nach fünf Fehlschlägen zu sperren, verhindert deshalb nichts; es reduziert Log-Volumen und eine verschwindend geringe Menge CPU. Das ist ein echter Nutzen, nur eben kein Sicherheitsnutzen, und der Kompromiss ist nicht kostenlos: Ein schlecht geschriebener Jail, der das falsche Log beobachtet, hat schon mehr Administratoren aus ihren eigenen Servern ausgesperrt, als er je Angreifer ausgesperrt hat.

Wo sich diese Werkzeuge tatsächlich verdient machen, ist eine Ebene höher, bei den Diensten, die Sie wirklich exponieren: ein Login-Formular, ein WordPress-Admin, eine API mit Rate-Limits, ein Mailserver mit SMTP AUTH. Die akzeptieren tatsächlich Passwörter, sie sind per Brute-Force angreifbar, und eine Bannliste ist genau die richtige Maßnahme. Unser Urteil ist also eng und spezifisch. Lassen Sie den SSH-Jail weg. Setzen Sie CrowdSec oder fail2ban vor das, was ein Passwortfeld hat. Und für welches Sie sich auch entscheiden, setzen Sie zuerst Ihre eigene Management-Adresse auf die Whitelist – ignoreip existiert für den Abend, an den Sie sich sonst aus den falschen Gründen erinnern werden.

Die Maschine dazu bringen, Veränderungen zu melden

Prävention ist das, was Sie in einer Stunde schaffen können. Detektion ist das, was Ihnen sagt, dass die Stunde nicht gereicht hat. Sie muss nicht aufwendig sein, und auf einem einzelnen Server decken drei günstige Maßnahmen das meiste ab.

Behalten Sie die Logs. Auf vielen Images liegt das Journal in /run und verflüchtigt sich beim Neustart, was bedeutet, dass die Aufzeichnung eines Vorfalls genau in dem Neustart verschwindet, der ihm folgt. /var/log/journal anzulegen ist eine Ein-Zeilen-Lösung und die wertvollste Sache in diesem Abschnitt.

Lassen Sie sich über Logins informieren. Eine Zeile in /etc/ssh/sshrc, die bei jedem Sitzungsstart logger auslöst, kostet nichts und liefert Ihnen eine saubere, mit grep durchsuchbare Aufzeichnung getrennt vom eigenen Geplapper von sshd. Eine Falle, die Leute erwischt: sshd führt ~/.ssh/rc statt /etc/ssh/sshrc aus, wenn der Benutzer eine solche Datei besitzt, sodass die systemweite Datei ausgerechnet für das Konto übersprungen wird, das am ehesten ein angepasstes Dotfile hat. Wenn Sie einen Hook brauchen, der nicht überschattet werden kann, verwenden Sie stattdessen pam_exec.

Wissen Sie, wie das Dateisystem am ersten Tag aussah. AIDE zeichnet Hashes Ihrer Binärdateien, Bibliotheken und Unit-Dateien auf und meldet, was sich seitdem verändert hat. Der Haken ist grundlegend und wird meist ignoriert: Eine Datenbank, die auf der Maschine gespeichert ist, die sie überwacht, kann von demjenigen neu erzeugt werden, der sie kompromittiert hat, und danach meldet die Prüfung für immer „keine Änderungen“. Kopieren Sie die Datenbank von der Maschine herunter, oder notieren Sie zumindest ihren Hash anderswo, dann lohnen sich die zwanzig Minuten für das Werkzeug. Bleibt sie, wo sie ist, ist es nur ein Sicherheits-Placebo.

Das allgemeine Prinzip lohnt sich, für sich genannt zu werden: Das Log, dem Sie nicht vertrauen können, ist das auf der kompromittierten Maschine. Alles, worauf Sie sich wirklich verlassen wollen – ein Journal, eine Integritätsdatenbank, ein Backup – sollte eine Kopie irgendwo haben, das derselbe Angreifer nicht kontrolliert. Ein zweiter kleiner Server in einer anderen Jurisdiktion ist eine legitime Antwort darauf, und ein Fünf-Dollar-Server reicht dafür aus.

Was das hier nicht leistet

Alles oben ist Perimeterschutz, und es lohnt sich, bei der Grenze genau zu sein, damit Sie eine verschlossene Haustür nicht mit einem Tresor verwechseln.

Es schützt keine Daten auf einer laufenden Maschine. Ein gehärteter Kernel und eine geschlossene Firewall sind irrelevant für jeden mit Hypervisor-Zugriff, und für den Inhalt des RAM, solange die Maschine läuft. Wenn Ihre Sorge der Festplatte gilt, wenn der Server ausgeschaltet, beschlagnahmt oder außer Betrieb genommen wird, dann ist das Festplattenverschlüsselung, und das ist ein anderes Verfahren mit einem anderen Fehlerbild – siehe VPS-Festplatte mit LUKS verschlüsseln.

Es macht Sie nicht anonym. Ein Server kann tadellos gehärtet sein und trotzdem verraten, wem er gehört – durch einen WHOIS-Eintrag, einen wiederverwendeten SSH-Key, ein Analytics-Tag, einen SSH-Client, der ohne Zwischenstation von zu Hause aus verbindet, oder ein Zertifikat, das zwei Identitäten miteinander verknüpft. Mit Monero zu bezahlen und sich dann von der eigenen Adresse aus einzuloggen, macht die Zahlung zunichte. Dieses Fehlerbild hat seine eigene Seite: die Fehler, die Sie deanonymisieren.

Es repariert nicht Ihre Anwendung. Eine SQL-Injection, ein unauthentifizierter Admin-Endpunkt oder eine Abhängigkeit mit Backdoor kümmert sich nicht um Ihre sshd-Einstellungen. Die meisten Kompromittierungen gut betriebener Server kommen über den Port, den Sie bewusst und absichtlich für einen selbst geschriebenen oder installierten Dienst geöffnet haben.

Es ist kein Backup. Ransomware, rm -rf mit einer Variable, die leer war, und ein fehlgeschlagenes Upgrade enden alle gleich. Machen Sie eine Kopie, legen Sie sie woanders ab, und stellen Sie einmal daraus wieder her, bevor Sie es wirklich brauchen – dieselbe Disziplin, die einen Umzug zu einem anderen Anbieter überlebbar macht, macht auch einen schlechten Dienstag überlebbar.

Nichts davon ist ein Argument gegen die Stunde. Es ist ein Argument dafür, genau zu wissen, was die Stunde gebracht hat.

  1. Mit einem Schlüssel deployen, niemals mit einem Passwort

    Erzeugen Sie das Schlüsselpaar auf Ihrer eigenen Maschine und fügen Sie die öffentliche Hälfte in das Deploy-Formular ein; das Image installiert ihn, und Sie werden nie ein Root-Passwort haben, das Sie verlieren könnten. Wenn Sie von einem als cloud-init markierten Image aus deployen, können Sie stattdessen die gesamte Konfiguration der ersten Stunde als User-Data übergeben – bis zu 64 KiB – und die Maschine kommt bereits gehärtet hoch.

    # on your laptop, not on the server
    ssh-keygen -t ed25519 -a 100 -C "$(whoami)@laptop-cvh"
    cat ~/.ssh/id_ed25519.pub        # paste this into the deploy form

    Verwenden Sie ed25519, es sei denn, etwas in Ihrer Toolchain verweigert das, dann ist RSA mit 4096 Bit in Ordnung. Schützen Sie den privaten Schlüssel mit einer Passphrase und laden Sie ihn in einen Agenten; eine Schlüsseldatei ohne Passphrase auf einem Laptop ist ein Passwort, das auf den Monitor geschrieben wurde. Derselbe Schlüsselsatz wird in den Rescue-Modus eingespielt, was Schritt 4 wiederherstellbar macht.

  2. Öffnen Sie die zweite Sitzung, bevor Sie irgendetwas anfassen

    Das ist nicht optional, und das ist keine Paranoia. Von hier an verändern Sie den Daemon, über den Sie verbunden sind, und die Firewall, die Ihnen den Zugriff darauf erlaubt. Halten Sie eine Sitzung offen und untätig als Rettungsleine zurück in die Maschine, und machen Sie jede Änderung in einer anderen. Ist eine Änderung falsch, ist die offene Sitzung immer noch authentifiziert und kann sie rückgängig machen; eine neue Verbindung würde abgelehnt.

    # terminal A — the rope. Log in and leave it alone.
    ssh -i ~/.ssh/id_ed25519 root@<server-ip>
    
    # terminal B — where every command below runs.
    ssh -i ~/.ssh/id_ed25519 root@<server-ip>

    Testen Sie jede Änderung, indem Sie eine dritte Verbindung öffnen, niemals, indem Sie die neu verbinden, in der Sie gerade arbeiten. Schlägt die dritte Verbindung fehl, haben Sie immer noch zwei funktionierende Shells und ein Problem statt einer Krise.

  3. Legen Sie das Konto an, das Sie tatsächlich verwenden werden

    Root über SSH ist genau für eine Stunde praktisch. Danach gibt Ihnen ein benanntes Konto mit sudo eine Audit-Spur, schützt Sie davor, dass ein vertippter Befehl mit vollen Rechten läuft, und erlaubt es Ihnen, ein kompromittiertes Konto zu deaktivieren, ohne die Maschine zu deaktivieren.

    adduser --disabled-password --gecos "" deploy
    install -d -m 0700 -o deploy -g deploy /home/deploy/.ssh
    cp /root/.ssh/authorized_keys /home/deploy/.ssh/authorized_keys
    chown deploy:deploy /home/deploy/.ssh/authorized_keys
    chmod 0600 /home/deploy/.ssh/authorized_keys
    usermod -aG sudo deploy
    
    # a long random password, stored in your manager, used only by sudo
    passwd deploy

    Setzen Sie dieses Passwort. Ein sudo-Konto, dessen Passwort nie gesetzt wurde, kann sudo nicht benutzen, und das zu entdecken, nachdem Sie den Root-Login deaktiviert haben, ist die klassische Art, sich selbst auszusperren, obwohl jede Datei korrekt ist. Prüfen Sie das, bevor Sie weitermachen: aus einem neuen Terminal ssh deploy@<server-ip>, dann sudo -v. Beides muss funktionieren.

  4. Schreiben Sie den SSH-Drop-in, dann fragen Sie den Daemon, was er gelesen hat

    Ein nummerierter Drop-in, der früh sortiert, schlägt alles, was das Cloud-Image mitgebracht hat, gemäß der Reihenfolge-Regel oben. Schreiben Sie ihn, prüfen Sie die Syntax, lesen Sie die effektive Konfiguration zurück, und laden Sie erst dann neu.

    cat > /etc/ssh/sshd_config.d/10-hardening.conf <<'EOF'
    PermitRootLogin no
    PasswordAuthentication no
    KbdInteractiveAuthentication no
    PubkeyAuthentication yes
    AuthenticationMethods publickey
    PermitEmptyPasswords no
    AllowUsers deploy
    MaxAuthTries 3
    LoginGraceTime 20
    X11Forwarding no
    AllowAgentForwarding no
    AllowTcpForwarding no      # remove this line if you use ssh -L / -D tunnels
    ClientAliveInterval 300
    ClientAliveCountMax 2
    EOF
    chmod 0644 /etc/ssh/sshd_config.d/10-hardening.conf
    
    sshd -t                                    # silence means the syntax is valid
    sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|allowusers) '
    systemctl reload ssh

    Lesen Sie diese sshd -T-Ausgabe vor dem Neuladen, nicht danach. Sie muss permitrootlogin no und passwordauthentication no zeigen. Tut sie das nicht, wird Ihre Datei von einer überschrieben, die früher sortiert – ls /etc/ssh/sshd_config.d/ und benennen Sie Ihre so um, dass sie weiter hinten steht. Öffnen Sie jetzt ein drittes Terminal und loggen Sie sich als deploy ein. Erst wenn das funktioniert, sollten Sie die Rettungsleine kappen.

  5. Laden Sie eine Default-Deny-Firewall

    nftables wird bei beiden Distributionen mitgeliefert und ersetzt das iptables-Regelwerk durch eine einzige lesbare Datei. Passen Sie die akzeptierten Ports an die Dienste an, die Sie tatsächlich betreiben – die Liste unten geht von SSH und einem Webserver aus, und sonst nichts.

    apt install -y nftables
    cat > /etc/nftables.conf <<'EOF'
    #!/usr/sbin/nft -f
    flush ruleset
    
    table inet filter {
      chain input {
        type filter hook input priority filter; policy drop;
    
        ct state established,related accept
        ct state invalid drop
        iif lo accept
    
        # ICMP must live: dropping it blackholes path-MTU discovery.
        ip protocol icmp icmp type { echo-request, echo-reply, destination-unreachable, time-exceeded, parameter-problem } accept
        ip6 nexthdr icmpv6 accept
    
        tcp dport 22 ct state new accept
        tcp dport { 80, 443 } ct state new accept
    
        limit rate 5/minute burst 5 packets log prefix "nft-drop: " level info
      }
      chain forward { type filter hook forward priority filter; policy drop; }
      chain output  { type filter hook output  priority filter; policy accept; }
    }
    EOF
    
    nft -c -f /etc/nftables.conf              # check before you commit to it
    systemctl enable --now nftables
    nft list ruleset | head -40

    Ist Docker installiert, entfernt flush ruleset auch die Regeln von Docker: Führen Sie danach systemctl restart docker aus und bestätigen Sie, dass Ihre Container noch antworten. Dann, von Ihrem Laptop aus, nmap -Pn -p- <server-ip>, und prüfen Sie, dass die Liste der offenen Ports genau den Ports entspricht, die Sie gerade erlaubt haben – nicht mehr und nicht weniger.

  6. Schalten Sie unbeaufsichtigte Sicherheitsupdates ein

    Nur das Security-Segment, mit einem Neustartfenster, das Sie selbst gewählt haben, statt eines, das Sie ständig aufschieben werden. Wählen Sie eine Stunde, die für Ihre Nutzer ruhig ist und nicht zur vollen Stunde liegt, damit Sie nicht mit dem Cron aller anderen kollidieren.

    apt install -y unattended-upgrades needrestart
    cat > /etc/apt/apt.conf.d/51-cvh-auto <<'EOF'
    // Debian. On Ubuntu, replace the two Origins-Pattern lines with:
    //   "${distro_id}:${distro_codename}-security";
    Unattended-Upgrade::Origins-Pattern {
      "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
      "origin=Debian,codename=${distro_codename},label=Debian-Security";
    };
    Unattended-Upgrade::Automatic-Reboot "true";
    Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
    Unattended-Upgrade::Automatic-Reboot-Time "04:17";
    Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
    APT::Periodic::Update-Package-Lists "1";
    APT::Periodic::Unattended-Upgrade "1";
    EOF
    
    unattended-upgrade --dry-run --debug | tail -25
    systemctl status unattended-upgrades --no-pager

    Ist ein unbeaufsichtigter Neustart wirklich inakzeptabel, setzen Sie es auf "false" und lassen Sie sich von needrestart -b melden, welche Dienste gegen gelöschte Bibliotheken laufen und ob ein neuerer Kernel installiert ist – und handeln Sie danach. Nicht akzeptabel ist, keins von beidem zu tun.

  7. Schließen Sie, was lauscht, und prüfen Sie von außen

    Zählen Sie auf, was an etwas anderes als Loopback gebunden ist, entfernen Sie, was Sie nicht nutzen, und bestätigen Sie das Ergebnis von einer Maschine, die nicht diese hier ist.

    ss -tulpn | grep -vE '127\.0\.0\.1|\[::1\]'
    
    # the usual leftovers on a base image
    systemctl disable --now rpcbind.socket rpcbind 2>/dev/null
    apt purge -y exim4-base exim4-config exim4-daemon-light 2>/dev/null
    apt autoremove --purge -y
    
    # what each running unit is allowed to reach
    systemd-analyze security --no-pager | head -20

    Für alles, was weiterlaufen muss, aber kein Publikum braucht – eine Datenbank, ein Cache, ein Admin-Panel, ein Metrics-Exporter –, binden Sie es in seiner eigenen Konfiguration an 127.0.0.1 und erreichen es über einen SSH-Tunnel: ssh -L 5432:127.0.0.1:5432 deploy@<server-ip>. Das ist strikt besser, als einen Port zu öffnen und zu hoffen, dass die eigene Authentifizierung des Dienstes solide ist, und es ist das Muster, zu dem Sie standardmäßig greifen sollten.

  8. Halten Sie die Baseline fest und schalten Sie die Alarme scharf

    Zehn Minuten, die sich nur an dem Tag auszahlen, an dem etwas schiefläuft – und genau das ist der Tag, an dem Sie nichts davon aus dem Gedächtnis rekonstruieren können.

    # persistent journal, so a reboot stops erasing the evidence
    mkdir -p /var/log/journal
    systemd-tmpfiles --create --prefix /var/log/journal
    systemctl restart systemd-journald
    
    # a clean, greppable line per SSH session
    cat > /etc/ssh/sshrc <<'EOF'
    logger -t ssh-login "user=$USER from=${SSH_CONNECTION%% *} tty=${SSH_TTY:-none}"
    EOF
    
    # file-integrity baseline — then get the database off the machine
    apt install -y aide
    aideinit
    mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
    sha256sum /var/lib/aide/aide.db     # copy this hash somewhere else
    
    last -n 20 ; lastb -n 20            # who got in, and who tried

    Schließen Sie ab, indem Sie, getrennt vom Server, vier Dinge notieren: den SSH-Host-Key-Fingerabdruck aus ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub, den AIDE-Hash von oben, die Ports, die Sie bewusst geöffnet haben, und wo der private Schlüssel liegt. Diese Notiz ist es, die aus einem schlechten Morgen eine Checkliste statt einer Ermittlung macht.

Vergleich

Die Maßnahmen, bewertet danach, was sie wirklich bringen

Jede Maßnahme der ersten Stunde geprüft an den zwei Fragen, die entscheiden, ob sie ihren Platz verdient: was sie tatsächlich verhindert – und was nicht, was auch immer die Tutorials suggerieren.
MaßnahmeWas sie verhindertWas sie nicht verhindertAufwandUrteil
SSH nur mit Schlüssel (PasswordAuthentication no)Jeden Bot im Internet, der Zugangsdaten errät – dauerhaft und schon konstruktionsbedingtJeden, der Ihren privaten Schlüssel besitzt, oder einen Fehler in sshd selbst5 Minuten, einmaligNicht verhandelbar
Default-Deny-Firewall (nftables)Dienste, von denen Sie vergessen hatten, dass sie lauschen, und jeden, den Sie später versehentlich installierenAngriffe auf die Ports, die Sie bewusst geöffnet haben10 Minuten, einmaligNicht verhandelbar
Unbeaufsichtigte SicherheitsupdatesDas n-Day-Fenster – die Wochen zwischen einem öffentlichen Exploit und Ihrem nächsten LoginZero-Days und alles, was einen Neustart braucht, den Sie nie einplanen5 Minuten plus ein NeustartfensterNicht verhandelbar
Benanntes Benutzerkonto mit sudo statt rootVertippte Befehle mit vollen Rechten und Prozesse, die grundlos als root laufenEine lokale Rechteausweitung in den Händen von jemandem, der bereits drin ist3 MinutenLohnt sich
Dateiintegritäts-Baseline (AIDE)Stille Änderungen an System-Binärdateien, Bibliotheken und Unit-DateienRein gar nichts, wenn die Datenbank auf der Maschine bleibt, die sie überwacht20 Minuten plus Speicherung außerhalb der MaschineLohnt sich, wenn die Maschine wichtig ist
SSH von Port 22 wegverlegenEtwa 95 % Ihres Authentifizierungs-Log-VolumensJeden, der einen Portscan durchführt – also jeden, der zählt2 Minuten, plus den Abend, an dem Sie den Port vergessenOptional, für ruhige Logs
fail2ban / CrowdSec auf sshdWiederholungstäter und die CPU-Zeit, die sie bei Ihnen verschwendenNichts, sobald Passwort-Authentifizierung deaktiviert ist10 Minuten, plus ein echtes AussperrrisikoBei SSH weglassen; bei Ihrer Anwendung einsetzen
FAQ

Fragen, die eine Antwort verdienen

Wie lange nach dem Deployment beginnt das Scannen?

Typischerweise Minuten. Internetweite Scanner durchkämmen fortlaufend den gesamten IPv4-Raum, sodass eine frische Adresse beim nächsten Durchlauf erreicht wird, ganz gleich, was darauf läuft. Gehen Sie davon aus, dass Sie ab dem Moment abgetastet werden, in dem die Maschine ihr erstes Paket beantwortet – deshalb passiert die Härtung in der ersten Stunde und nicht am ersten Wochenende.

Brauche ich noch fail2ban, wenn der Passwort-Login deaktiviert ist?

Bei SSH nein. Mit PasswordAuthentication no gibt es keinen Codepfad, den eine Brute-Force gewinnen könnte, also verhindert das Sperren nach fünf Fehlschlägen nichts – es reduziert Log-Rauschen, was etwas wert ist, aber keine Sicherheit bedeutet. Wo diese Werkzeuge tatsächlich hingehören, ist vor allem, was wirklich ein Passwort akzeptiert: ein Web-Login-Formular, ein Admin-Panel, SMTP AUTH. Wenn Sie eins installieren, setzen Sie zuerst Ihre eigene Adresse auf die Whitelist.

ufw, firewalld oder nftables?

Jedes davon, solange die Standardregel drop lautet und Sie verstehen, was Sie da bereitgestellt haben. ufw ist am freundlichsten und schreibt unter der Haube nftables-Regeln auf aktuellem Debian und Ubuntu. Reines nftables ist eine einzige lesbare Datei, die Sie diffen und versionieren können, deshalb nutzen wir es. Die Wahl spielt eine weit geringere Rolle als die Standardregel – und keine der drei ändert etwas daran, dass Docker unterhalb aller drei Ports veröffentlicht.

Sollte ich SSH von Port 22 wegverlegen?

Nur für ruhigere Logs. Es hält keinen kompetenten Angreifer auf – ein vollständiger Scan dauert Sekunden, und das Banner identifiziert den Dienst. Es entfernt tatsächlich den größten Teil des Rauschens aus Ihrem Authentifizierungs-Log, wodurch echte Anomalien sichtbar werden. Behandeln Sie es als Log-Hygiene, niemals als Sicherheitsmaßnahme, und prüfen Sie, ob Ihr sshd socket-aktiviert ist, bevor Sie es ändern: Auf Ubuntu 24.04 wird die Port-Direktive in sshd_config ignoriert, und der Port gehört ssh.socket.

Werden automatische Updates meine Seite um vier Uhr morgens lahmlegen?

Beschränkt auf das Security-Segment, sehr selten. Diese Pakete sind zurückportierte Fixes für die Version, die Sie bereits betreiben, keine neuen Upstream-Releases. Das realistische Risiko ist der Neustart, nicht der Patch – wählen Sie also das Fenster selbst, setzen Sie Automatic-Reboot-WithUsers auf false, damit gewartet wird, solange jemand eingeloggt ist, und wenn der Dienst wirklich nicht unbeaufsichtigt neu starten kann, führen Sie needrestart -b nach Zeitplan aus und handeln Sie danach. Die einzige unhaltbare Position ist automatische Updates bei einer Uptime, die in Jahren gemessen wird.

Ich habe mich selbst ausgesperrt. Welche Möglichkeiten habe ich?

Booten Sie den Server über das Panel in den Rescue-Modus. Er startet eine Alpine-Umgebung im RAM mit denselben SSH-Keys wie Ihr Konto und Ihrer Festplatte ausgehängt unter /dev/vda, sodass Sie sie einhängen, den sshd-Drop-in oder die Firewall-Datei reparieren, aushängen und neu starten können. Der Rescue-Boot selbst rührt nichts auf der Festplatte an. Der Host-Key-Fingerabdruck des Rescue-Systems unterscheidet sich von Ihrem normalen – das ist zu erwarten und kein Abfangversuch.

Ist es eine gute Idee, stattdessen Lynis oder ein CIS-Hardening-Skript laufen zu lassen?

Als Audit ja, als Ersatz nein. Lynis ist eine wirklich nützliche zweite Meinung und findet Dinge, die diese Seite nicht erwähnt. Automatisierte CIS-Remediation-Skripte sind eine andere Sache: Sie wenden Hunderte Änderungen an, die für eine Flotte von Firmen-Arbeitsplätzen gedacht sind, von denen mehrere einen Server auf Weisen kaputt machen, die sich Wochen später nur schwer zurückverfolgen lassen. Machen Sie die Stunde zuerst von Hand, damit Sie verstehen, was Ihre Maschine tut, und lassen Sie dann einen Auditor laufen und lesen Sie seine Befunde einen nach dem anderen.

Macht Härtung meinen Server anonym?

Nein, und die beiden zu verwechseln, ist ein häufiger und teurer Fehler. Härtung kontrolliert, wer hineinkommt; Anonymität kontrolliert, wer erkennen kann, dass es Ihnen gehört. Ein perfekt abgeriegelter Server verrät die Eigentümerschaft trotzdem über einen WHOIS-Eintrag, einen wiederverwendeten SSH-Key, ein Analytics-Tag oder einen Admin-Login von Ihrer privaten Adresse aus. Mit Monero zu bezahlen und sich dann direkt über Ihre eigene Verbindung einzuloggen, macht die Zahlung vollständig zunichte – das wird behandelt in den Fehlern, die Sie deanonymisieren.

Deploy your offshore server.

Wählen Sie eine Region. Wählen Sie einen Plan. Fügen Sie einen Schlüssel ein. Zahlen Sie. Die nächsten 47 Sekunden gehen auf uns.