Die ersten Stunden im Netz: Was an einem neuen VPS anklopft
Teil 1 der Reihe Server im Netz: SSH-Log, tcpdump-Mitschnitt und eine Falle in Caddy zeigen, was an einem frischen VPS anklopft. Mit echten Zahlen, der Panne beim Mitschnitt und neuen Subdomains, die nach zwei Sekunden besucht werden.
Geprüft am 05.11.2026 · für tcpdump 4.99.4, OpenSSH 9.6p1, Caddy 2.11.7
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Ein neuer Server ist nicht lange allein. Kaum hat er eine öffentliche Adresse, klopfen Programme an, die das ganze Internet nach offenen Diensten, schwachen Passwörtern und vergessenen Dateien absuchen. Wie schnell das geht und wonach sie suchen, lässt sich mit Bordmitteln messen. Diese Anleitung zeigt, wie Sie das SSH-Log auswerten, eingehende Verbindungsversuche mit tcpdump mitschneiden, mit Caddy eine Falle für Aufrufe per IP-Adresse aufstellen und messen, wie schnell neue Subdomains gefunden werden. Dazu kommen die echten Zahlen vom Testserver der Reihe, und eine Panne beim Mitschnitt, die viele Anleitungen verschweigen.
Dies ist Teil 1 der Reihe „Server im Netz“. Als Beispiel dient ein netcup-VPS mit Ubuntu und Docker. Die Reihe baut darauf Schritt für Schritt einen öffentlichen Server mit der Domain sedv-lab.de auf, mit Firewall, Website, eigenem DNS, Mail und Überwachung.
Voraussetzungen
- Ein VPS mit Ubuntu, frisch installiert oder schon in Betrieb
- Zugang per SSH mit Schlüssel und root-Rechten
tcpdump, unter Ubuntu mitapt install tcpdump- Für die Falle und die Messung der Subdomains: Caddy aus Teil 4 mit JSON-Logs
Schritt 1: Das SSH-Log auswerten
Jeder Versuch, sich per SSH anzumelden, landet in /var/log/auth.log. Bots probieren Benutzernamen durch, und sshd schreibt dazu Zeilen wie Invalid user admin from … oder Connection closed by authenticating user root … [preauth]. Einen ersten Überblick geben zwei Befehle:
grep -E "Invalid user|Connection closed by (authenticating|invalid) user" /var/log/auth.log | wc -l
grep -oE "Invalid user [^ ]+" /var/log/auth.log | sort | uniq -c | sort -rn | head
Für genaue Zahlen zählen Sie jede Verbindung nur einmal, denn sshd schreibt pro Versuch mehrere Zeilen. Dafür eignet sich die Prozessnummer in eckigen Klammern hinter sshd, die je Verbindung eindeutig ist. Wir haben das mit einem kleinen Python-Skript gemacht, das je Prozessnummer Zeit, Benutzer und Adresse merkt.

Auf dem Testserver stand der erste Eintrag im SSH-Log um 20:22:38 Uhr, der erste fremde Versuch kam um 20:29:20 Uhr, also 6 Minuten und 42 Sekunden später. In den ersten Stunden kamen nur vereinzelte Versuche. Am Abend darauf, gut 24 Stunden nach der Installation, stieg die Zahl sprunghaft auf mehrere hundert je Stunde und blieb dort. Zwei Adressen allein machten 71 Prozent der 5442 Versuche aus, sie probierten unermüdlich weiter.
Wichtig ist, was nicht im Log stand: kein einziger Versuch mit Passwort. Die Anmeldung mit Passwort war von Anfang an abgeschaltet. Der Server bot gar keine Passwortabfrage an, die Bots trennten die Verbindung. Alle 802 erfolgreichen Anmeldungen liefen mit Schlüssel und kamen von eigenen Rechnern.
Verifizieren: sshd -T | grep -E "passwordauthentication|permitrootlogin" zeigt die wirksamen Einstellungen. Bei sshd gilt der erste Wert, der gelesen wird, und Dateien aus /etc/ssh/sshd_config.d/ werden über die Include-Zeile am Anfang zuerst eingelesen. Ein Eintrag weiter unten in der sshd_config wirkt deshalb nicht, wenn eine dieser Dateien etwas anderes sagt. Verlassen Sie sich auf sshd -T, nicht auf einen Blick in die Datei. Auf dem Testserver erlaubte die Einstellung übrigens noch die Anmeldung als root mit Schlüssel, das ändert Teil 2.
Schritt 2: Verbindungsversuche mitschneiden
SSH ist nur ein Port von vielen. Welche anderen abgefragt werden, zeigt ein Mitschnitt aller eingehenden Verbindungsversuche. Dafür reicht das erste Paket jeder TCP-Verbindung, das SYN, dazu UDP und ICMP. Ein Lauf über einige Stunden mit stündlich neuer Datei:
mkdir -p /root/mitschnitt
systemd-run --unit mitschnitt -p RuntimeMaxSec=16200 \
/usr/bin/tcpdump -Z root -U -i eth0 -Q in -n -s 256 -G 3600 \
-w "/root/mitschnitt/syn-%Y%m%d-%H%M.pcap" \
"not host EIGENE-IP and not host EIGENE-IPV6 and ((tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn) or (ip6 and ip6[6]==6 and (ip6[53] & 0x12) == 0x02) or (udp and not src port 53 and not src port 123) or icmp or icmp6)"
-G 3600 beginnt jede Stunde eine neue Datei, -Q in nimmt nur eingehende Pakete, -s 256 speichert nur den Anfang jedes Pakets. Die eigenen Adressen fallen heraus, damit der eigene Zugriff die Zahlen nicht verfälscht. tcp[tcpflags] wirkt nur bei IPv4. Für IPv6 prüft der zweite Ausdruck die Flags direkt im Paket, das klappt nur ohne zusätzliche IPv6-Erweiterungsköpfe, was bei SYN-Paketen der Normalfall ist.
Hier lag die Panne. Unser erster Mitschnitt lief ohne -Z root und brach nach genau einer Stunde ab, im Journal stand:
tcpdump: …/syn-20261104-1532.pcap: Permission denied
tcpdump gibt nach dem Start seine root-Rechte ab und läuft als Benutzer tcpdump weiter. Die erste Datei konnte es noch anlegen, beim Wechsel zur zweiten fehlte in /root die Berechtigung. Mit -Z root behält es die Rechte. Alternativ schreiben Sie in ein Verzeichnis außerhalb von /root, das dem Benutzer tcpdump gehört, etwa /var/tmp/mitschnitt nach chown tcpdump:tcpdump.
Verifizieren: Nach etwas mehr als einer Stunde liegen zwei Dateien im Verzeichnis, und systemctl is-active mitschnitt meldet active.
Schritt 3: Den Mitschnitt auswerten
for f in /root/mitschnitt/*.pcap; do tcpdump -nn -r "$f" 'tcp or udp' 2>/dev/null; done \
| grep -oE "> [^ ]+\.[0-9]+:" | grep -oE "[0-9]+:$" | sort | uniq -c | sort -rn | head -20
Die Zeile zählt die Zielports der mitgeschnittenen TCP- und UDP-Pakete, ICMP hat keine Ports. Im Test liefen über viereinhalb Stunden 8378 Pakete von 2047 Absendern ein, die 1529 verschiedene Ports abfragten.

Neben Web und SSH stand Telnet auf Port 23 ganz vorn, ein Dienst, der in Routern und Kameras noch oft offen ist. Dahinter folgten typische Ports für Verwaltungsoberflächen wie 8080 und 8443, Windows-Freigaben auf 445, Remote Desktop auf 3389, Mail auf 25, VNC auf 5900 und Datenbanken wie MySQL auf 3306 und SQL Server auf 1433. Jeder dieser Dienste, der versehentlich offen ist, wird also binnen Stunden gefunden.
Verifizieren: tcpdump -nn -r DATEI | head zeigt einzelne Zeilen mit Absender und Zielport.
Schritt 4: Eine Falle für Aufrufe per IP
Scanner rufen den Server über seine IP-Adresse auf, mit erfundenen Namen oder mit den Namen, die sie aus den Zertifikaten kennen. Ein Block in Caddy, der alles beantwortet, was keiner Site zugeordnet ist, schreibt diese Aufrufe in ein eigenes Log:
:80 {
log {
output file /falle/zugriffe.json
format json
}
respond 404
}
Caddy protokolliert in diesem Block alle Anfragen auf Port 80, auch die automatischen Weiterleitungen der eigenen Sites auf HTTPS. Die Zahlen unten enthalten deshalb auch normale Aufrufe, die nur auf HTTPS umgeleitet wurden. Läuft Caddy in Docker, ist /falle ein Pfad im Container, eingebunden aus einem Verzeichnis auf dem Host.
jq -r '.request.uri' /falle/zugriffe.json | sort | uniq -c | sort -rn | head -20
In gut 24 Stunden kamen 1572 Anfragen von 336 Absendern. Gesucht wurde nach Dateien mit Zugangsdaten wie /.env und /.git/config, nach Statusseiten wie /server-status, nach Verwaltungsoberflächen von cPanel und WHM, nach dem Docker-Registry-Verzeichnis /v2/_catalog, nach GraphQL-Schnittstellen und nach einer bekannten Lücke in Microsoft Exchange. 110 Anfragen kamen ganz ohne Browserkennung. Bemerkenswert war ein Name: caddy.sedv-lab.de wurde 468 Mal aufgerufen, fast nur von einer einzigen Adresse in einer Cloud. Den Namen gibt es nicht, durch den Wildcard-Eintrag aus Teil 3 löste er aber auf. Wer einen Wildcard-Eintrag setzt, macht jeden geratenen Namen erreichbar.
Verifizieren: curl -s -o /dev/null -w '%{http_code}\n' http://IHRE-IP/ liefert 404, und der Aufruf erscheint im Log der Falle.
Schritt 5: Wie schnell neue Namen auffallen
Jedes Zertifikat von Let's Encrypt steht in öffentlichen Logs, den Certificate-Transparency-Logs. Wer die mitliest, kennt jeden neuen Namen sofort. Ob das jemand tut, zeigt ein Vergleich: Wann hat Caddy das Zertifikat gespeichert, und wann kam der erste fremde Abruf? Die Zertifikate liegen im Datenverzeichnis von Caddy unter caddy/certificates/, je Name ein Ordner. Die Änderungszeit der Datei .crt ist ungefähr der Zeitpunkt, zu dem Caddy das Zertifikat gespeichert hat, nach einer Erneuerung entsprechend später. Im CT-Log steht ein Vorzertifikat sogar schon kurz davor.

Bei acht von elf Namen kam der erste fremde Besuch nach einer oder zwei Sekunden, beim langsamsten nach 69 Sekunden. Einer der ersten Besucher nannte sich CT-WP-Scan und fragte sofort nach WordPress-Pfaden wie /wp-json/ und /xmlrpc.php. Die Subdomains standen nirgends, nur der Wildcard-Eintrag machte sie auflösbar. Alles spricht für die CT-Logs als Quelle. Ein Name, der ein Zertifikat bekommt, ist also öffentlich, sobald es ausgestellt ist. Verlassen Sie sich nie darauf, dass ein Dienst unter einem unbekannten Namen unentdeckt bleibt.
Verifizieren: Legen Sie eine neue Subdomain mit Zertifikat an und sehen Sie ins Log der Site. Die ersten fremden Zugriffe kommen meist binnen Sekunden.
Was daraus folgt
- SSH nur mit Schlüssel, wie im Test, macht die Flut erfolglos, auch wenn sie weiter ankommt. Teil 2 legt mit einer Firewall und einer Teergrube für Bots nach.
- Alles, was nicht öffentlich sein muss, lauscht nur auf
127.0.0.1oder steht hinter der Firewall. Der Mitschnitt zeigt, dass jeder offene Port abgefragt wird. - Neue Dienste sind ab der ersten Sekunde öffentlich. Anmeldung und Absicherung kommen vor dem Zertifikat, nicht danach.
- Wiederkehrende Angreifer lassen sich automatisch sperren, das zeigt Teil 17 mit CrowdSec.
Typische Fehler
| Meldung oder Beobachtung | Ursache und Lösung |
|---|---|
tcpdump: …pcap: Permission denied nach der ersten Stunde | tcpdump hat die root-Rechte abgegeben. -Z root setzen oder ein Verzeichnis für den Benutzer tcpdump nehmen. |
| Zahlen viel zu hoch, eigene Adresse ganz oben | Eigene Zugriffe nicht ausgeschlossen. not host EIGENE-IP im Filter, bei der Auswertung eigene Adressen herausrechnen. |
| Doppelt so viele SSH-Versuche wie erwartet | Mehrere Logzeilen je Verbindung gezählt. Je Prozessnummer nur einmal zählen. |
Änderung in der sshd_config wirkt nicht | Eine Datei in sshd_config.d setzt den Wert vorher. Mit sshd -T prüfen. |
Häufige Fragen
Ist das gefährlich?
Die Versuche selbst sind Grundrauschen, das jeden Server trifft. Gefährlich wird es, wenn ein Dienst schwach geschützt offen steht: ein Passwort für SSH, eine Datenbank ohne Anmeldung, eine .env-Datei im Webverzeichnis.
Hilft es, SSH auf einen anderen Port zu legen?
Es verringert das Rauschen im Log, denn viele Bots fragen nur Port 22. Schutz bringt es nicht, der Mitschnitt zeigt, dass auch ungewöhnliche Ports abgefragt werden. Teil 2 nutzt den Effekt anders: Auf Port 22 wartet dort eine Teergrube.
Darf ich so mitschneiden?
Auf dem eigenen Server zur Absicherung in der Regel ja. Bei TCP nimmt der Filter oben nur das erste Paket auf, UDP und ICMP aber vollständig bis 256 Byte je Paket, samt Inhalt. Die Dateien enthalten IP-Adressen, löschen Sie sie nach der Auswertung.
Fazit
Ein Server im Netz wird binnen Minuten gefunden, neue Namen binnen Sekunden. Das ist kein Grund zur Panik, aber einer für Sorgfalt von Anfang an. Mit den Befehlen aus dieser Anleitung sehen Sie selbst, was an Ihrem Server anklopft. Achten Sie beim Mitschnitt auf -Z root, sonst endet er nach der ersten Stunde.


