Cómo comprobar puertos abiertos en Linux: local, red y firewall

comprobar puertos

Antes de nada: abierto ≠ expuesto (y por qué te puede engañar la prueba)

Hablar de “puertos abiertos” como si fuera una lista fija se queda corto. Un puerto listening en el sistema no siempre está expuesto hacia fuera. Por ejemplo, puedo tener un servicio escuchando en 127.0.0.1:8080; para el host está abierto, pero desde Internet es invisible. En mi experiencia, los falsos positivos y negativos suelen venir de aquí:

  • Loopback: servicios que sólo escuchan en 127.0.0.1 o ::1.
  • IPv6 vs IPv4: si el servicio escucha sólo en IPv6 y escaneas en IPv4, parecerá “cerrado”. A la inversa, igual.
  • Firewall/NAT/perímetro: el host escucha, pero un firewall (local o perimetral), un Security Group en la nube o el router filtra o redirige.
  • Rutas y políticas: zonas de firewalld, políticas DROP, listas por interfaz o reglas por estado de conexión.

Mi regla de oro: mirar el problema desde tres ángulos —dentro del host, desde fuera de la red y en el firewall/perímetro— y cuadrar la foto con evidencias de los tres.


Desde dentro del host: identifica qué escucha realmente (ss, lsof)

Cuando quiero rapidez y detalle, prefiero ss frente a netstat. ss es más ágil, filtra mejor y muestra el owner del socket sin dolores.

ss -lntup: lectura rápida y filtros útiles

Lista puertos TCP en escucha, sin reverse DNS, con procesos:

sudo ss -lntup

Parámetros clave:

  • -l (listening), -n (no resolver), -t (TCP), -u (UDP), -p (proceso).
  • -4 / -6 para separar IPv4/IPv6.
  • Filtros muy prácticos:
# Filtrar por puerto 22
sudo ss -ltnp '( sport = :22 )'

# Ver solo IPv6 en escucha
sudo ss -ltn6

# Ver UDP "en escucha" (recordatorio: UDP no establece sesión)
sudo ss -lnup

Combinado con lsof para ver ficheros y sockets:

sudo lsof -iTCP -sTCP:LISTEN -P -n
sudo lsof -iUDP -P -n | head

En mi caso, antes de tocar reglas, corro ss y confirmo que realmente hay algo escuchando. Evita perseguir “fantasmas” de firewall cuando en realidad no hay servicio.

Diferencias prácticas ss vs netstat

netstat (paquete net-tools) está deprecado en muchas distros; funciona, pero ss (en iproute2) ofrece filtros modernos, mejor rendimiento y más detalle por socket. Si tu documentación antigua menciona netstat -tulpn, tradúcelo mentalmente a ss -lntup.

Consejo: si trabajas con contenedores o namespaces, asegúrate de auditar el namespace correcto:

# Ver sockets de red del contenedor (usa el PID del proceso principal)
sudo nsenter -t <PID> -n ss -lntup

# O con netns nominal
sudo ip netns exec <ns> ss -lntup

Desde fuera de la red: valida exposición real con nmap (TCP/UDP)

Para confirmar qué es alcanzable de verdad, me voy a otra máquina y paso nmap. Esto evita autoengaños del tipo “aquí lo veo abierto, así que desde fuera debe estarlo”.

Estados open/closed/filtered y falsos negativos

  • open: una aplicación responde al puerto.
  • closed: ningún servicio escuchando; el host responde con rechazo (p. ej., RST).
  • filtered: un firewall filtra; no hay respuesta concluyente (pérdida de paquetes, ICMP bloqueado…).

Si un host “no responde al ping”, puede ser normal; usa -Pn para escanear igualmente. Para IPv6, añade -6.

Ejemplos: rango completo, servicio concreto y UDP

Escaneo TCP de todos los puertos (rápido y útil):

nmap -p- -sS -Pn --reason 198.51.100.10

Detección de servicio/versión en puertos típicos:

nmap -p 22,80,443 -sS -sV --reason 198.51.100.10

UDP (más lento y propenso a “open|filtered”):

sudo nmap -sU --top-ports 200 --reason 198.51.100.10
# O focalizado:
sudo nmap -sU -p 53,123,161 --reason 198.51.100.10

En mi práctica, combino -sS (TCP) y -sU (UDP) cuando necesito la foto completa y pruebo también -6 para evitar falsos negativos si el servicio sólo escucha en IPv6.


Firewall y perímetro: ufw, firewalld/nftables para cuadrar la foto

Un check local dice “escucha”, nmap desde fuera dice “closed/filtered”… toca revisar la política de firewall.

ufw (Ubuntu/Debian)

sudo ufw status verbose
sudo ufw allow 22/tcp
sudo ufw delete allow 8080/tcp

Ojo con el perfil IPv6 (fichero /etc/ufw/ufw.conf, IPV6=yes) y con reglas por aplicación (/etc/ufw/applications.d/).

firewalld (RHEL/Fedora) sobre nftables

# Zona activa y su interfaz
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --zone=public --list-all

# Abrir puerto en runtime y después hacerlo permanente
sudo firewall-cmd --zone=public --add-port=8080/tcp
sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
sudo firewall-cmd --reload

Trampa típica: abrir en la zona equivocada o tener la interfaz en otra zona.

nftables (reglas finas)

sudo nft list ruleset
# Ejemplo de permitir SSH
sudo nft add rule inet filter input tcp dport 22 ct state new accept

Cuando “cuadro la foto”, reviso ufw/firewalld/nft porque un DROP silencioso convierte puertos abiertos en “filtered” a ojos de nmap.

