EQVPS
DashboardLoslegen

Offene Ports auf einem VPS prüfen: was lauscht, was das Internet sieht und die Docker-Überraschung

Sieh dir jeden Port an, auf dem dein Server lauscht, finde den Prozess dahinter, scanne den Server von außen wie ein Angreifer und schließe, was du nicht brauchst. Mit dem Docker-Port, der trotz aktiver Firewall offen bleibt. Jede Zahl auf einem frischen Ubuntu-24.04-Server gemessen.

Ein offener und vergessener Port ist der klassische Weg in einen Server: eine Datenbank auf einer öffentlichen Adresse, ein Debug-Dashboard, ein Container, der einen Port veröffentlicht, den niemand veröffentlichen wollte. Die Prüfung dauert eine Minute, wenn du zwei Befehle und eine Falle kennst. Alles unten haben wir auf einem frischen Ubuntu-24.04-Server aus unserem Image ausgeführt und ihn von einem zweiten Rechner gescannt, die Ausgaben siehst du also genauso auf deinem eigenen Server.

1. Was lauscht

Der Befehl ist ss. Die Buchstaben stehen für TCP, UDP, lauschende Sockets, numerische Ports und den Prozessnamen:

sudo ss -tulpn

Auf einem frischen Server gibt er sechs Zeilen aus:

Netid State  Local Address:Port  Process
udp   UNCONN    127.0.0.54:53    systemd-resolve
udp   UNCONN 127.0.0.53%lo:53    systemd-resolve
tcp   LISTEN    127.0.0.54:53    systemd-resolve
tcp   LISTEN 127.0.0.53%lo:53    systemd-resolve
tcp   LISTEN       0.0.0.0:22    sshd
tcp   LISTEN          [::]:22    sshd

Entscheidend ist die Spalte Local Address. Sie sagt dir, wer sich verbinden kann:

AdresseWer sie erreicht
127.0.0.1:… oder 127.0.0.53Nur Programme auf diesem Server
0.0.0.0:…Jeder über IPv4, sofern die Firewall nicht blockt
[::]:…Jeder über IPv6 (meist auch IPv4)
10.0.0.5:… (eine bestimmte Adresse)Jeder, der diese Adresse erreicht

Der frische Server zeigt nach außen also genau eine Sache: SSH auf Port 22, über IPv4 und IPv6. Der DNS-Resolver auf 127.0.0.53 ist privat.

Um nur das aufzulisten, was das Internet sehen könnte, filtere die Loopback-Adressen heraus:

sudo ss -tlnp | awk 'NR>1 && $4 !~ /^(127\.|\[::1\])/ {print $4, $6}'

Führe das nach jeder Installation aus. Wir haben nginx, Docker und eine kleine Python-App installiert, und die Liste wuchs von 2 auf 10 Zeilen, darunter ein docker-proxy auf 0.0.0.0:8081 und ein containerd-Socket auf einem zufälligen localhost-Port.

2. Welcher Prozess einen Port belegt

Wenn ein Port belegt ist und du wissen willst, von wem:

sudo lsof -i :80 -P -n
sudo fuser 80/tcp
sudo ss -tlnp 'sport = :80'

lsof ist am lesbarsten. Für nginx zeigte es einen Master-Prozess als root und einen Worker als www-data, beide auf *:80, für IPv4 und IPv6. fuser gibt nur die PIDs aus, praktisch in Skripten. Wenn du den Port freimachen musst, stoppe den Dienst statt die PID zu killen, sonst startet systemd ihn neu: sudo systemctl stop nginx.

3. Was das Internet sieht

ss zeigt die Sicht des Servers. Die Sicht des Internets kann abweichen, weil eine Firewall dazwischensitzt oder weil ein Dienst an 127.0.0.1 gebunden ist. Für das echte Bild scanne den Server von einem anderen Rechner, deinem Laptop oder einem zweiten Server. Das Werkzeug ist nmap (apt install nmap, für Windows und macOS der Installer von nmap.org).

nmap your-server-ip
nmap -p- your-server-ip
nmap -p 22,80,443,3306 your-server-ip

Die erste Form prüft die 1.000 häufigsten Ports, die zweite alle 65.535, die dritte eine Liste. Auf unserem frischen Server, noch ohne Firewall:

Not shown: 999 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
Nmap done: 1 IP address (1 host up) scanned in 6.83 seconds

Der vollständige Scan aller 65.535 Ports dauerte 8,9 Sekunden und fand denselben einzigen Port. Geschlossene Ports antworten sofort mit einem Reset, deshalb geht das Scannen so schnell.

Drei Zustände zählen:

  • open: ein Programm hat die Verbindung angenommen. Das ist deine Angriffsfläche.
  • closed: der Server hat geantwortet, dass dort nichts lauscht. Sicher, bestätigt aber, dass der Server existiert und was er nicht betreibt.
  • filtered: keine Antwort. Eine Firewall hat das Paket verworfen. Der Scanner kann nicht sagen, ob dahinter ein Dienst steckt.

Für einen einzelnen Port ohne Installation meldet nc -zv server-ip 443 succeeded oder refused und hängt bei einem gefilterten Port bis zum Timeout. Für UDP hänge -sU an nmap an und rechne mit Wartezeit; auf unserem Server waren die drei üblichen UDP-Ports 53, 123 und 161 alle closed.

Ein Hinweis zu NAT-Tarifen: aus dem Internet ist nur der SSH-Port erreichbar, den wir an dich weitergeleitet haben. Ein Scan der geteilten Adresse zeigt unseren Rand, nicht deinen Server, und die übrigen Ports sind unerreichbar, egal was darauf lauscht. Bei einem Tarif mit eigener IPv4-Adresse verwaltest du jeden offenen Port selbst.

4. Schließen, was du nicht brauchst

Drei Wege, vom besten zum breitesten.

An localhost binden. Wenn nur Programme auf dem Server einen Dienst nutzen, lass ihn auf 127.0.0.1 lauschen. Wir starteten eine kleine Web-App mit --bind 127.0.0.1 8080: ss zeigte sie auf 127.0.0.1:8080, und nmap von außen meldete 8080/tcp closed. Für Datenbanken ist das die richtige Voreinstellung: Redis, MySQL und PostgreSQL lauschen unter Ubuntu ab Werk auf localhost, und unsere Anleitungen für Redis und MySQL lassen das so.

Den Dienst stoppen. sudo systemctl disable --now name entfernt den Listener dauerhaft. Prüfe mit ss, dass er weg ist.

Die Firewall einschalten. Erst SSH erlauben, dann das, was du anbietest, dann aktivieren:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw enable
sudo ufw status verbose

Der Scan von außen änderte sich komplett:

Not shown: 997 filtered tcp ports (no-response)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
8081/tcp open  blackice-icecap
Nmap done: 1 IP address (1 host up) scanned in 10.18 seconds

Jeder nicht freigegebene Port wechselte von closed zu filtered, und der vollständige Scan aller 65.535 Ports dauerte nun 110 Sekunden statt 8,9. Mehr Zeit pro Port für den Scanner, weniger Informationen über deinen Server. Unsere UFW-Anleitung behandelt Rate-Limits, Freigaben für eine einzelne IP und IPv6.

Aber sieh dir die dritte Zeile an.

5. Die Docker-Überraschung

Port 8081 blieb bei aktiver Firewall und ohne erlaubende Regel offen. Der Port gehört zu einem Container, den wir mit docker run -p 8081:80 nginx:alpine gestartet hatten. Docker fügt der Kernel-Firewall eigene Regeln hinzu, und die werden vor denen von ufw ausgewertet. Die Regel, die es auf unserem Server schrieb:

-A DOCKER ! -i docker0 -p tcp --dport 8081 -j DNAT --to-destination 172.17.0.2:80

