EQVPS
DashboardAan de slag

Open poorten op een VPS controleren: wat luistert, wat het internet ziet en de Docker-verrassing

Bekijk elke poort waarop je server luistert, vind het proces erachter, scan de server van buitenaf zoals een aanvaller dat zou doen en sluit wat je niet nodig hebt. Inclusief de Docker-poort die openblijft, ook met de firewall aan. Elk getal gemeten op een verse Ubuntu 24.04-server.

Een open en vergeten poort is de klassieke weg naar binnen: een database op een publiek adres, een debug-dashboard, een container die een poort publiceerde die niemand wilde publiceren. Controleren kost een minuut als je twee commando's en één valkuil kent. We deden alles hieronder op een verse Ubuntu 24.04-server van ons image en scanden hem vanaf een tweede machine, dus de uitvoer is wat je op je eigen server ziet.

1. Wat luistert er

Het commando is ss. De letters staan voor TCP, UDP, luisterende sockets, numerieke poorten en de procesnaam:

sudo ss -tulpn

Op een verse server geeft het zes regels:

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

De kolom die telt is Local Address. Die vertelt wie kan verbinden:

AdresWie het bereikt
127.0.0.1:… of 127.0.0.53Alleen programma's op deze server
0.0.0.0:…Iedereen via IPv4, tenzij de firewall blokkeert
[::]:…Iedereen via IPv6 (en meestal ook IPv4)
10.0.0.5:… (een specifiek adres)Iedereen die dat adres kan bereiken

De verse server stelt dus precies één ding open: SSH op poort 22, via IPv4 en IPv6. De DNS-resolver op 127.0.0.53 is privé.

Om alleen te tonen wat het internet zou kunnen zien, filter je de loopback-adressen eruit:

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

Draai dit na elke installatie. We installeerden nginx, Docker en één kleine Python-app, en de lijst groeide van 2 naar 10 regels, waaronder een docker-proxy op 0.0.0.0:8081 en een containerd-socket op een willekeurige localhost-poort.

2. Welk proces een poort bezet

Als een poort bezet is en je wilt weten door wie:

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

lsof leest het prettigst. Voor nginx toonde het een masterproces als root en een worker als www-data, beide op *:80, voor IPv4 en IPv6. fuser geeft alleen de PID's, handig in scripts. Moet je de poort vrijmaken, stop dan de dienst in plaats van de PID te killen, anders start systemd hem opnieuw: sudo systemctl stop nginx.

3. Wat het internet ziet

ss toont het zicht van de server. Het zicht van het internet kan afwijken, omdat er een firewall tussen zit of omdat een dienst aan 127.0.0.1 is gebonden. Voor het echte beeld scan je de server vanaf een andere machine, je laptop of een tweede server. Het gereedschap is nmap (apt install nmap, of de installer van nmap.org op Windows en macOS).

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

De eerste vorm controleert de 1.000 meest gebruikte poorten, de tweede alle 65.535, de derde een lijst. Op onze verse server, nog zonder 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

De volledige scan van 65.535 poorten duurde 8,9 seconden en vond dezelfde enige poort. Gesloten poorten antwoorden meteen met een reset, daarom gaat scannen zo snel.

Drie toestanden tellen:

  • open: een programma accepteerde de verbinding. Dit is je aanvalsoppervlak.
  • closed: de server antwoordde dat daar niets luistert. Veilig, maar het bevestigt dat de server bestaat en wat hij niet draait.
  • filtered: geen antwoord. Een firewall gooide het pakket weg. De scanner weet niet of er een dienst achter zit.

Voor één poort zonder iets te installeren meldt nc -zv server-ip 443 succeeded of refused, en blijft hij op een gefilterde poort hangen tot de time-out. Voor UDP voeg je -sU aan nmap toe en reken je op wachten; op onze server waren de drie gebruikelijke UDP-poorten, 53, 123 en 161, closed.

Een opmerking voor NAT-abonnementen: vanaf het internet is alleen de SSH-poort bereikbaar die we naar je doorsturen. Een scan van het gedeelde adres toont onze rand, niet je server, en de andere poorten zijn onbereikbaar, wat er ook op luistert. Met een abonnement met een eigen IPv4-adres beheer je elke open poort zelf.

4. Sluit wat je niet nodig hebt

Drie manieren, van beste naar breedste.

Aan localhost binden. Gebruiken alleen programma's op de server een dienst, laat hem dan op 127.0.0.1 luisteren. We startten een kleine webapp met --bind 127.0.0.1 8080: ss toonde hem op 127.0.0.1:8080 en nmap van buitenaf meldde 8080/tcp closed. Voor databases is dit de juiste standaard: Redis, MySQL en PostgreSQL luisteren op Ubuntu standaard op localhost, en onze handleidingen voor Redis en MySQL laten dat zo.