Perímetro/Nube: no olvides Security Groups (AWS, Azure, GCP), ACLs, WAF y el router ISP. Puedes tener todo OK en el host y seguir bloqueado fuera.


Casos que confunden: loopback, IPv6, contenedores y puertos efímeros

  • Loopback: servicios locales (dashboards, Prometheus, etc.) oyen en 127.0.0.1 por seguridad. Para exponerlos, cambia bind address a 0.0.0.0/:: y abre en firewall.
  • Sólo IPv6: si ves :::443 en ss y nmap (IPv4) marca “closed”, prueba nmap -6.
  • Contenedores/Namespaces: Docker publica puertos con DNAT; el contenedor puede escuchar en 0.0.0.0:80 dentro pero no estar mapeado hacia el host. Verifica con:
docker ps
docker inspect <container> | jq '.[0].HostConfig.PortBindings'
ss -lntup | grep -E 'docker|containerd'

En Kubernetes, mira Service/Ingress y NetworkPolicy.

Puertos efímeros: son puertos cliente (rango ip_local_port_range) que verás en estados ESTAB/TIME-WAIT; no son “servidores en escucha” pero confunden si filtras mal:

cat /proc/sys/net/ipv4/ip_local_port_range
cat /proc/sys/net/ipv6/ip_local_port_range 2>/dev/null || echo "usa el mismo rango que IPv4"

Yo suelo recordar: “las herramientas muestran ángulos distintos del mismo problema”; sólo cruzando host + red + firewall saco la verdad.


Checklist rápida: comandos y pasos en 60 segundos

  1. Local: sudo ss -lntup → ¿existe el puerto? ¿en IPv4/IPv6? ¿en qué bind?
  2. Red: desde otra máquina → nmap -p- -sS -Pn --reason <tu_IP> y, si toca, -6 y/o -sU.
  3. Firewall:
    • Ubuntu: sudo ufw status verbose
    • RHEL/Fedora: sudo firewall-cmd --get-active-zones && --list-all
    • General: sudo nft list ruleset
  4. Perímetro/Nube: revisa SG/ACL/WAF/router.
  5. Reprueba: vuelve a lanzar nmap y valida.

Errores comunes y cómo evitarlos

  • Escanear IPv4 cuando el servicio sólo escucha en IPv6. Solución: nmap -6.
  • Abrir el puerto en la zona equivocada de firewalld. Solución: confirma interfaz↔zona.
  • Confiar en netstat y obviar ss. Solución: adopta ss y sus filtros.
  • Olvidar el perímetro (NAT/SG). Solución: diagrama simple del flujo y valida hop a hop.
  • Interpretar UDP como “cerrado” cuando es “filtered”. Solución: usa --reason, prueba puertos concretos y paciencia.

Sobre Comprobar puertos abiertos

Comprobar puertos abiertos de verdad significa mirar el sistema desde tres perspectivas: dentro del host, desde fuera y en el firewall/perímetro. En mi práctica, ss me da la realidad local con rapidez; nmap (desde otra máquina) me dice qué es realmente alcanzable; y el repaso a ufw/firewalld/nftables me permite cuadrar la foto, incluyendo IPv6, contenedores y puertos efímeros. Con ese triángulo, los “misterios” desaparecen.


FAQs

¿ss o netstat?
ss es más moderno, rápido y con mejores filtros. Úsalo por defecto; deja netstat para sistemas antiguos.

¿Por qué nmap dice “filtered”?
Porque no recibe respuestas concluyentes: hay firewall/NAT. Revisa reglas y usa --reason/-Pn.

¿Cómo verifico IPv6?
Asegúrate de que el servicio escucha en ::/[::1], usa ss -6 y escanea con nmap -6.

¿Qué pasa con puertos efímeros y NAT?
Los efímeros son puertos cliente temporales; no confundir con listening. Con NAT, valida tanto la IP interna como la pública y las reglas de port forwarding.

¿Cómo pruebo UDP de forma fiable?
Es más difícil: combina nmap -sU con pruebas de aplicación (p. ej., consultas DNS a 53/UDP) y observa open|filtered.

Opinión Personal

Hablar de “comprobar puertos abiertos” como si fuera una checklist es engañarse. Un puerto en listening no siempre está expuesto y ahí se pierden horas. Mi postura es clara: si no lo puedes alcanzar desde fuera, no existe para el usuario. Por eso empiezo dentro del host con ss (más rápido y preciso que netstat) para saber qué realmente escucha, separo IPv4/IPv6 y verifico procesos. Después, desde otra máquina, valido con nmap (TCP y, cuando toca, UDP) para distinguir entre open, closed y filtered. Y cierro el triángulo mirando el firewall: ufw, firewalld/nftables o la política del perímetro en la nube.

Lo impopular: muchos fallos no son “del puerto”, son de alcance. Contenedores sin port mapping, servicios atados a 127.0.0.1, reglas en la zona equivocada, o el clásico “solo escucha en IPv6”. También veo confusiones con puertos efímeros: son clientes, no servicios; no deberían salir en tu inventario de exposición.

Mi criterio operativo es simple y me ha ahorrado tickets: host → red → firewall, en ese orden, y repetir. Cada cambio, un escaneo. Cada apertura, documentada. Menos adivinar, más evidencias. ¿Resultado? Menos sustos, más tiempo para lo importante.

Ahora te leo: ¿cómo compruebas tú los puertos en Linux? ¿ss o netstat? ¿Qué te ha roto más la cabeza: IPv6, UDP o contenedores? Déjame tus comentarios abajo y enriquezcamos la guía con tus casos reales.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *