Puertos, localhost y loopback
Puertos, localhost y loopback
[!tip] Puertos en una frase Un puerto es como el número de apartamento en un edificio: la IP es el edificio (servidor), el puerto es la puerta específica (servicio) por donde entra la comunicación.
¿Qué es un puerto?
Un puerto es un número de 16 bits (0-65535) que identifica un servicio específico en un servidor. Piensa en un servidor como un edificio con múltiples puertas:
Servidor: 192.168.1.100 (la dirección del edificio)
Puerto 22 → SSH (acceso remoto)
Puerto 80 → HTTP (servidor web)
Puerto 443 → HTTPS (servidor web seguro)
Puerto 3000 → Tu app de desarrollo
Puerto 5432 → PostgreSQL (base de datos)
Puerto 6379 → Redis (caché)
Puerto 8080 → Proxy inverso alternativo
La analogía del teléfono
IP = Número de teléfono del servidor
Puerto = Extensión dentro del servidor
Llamar al 666-555-1234 → Conectas al servidor
Extensión 22 → SSH
Extensión 80 → Web
Extensión 443 → Web segura
Rangos de puertos
| Rango | Nombre | Uso típico |
|---|---|---|
| 0-1023 | Well-known / System ports | Servicios estándar: SSH(22), HTTP(80), HTTPS(443), DNS(53), SMTP(25) |
| 1024-49151 | Registered ports | Servicios registrados: PostgreSQL(5432), MySQL(3306), MongoDB(27017) |
| 49152-65535 | Dynamic / Ephemeral | Puertos temporales del cliente (conexiones salientes) |
[!tip] ¿Por qué 65535? Porque un puerto es 16 bits: 2^16 = 65536 valores posibles (0-65535).
localhost / 127.0.0.1 / ::1
localhost es un nombre que siempre apunta a tu propia máquina.
Direcciones equivalentes
| Nombre | IPv4 | IPv6 | Significado |
|---|---|---|---|
localhost |
127.0.0.1 |
::1 |
Tu máquina local |
0.0.0.0 |
:: |
Ninguna | "Todas las interfaces" |
¿Por qué 0.0.0.0 no es "tu máquina"?
# Bind a 127.0.0.1 (solo acceso local)
node server.js --host 127.0.0.1 --port 3000
# Accesible desde: localhost:3000
# No accesible desde: otra máquina en la red
# Bind a 0.0.0.0 (acceso desde cualquier interfaz)
node server.js --host 0.0.0.0 --port 3000
# Accesible desde: localhost:3000, 192.168.1.5:3000, cualquier IP del servidor
# No accesible desde: Internet (a menos que el firewall lo permita)
[!warning] 0.0.0.0 NO es localhost
0.0.0.0significa "escucha en TODAS las interfaces de red"127.0.0.1significa "solo escucha en la interfaz loopback"- Cuando ves
http://localhost:3000en docs de desarrollo, normalmente el servidor necesita binding a0.0.0.0para que funcione dentro de Docker
El loopback (la interfaz de red interna)
El loopback es una interfaz de red virtual que tu sistema operativo crea. Los paquetes que envías a 127.0.0.1 nunca salen de tu máquina:
Tu proceso Loopback interface
│ │
│─── Paquete → 127.0.0.1 ────→ │
│ │ (nunca toca la tarjeta de red)
│ │ (nunca toca el cable/WiFi)
│←── Paquete ←─────────────────│ (el SO lo maneja internamente)
[!tip] El loopback es increíblemente rápido Porque los paquetes no salen de la máquina, el loopback es orders de magnitud más rápido que cualquier interfaz de red real. Latencia: ~0.01ms vs ~1ms para una interfaz local.
Puertos en Docker
El problema: contenedores tienen su propia red
# Dentro del contenedor:
# Tu app corre en localhost:3000
# Pero localhost dentro del contenedor NO es localhost de tu máquina
# Desde tu máquina (host):
curl http://localhost:3000 → Connection refused! (porque el contenedor NO está en tu localhost)
# Solución: puertos expuestos
docker run -p 3000:3000 mi-app
# ↑ ↑ ↑ ↑
# host │ container
# puerto │ puerto
Cómo funciona -p host:container
Tu máquina (host) Contenedor
│
│ Docker bridge network
│
3000 ←─────────────│─────────────→ 3000
(localhost:3000) │ (app:3000)
# El puerto 3000 del host redirige al puerto 3000 del contenedor
Ejemplos de mapeo de puertos
# Puerto igual en host y container
docker run -p 3000:3000 mi-app
# Acceso: http://localhost:3000
# Puerto diferente
docker run -p 8080:3000 mi-app
# Acceso: http://localhost:8080 (redirige al 3000 dentro del contenedor)
# Múltiples puertos
docker run -p 3000:3000 -p 5432:5432 mi-app
# Acceso: localhost:3000 y localhost:5432
# Solo accesible desde localhost
docker run -p 127.0.0.1:3000:3000 mi-app
# No accesible desde otra máquina en la red
# Accesible desde cualquier IP (¡cuidado en producción!)
docker run -p 0.0.0.0:3000:3000 mi-appPuertos en Docker Compose
# docker-compose.yml
services:
web:
build: .
ports:
- "3000:3000"
- "127.0.0.1:8080:8080" # Solo accesible desde localhost
db:
image: postgres:16
ports:
- "5432:5432" # Accesible desde localhost y desde otros contenedores
# Los puertos internos NUNCA se exponen al host (solo entre contenedores)
redis:
image: redis:7
ports: [] # Sin puertos expuestos — solo accessible desde otros contenedores[!important] Puertos internos vs expuestos
- Sin puertos expuestos: Los contenedores se comunican por la red interna de Docker. No se pueden acceder desde tu máquina host.
- Con puertos expuestos: Se pueden acceder desde tu máquina con
localhost:puerto.Regla práctica: Expone solo los puertos del frontend al host. El backend, DB, Redis, etc., solo necesitan ser accesibles entre contenedores.
Docker networking (concepto)
# En docker-compose, los servicios se comunican por nombre
services:
web:
depends_on: [api]
environment:
API_URL: http://api:3000 # ← usa el nombre del servicio, no localhost
api:
ports:
- "3000:3000"
Ver puertos abiertos
Linux
# Ver puertos que están escuchando (sudo necesario)
sudo ss -tlnp
# Estado Recv-Q Send-Q Local Address:Port Peer Address:Port Process
# LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1234,fd=3))
# LISTEN 0 128 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=5678,fd=6))
# LISTEN 0 128 0.0.0.0:3000 0.0.0.0:* users:(("node",pid=9012,fd=15))
# LISTEN 0 128 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=3456,fd=5))
# Ver puertos en uso por un proceso específico
sudo lsof -i -P -n | grep 3000
# node 9012 emilio 15u IPv4 123456 0t0 TCP *:3000 (LISTEN)¿Qué significa 0.0.0.0:3000 vs 127.0.0.1:3000?
| Bind address | Accesible desde |
|---|---|
0.0.0.0:3000 |
localhost + cualquier IP de la máquina |
127.0.0.1:3000 |
Solo localhost |
192.168.1.5:3000 |
Solo desde esa IP específica |
[!tip] Por qué ver
0.0.0.0vs127.0.0.1importa Si tu app node.js haceapp.listen(3000)por defecto, escucha en0.0.0.0. Si haceapp.listen(3000, '127.0.0.1'), solo escucha en localhost.En Docker, necesitas que escuche en
0.0.0.0(o::) para que el puerto mapeado funcione.
Puertos comunes que necesitas conocer
| Puerto | Servicio | Protocolo |
|---|---|---|
| 22 | SSH | TCP |
| 53 | DNS | UDP/TCP |
| 80 | HTTP | TCP |
| 443 | HTTPS | TCP |
| 3000 | Node.js (dev) | TCP |
| 5432 | PostgreSQL | TCP |
| 3306 | MySQL | TCP |
| 6379 | Redis | TCP |
| 27017 | MongoDB | TCP |
| 8080 | Proxy/Alt HTTP | TCP |
| 8443 | Alt HTTPS | TCP |
| 9200 | Elasticsearch | TCP |
| 5672 | RabbitMQ | TCP |
| 15672 | RabbitMQ Management | TCP |
| 2375 | Docker API (sin TLS) | TCP |
| 2376 | Docker API (con TLS) | TCP |
| 8888 | Jupyter, Prometheus | TCP |
IPv4 vs IPv6
IPv4 (32 bits)
Formato: 4 grupos de 8 bits, separados por puntos
192.168.1.100
Rangos privados (no enrutables en Internet):
10.0.0.0/8 (10.0.0.0 - 10.255.255.255)
172.16.0.0/12 (172.16.0.0 - 172.31.255.255)
192.168.0.0/16 (192.168.0.0 - 192.168.255.255)
Total: ~4.3 mil millones de direcciones
IPv6 (128 bits)
Formato: 8 grupos de 4 hexadecimales, separados por dos puntos
2001:0db8:85a3:0000:0000:8a2e:0370:7334
Compresión: los ceros a la izquierda y bloques consecutivos de ceros se pueden omitir
2001:db8:85a3::8a2e:370:7334
Rango local (equivalente a 127.0.0.1):
::1 (loopback)
Total: 3.4 × 10^38 direcciones (prácticamente infinito)
[!tip] Por qué necesitamos IPv6 El IPv4 se agotó en 2011. Con NAT (ver [[13-nat-red]]) pudimos alargar la vida, pero IPv6 es la solución definitiva. Cada dispositivo puede tener su propia IP pública.
Resumen
- Un puerto identifica un servicio específico en un servidor (número 0-65535)
- localhost (127.0.0.1) siempre apunta a tu máquina; 0.0.0.0 significa "todas las interfaces"
- En Docker, necesitas
-p host:containerpara exponer puertos al host - Los servicios expuestos a Internet deben tener firewall configurado (solo abrir puertos necesarios)
- IPv6 es el futuro (más direcciones, sin necesidad de NAT)
[!quote] La clave Puertos + IP = dirección completa. La IP dice "dónde" (qué servidor), el puerto dice "a qué servicio" (qué puerta). Sin puerto, no sabes a qué servicio conectar.
Conexión con el resto de la wiki
| Concepto tocado | Artículo en profundidad |
|---|---|
| Cómo navega de URL a página | [[02-como-navegar-de-url-a-pagina]] (el puerto se extrae de la URL) |
| NAT | [[13-nat-red]] (cómo el mapeo de puertos en NAT conecta mundo exterior e interior) |
| Servidores y procesos | [[14-servidores-procesos]] (un servidor es un proceso escuchando en un puerto) |