De dienst stoppen. sudo systemctl disable --now naam haalt de listener definitief weg. Controleer met ss dat hij weg is.

De firewall aanzetten. Sta eerst SSH toe, dan wat je aanbiedt, en zet hem dan aan:

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

De scan van buitenaf veranderde volledig:

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

Elke niet-toegestane poort ging van closed naar filtered, en de volledige scan van 65.535 poorten duurde nu 110 seconden in plaats van 8,9. Meer tijd per poort voor de scanner, minder informatie over je server. Onze UFW-handleiding behandelt rate limits, één IP toestaan en IPv6.

Maar kijk naar de derde regel.

5. De Docker-verrassing

Poort 8081 bleef open met de firewall aan en zonder regel die hem toestond. Die poort hoort bij een container die we startten met docker run -p 8081:80 nginx:alpine. Docker voegt eigen regels toe aan de kernelfirewall, en die worden vóór die van ufw beoordeeld. De regel die het op onze server schreef:

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

Elk pakket voor poort 8081 wordt naar de container doorgestuurd voordat ufw iets te zeggen heeft. Elke container met -p of een ports:-regel doet dit, en ss toont het eerlijk als docker-proxy op 0.0.0.0:8081.

De oplossing is alleen op localhost publiceren:

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

Schrijf in Compose "127.0.0.1:8081:80" onder ports:. Na de wijziging toonde ss 127.0.0.1:8081, kreeg de Docker-regel -d 127.0.0.1/32 erbij en meldde de scan van buitenaf 8081/tcp filtered. Zet nginx als reverse proxy ervoor voor de publieke kant, met HTTPS, zodat alleen de poorten 22, 80 en 443 op de server open staan.

Checklist na elke wijziging

  1. sudo ss -tulpn: is elke regel met 0.0.0.0 of [::] iets wat je wilde openstellen?
  2. nmap server-ip vanaf je laptop: kloppen de open poorten?
  3. Een database, cache of beheerpaneel op een publiek adres: verplaats het vandaag naar 127.0.0.1 of achter de firewall.
  4. Elke Docker-ports:-regel: begint die met 127.0.0.1: als het niet de publieke webpoort is?
  5. SSH open voor iedereen: voeg fail2ban of inloggen alleen met een sleutel toe.

Op Windows Server is dezelfde controle Get-NetTCPConnection -State Listen, en de regels staan in de Windows Firewall. Elk Linux-abonnement, vanaf de Nano voor $3, heeft een versie met een eigen IPv4-adres, en daar ziet de wereld wat jij in ss ziet, min je firewall.

FAQ

Welke poorten staan open op een verse VPS?

Op ons Ubuntu 24.04-image één: SSH op poort 22. Verder luistert alleen de lokale DNS-resolver op 127.0.0.53 en 127.0.0.54, die het internet niet kan bereiken. Een scan van alle 65.535 TCP-poorten vanaf een andere machine vond precies één open poort.

Wat is het verschil tussen een closed en een filtered poort?

Closed betekent dat de server antwoordde dat daar niets luistert, dus de scanner weet het meteen. Filtered betekent helemaal geen antwoord, wat een firewall doet als hij pakketten weggooit. Beide houden indringers buiten, maar filtered verbergt ook welke diensten er zijn en maakt een volledige scan op onze server zo'n twaalf keer trager.

Waarom toont ss een poort die nmap closed noemt?

De dienst luistert alleen op 127.0.0.1, het loopback-adres. Programma's op de server zelf kunnen verbinden, van buitenaf niemand. Kijk in ss naar de kolom Local Address: 127.0.0.1:8080 is privé, 0.0.0.0:8080 of [::]:8080 is bereikbaar vanaf het internet als de firewall het toelaat.

Ik heb ufw aangezet, waarom staat mijn Docker-poort nog open?

Docker schrijft eigen firewallregels die vóór die van ufw worden toegepast. Een container gestart met -p 8081:80 was op onze server van buitenaf bereikbaar met ufw actief en zonder regel voor 8081. Publiceer op localhost, -p 127.0.0.1:8081:80, en zet nginx of Caddy ervoor voor de publieke kant.

Hoe controleer ik een poort vanaf mijn eigen computer?

Gebruik nc -zv server-ip 443 voor één poort, of installeer nmap en draai nmap server-ip voor de duizend meest gebruikte poorten. Op een NAT-abonnement antwoordt vanaf het internet alleen je doorgestuurde SSH-poort; de rest is bewust onbereikbaar.

Reacties

Nog geen reacties. Wees de eerste.

Laat een reactie achter

Reacties worden gemodereerd voordat ze verschijnen.