Jedes Paket für Port 8081 wird in den Container weitergeleitet, bevor ufw mitreden kann. Das macht jeder Container mit -p oder einem ports:-Eintrag, und ss zeigt es ehrlich als docker-proxy auf 0.0.0.0:8081.

Die Lösung ist, nur auf localhost zu veröffentlichen:

docker rm -f web
docker run -d --name web -p 127.0.0.1:8081:80 nginx:alpine

In Compose schreibst du "127.0.0.1:8081:80" unter ports:. Nach der Änderung zeigte ss 127.0.0.1:8081, die Docker-Regel bekam -d 127.0.0.1/32, und der Scan von außen meldete 8081/tcp filtered. Stelle nginx als Reverse Proxy mit HTTPS davor, damit auf dem Server nur die Ports 22, 80 und 443 offen sind.

Checkliste nach jeder Änderung

  1. sudo ss -tulpn: ist jede Zeile mit 0.0.0.0 oder [::] etwas, das du freigeben wolltest?
  2. nmap server-ip vom Laptop: stimmen die offenen Ports überein?
  3. Eine Datenbank, ein Cache oder ein Admin-Panel auf einer öffentlichen Adresse: noch heute auf 127.0.0.1 oder hinter die Firewall.
  4. Jeder Docker-ports:-Eintrag: beginnt er mit 127.0.0.1:, wenn er nicht der öffentliche Web-Port ist?
  5. SSH für alle offen: ergänze fail2ban oder Login nur per Schlüssel.

Unter Windows Server ist dieselbe Prüfung Get-NetTCPConnection -State Listen, und die Regeln stehen in der Windows-Firewall. Jeder Linux-Tarif ab dem Nano für $3 hat eine Variante mit eigener IPv4-Adresse, und dort sieht die Welt, was du in ss siehst, abzüglich deiner Firewall.

FAQ

Welche Ports sind auf einem frischen VPS offen?

Auf unserem Ubuntu-24.04-Image genau einer: SSH auf Port 22. Sonst lauscht nur der lokale DNS-Resolver auf 127.0.0.53 und 127.0.0.54, den das Internet nicht erreicht. Ein Scan aller 65.535 TCP-Ports von einem anderen Rechner fand genau einen offenen Port.

Was ist der Unterschied zwischen closed und filtered?

Closed heißt, der Server hat geantwortet, dass dort nichts lauscht, der Scanner weiß es also sofort. Filtered heißt, es kommt gar keine Antwort, so verhält sich eine Firewall, die Pakete verwirft. Beides hält Eindringlinge fern, aber filtered verbirgt zusätzlich, welche Dienste es gibt, und macht einen vollständigen Scan auf unserem Server etwa zwölfmal langsamer.

Warum zeigt ss einen Port, den nmap als closed meldet?

Der Dienst lauscht nur auf 127.0.0.1, der Loopback-Adresse. Programme auf dem Server selbst können sich verbinden, von außen niemand. Achte in ss auf die Spalte Local Address: 127.0.0.1:8080 ist privat, 0.0.0.0:8080 oder [::]:8080 ist aus dem Internet erreichbar, sofern die Firewall es zulässt.

Ich habe ufw aktiviert, warum ist mein Docker-Port trotzdem offen?

Docker schreibt eigene Firewall-Regeln, die vor denen von ufw greifen. Ein mit -p 8081:80 gestarteter Container war auf unserem Server bei aktivem ufw und ohne Regel für 8081 von außen erreichbar. Veröffentliche stattdessen auf localhost, -p 127.0.0.1:8081:80, und stelle nginx oder Caddy für die öffentliche Seite davor.

Wie prüfe ich einen Port von meinem eigenen Rechner aus?

Für einen Port nc -zv server-ip 443, für die tausend häufigsten installierst du nmap und führst nmap server-ip aus. Bei einem NAT-Tarif antwortet aus dem Internet nur dein weitergeleiteter SSH-Port; alles andere ist bewusst nicht erreichbar.

Kommentare

Noch keine Kommentare. Sei der Erste.

Kommentar hinterlassen

Kommentare werden vor der Anzeige moderiert.