Skip to content

Puertos y localhost

💡 Guía de aprendizaje: Cuando ejecutas npm run dev y aparece http://localhost:5173 en la terminal, ¿te has preguntado qué es localhost? ¿Y 5173? ¿Por qué a veces aparece un error EADDRINUSE? Este capítulo explica de una vez estos conceptos que ves todos los días en desarrollo pero que rara vez se profundizan.

Antes de empezar, te recomendamos repasar dos conceptos básicos:


0. Introducción: ¿Qué es realmente ese localhost:5173 que ves todos los días?

1
2
3
4
5
1. You run npm run dev
Terminal
$ npm run dev

> vite

  准备就绪...
Listening
Browser
等待你打开Browser...
💡 You type the start command in terminal
What is an HTTP Server?
🏪
Imagine a service windowHTTP 服务器就像一个"永远开着的服务窗口"——它一直等在那里,有人来问就回答,没人来就静静等着。
📋
Only understands one "code"这个窗口只听得懂 HTTP 协议的请求格式(比如 GET /index.html),然后把对应的文件内容返回给你。
⚙️
Dev Server = Enhanced WindowVite、Webpack 的开发服务器不只是"原样返回文件",它还会即时编译你的代码(Vue → JS、TS → JS、Sass → CSS),然后再返回给Browser。
One-line Summary:Dev server = An HTTP server running on localhost + Real-time code compiler. It listens on a port, and when browser requests, it returns the compiled code.

La vida diaria de todo desarrollador gira en torno a esta línea de salida:

➜  Local:   http://localhost:5173/

Pero, ¿has pensado que en esta breve línea se esconden varios conceptos clave:

  • http:// → Protocolo de comunicación (en qué "idioma" hablar)
  • localhost → Dirección de destino (a quién buscar)
  • :5173 → Número de puerto (una vez encontrado, a qué puerta llamar)

Entender estas tres cosas te permitirá comprender el 90% de los problemas de red en entornos de desarrollo. Vamos a desglosarlos uno por uno.


1. ¿Qué es un puerto? (IP es el edificio, el puerto es el número de habitación)

1.1 Una analogía intuitiva

Imagina que un servidor es un edificio:

  • La dirección IP (como 192.168.1.100) es la dirección del edificio — te dice "a qué edificio ir".
  • El número de puerto (como :80) es el número de habitación — te dice "a qué habitación entrar".

Un edificio puede tener simultáneamente un restaurante (hab. 80), una cafetería (hab. 443) y una oficina (hab. 22). Igualmente, un ordenador puede ejecutar simultáneamente un servidor web, una base de datos y un servicio SSH, cada uno en un puerto diferente.

👇 Pruébalo: Haz clic en las "placas de habitación" de abajo para simular una conexión a diferentes puertos. Observa qué sucede cuando un puerto está "abierto" (un programa escuchando) y cuando está "cerrado".

Select a "building":
Web Server BuildingIP: 192.168.1.100
80
HTTPWeb access entry
🟢 Listening
443
HTTPSEncrypted web entry
🟢 Listening
22
SSHRemote management channel
🟢 Listening
3306
MySQLDatabase (closed)
🔴 Closed
Core Analogy:IP 地址 = 大楼地址,端口号 = 房间门牌号。一台电脑上可以同时运行多个服务,每个服务"占用"一个端口号,就像同一栋大楼里的不同房间。

1.2 Rango de valores de los puertos

Un número de puerto es un entero entre 0 y 65535 (65 536 puertos en total). Se dividen en tres rangos:

RangoIntervaloUsoEjemplo
Puertos de sistema0 – 1023Reservados para protocolos estándar; usuarios normales no pueden usarlos libremente80 (HTTP), 443 (HTTPS), 22 (SSH)
Puertos registrados1024 – 49151Para aplicaciones comunes registradas3306 (MySQL), 5432 (PostgreSQL), 6379 (Redis)
Puertos dinámicos49152 – 65535Asignados temporalmente por el sistema operativoEl navegador usa uno aleatorio como puerto origen al hacer peticiones

¿Por qué tu servidor de desarrollo prefiere 3000, 5173, 8080? Porque todos están en el rango de "puertos registrados": no necesitan permisos de administrador para escuchar y es poco probable que entren en conflicto con servicios del sistema.

1.3 Referencia rápida de puertos comunes en desarrollo

👇 Pruébalo: Introduce un número de puerto o nombre de servicio para buscar; haz clic en cualquier fila para ver un ejemplo de uso.

PortServiceDescriptionExposure Risk
80HTTP网页访问(未加密)安全
443HTTPS网页访问(加密)安全
22SSH安全远程登录注意
21FTP文件传输敏感
3306MySQLMySQL 数据库敏感
5432PostgreSQLPostgreSQL 数据库敏感
27017MongoDBMongoDB 数据库敏感
6379RedisRedis 缓存敏感
3000Node/ReactNode.js / React 开发服务器安全
5173ViteVite 开发服务器安全
8080通用 HTTPHTTP 备用端口 / 代理安全
8000Django/PythonDjango / Python HTTP 服务安全
5000FlaskFlask 开发服务器安全
4200AngularAngular 开发服务器安全
53DNS域名解析注意
25SMTP邮件发送注意
0 – 1023
System PortsReserved for standard services (HTTP, SSH, etc.), regular users cannot occupy.
1024 – 49151
Registered PortsFor common applications (MySQL 3306, Redis 6379, etc.), most encountered in development.
49152 – 65535
Dynamic PortsTemporarily assigned by OS, like when your browser makes requests, system randomly assigns one.
Security Alert:数据库端口(3306、5432、27017、6379)绝对不要直接暴露到公网!生产环境应只允许内网访问或通过 SSH 隧道连接。

2. ¿Qué es localhost? (Encontrarse a uno mismo)

2.1 El concepto central de "loopback"

localhost es un nombre de dominio especial que siempre apunta a tu propio ordenador.

Cuando escribes http://localhost:3000 en el navegador, ocurre lo siguiente:

  1. El navegador pregunta al sistema: "¿Cuál es la IP de localhost?"
  2. El sistema responde directamente: "127.0.0.1" (no necesita consultar DNS)
  3. El paquete se envía a 127.0.0.1, pero no sale realmente del ordenador
  4. El sistema, a través de la "interfaz de loopback", hace rebotar el paquete de vuelta
  5. El programa que escucha en el puerto 3000 recibe la petición y devuelve la respuesta

Todo el proceso no pasa por cables de red, ni por routers, ni necesita conexión a Internet.

👇 Pruébalo: Haz clic en "Enviar petición" y observa el recorrido completo del paquete. Luego haz clic en las "tarjetas de disfraz" para conocer las diferentes formas de escribir localhost y sus diferencias.

🔗
🌐
BrowserYou enter URL in address bar
📖
DNS Resolutionlocalhost → 127.0.0.1 (no internet)
🔄
Network LayerPacket sent to 127.0.0.1 (loopback interface)
⚙️
Local ServiceProgram on port 3000 receives request
📨
Return Response{ "message": "Hello!" }
Your App(Browser)
Request stays on local machine
Local Service(:3000)
Localhost "Aliases" (click to see description)
localhost→ 127.0.0.1
127.0.0.1→ 127.0.0.1
::1→ ::1
0.0.0.0→ 0.0.0.0
This is mapped in your computer's <code>/etc/hosts</code> file. When browser sees <code>localhost</code>, it directly resolves to <code>127.0.0.1</code> without asking DNS server.: 这是写在你电脑 /etc/hosts 文件里的映射。浏览器看到 localhost 时,直接解析为 127.0.0.1,不会去问 DNS 服务器。
Core Concept:localhost 就是"自己找自己"。数据包通过环回接口(loopback interface)在本机内部折返,不经过网线、不经过路由器,速度极快且完全安全。

2.2 localhost vs 127.0.0.1 vs 0.0.0.0

Estos tres conceptos suelen confundirse, pero sus significados son completamente distintos:

EscrituraSignificadoQuién puede acceder
localhost / 127.0.0.1Dirección de loopback, solo el ordenador localSolo tu propio ordenador
0.0.0.0Escuchar en todas las interfaces de redOrdenador local + otros dispositivos en la red local
192.168.x.xIP de la red localDispositivos en la red local

En la práctica:

bash
# Solo tú puedes acceder (seguro, ideal para desarrollo)
npm run dev -- --host localhost

# Tu teléfono también puede acceder (ideal para depuración móvil)
npm run dev -- --host 0.0.0.0

Muchos frameworks (como Vite, Next.js) escuchan en localhost por defecto, por lo que tu teléfono no puede acceder aunque esté en la misma WiFi. ¿Quieres depurar desde el móvil? Añade el parámetro --host.


3. Conflictos de puertos: el problema más común en desarrollo

3.1 ¿Por qué se producen conflictos?

Un puerto solo puede ser escuchado por un programa en cada momento. Es como una habitación que solo puede alojar a una familia.

Si intentas iniciar un segundo servicio en el mismo puerto, verás este clásico error:

Error: listen EADDRINUSE :::3000

Traducido: "La habitación 3000 ya está ocupada, ¡no puedes entrar!"

Escenarios de conflicto comunes:

  • El servidor de desarrollo anterior no se cerró correctamente y sigue ejecutándose en segundo plano
  • Dos proyectos diferentes usan el mismo puerto por defecto
  • Un servicio del sistema ya ocupa el puerto que quieres

👇 Pruébalo: Intenta iniciar servicios varias veces en el simulador de abajo. Cuando haya conflicto, compara las diferentes formas de manejarlo entre "inicio directo" e "inicio inteligente".

Try starting:React(default port 5173)
Currently Running Services1 services
Vite:5173🟢 Running
Port Conflict:一个端口同一时刻只能被一个程序监听。如果你看到 EADDRINUSE 错误,说明这个端口已经被占了。要么杀掉旧进程,要么换个端口。

3.2 Diagnóstico y solución

Cuando hay un conflicto de puertos, el proceso de diagnóstico es muy fijo:

macOS / Linux:

bash
# Paso 1: Ver quién ocupa el puerto 3000
lsof -i :3000

# Paso 2: Con el PID, forzar la terminación
kill -9 <PID>

Windows:

bash
# Paso 1: Ver quién ocupa el puerto 3000
netstat -ano | findstr :3000

# Paso 2: Terminar el proceso
taskkill /PID <PID> /F

Muchos frameworks modernos (Vite, Create React App, etc.) preguntan automáticamente "¿Quieres cambiar de puerto?" cuando hay conflicto. Pero entender los principios subyacentes te ayudará a resolver más rápido esos casos en que el framework no puede ayudarte.


4. La "política del mismo origen" y CORS en desarrollo

4.1 ¿Qué es un "origen"?

El navegador tiene un mecanismo de seguridad llamado política del mismo origen (Same-Origin Policy): solo cuando protocolo, dominio y puerto coinciden exactamente, se considera el "mismo origen".

Dirección ADirección B¿Mismo origen?Razón
http://localhost:5173http://localhost:5173/about✅ Mismo origenProtocolo, dominio y puerto iguales
http://localhost:5173http://localhost:3000❌ Distinto origenPuerto diferente (5173 vs 3000)
http://localhost:5173https://localhost:5173❌ Distinto origenProtocolo diferente (http vs https)

4.2 ¿Por qué la separación frontend/backend inevitablemente encuentra CORS?

Cuando la arquitectura de tu proyecto es:

Frontend (Vite)  →  http://localhost:5173
Backend (Express) →  http://localhost:3000

La página frontend se carga desde :5173 y luego usa fetch('/api/users') para pedir la API en :3000 — ¡los puertos son diferentes, se activa la restricción CORS!

Dos soluciones comunes:

Solución 1: Configurar CORS en el backend

javascript
// Backend Express
app.use(cors({ origin: 'http://localhost:5173' }))

Solución 2: Configurar proxy en el frontend (recomendado)

javascript
// vite.config.js
export default {
  server: {
    proxy: {
      '/api': 'http://localhost:3000'
    }
  }
}

El principio del proxy: el servidor de desarrollo de Vite "reenvía" las peticiones por ti. El navegador cree que se comunica con :5173 (mismo origen), pero en realidad Vite las reenvía en secreto a :3000.


5. Diagnóstico práctico: los tres problemas más comunes

👇 Pruébalo: Selecciona un problema que hayas tenido y sigue los pasos. Cada paso se puede ejecutar para ver la salida.

Select a common issue:
🔴
Port OccupiedError: listen EADDRINUSE :::3000
Troubleshooting Steps (1/3)
$lsof -i :3000
Check who is using this port
Troubleshooting Mantra:先确认服务有没有启动(lsof / netstat),再确认端口对不对,最后确认是不是跨域问题。90% 的 localhost 问题都逃不出这三步。

6. Tabla de términos

Término en inglésTraducciónExplicación
PortPuertoNúmero entre 0 y 65535 que distingue diferentes servicios de red en una misma máquina. Cada servicio "escucha" un puerto, esperando conexiones de clientes.
localhostHost localNombre de dominio especial que siempre apunta al ordenador local (127.0.0.1). Permite acceder a servicios locales sin conexión a Internet.
Loopback InterfaceInterfaz de loopbackInterfaz de red virtual del sistema operativo. Los paquetes enviados a 127.0.0.1 no salen del ordenador, sino que "rebotan" a través de esta interfaz.
EADDRINUSEDirección ya en usoError de Node.js / del sistema que indica que el puerto que quieres escuchar ya lo usa otro programa.
CORSRecursos de Origen CruzadoMecanismo de seguridad del navegador. Cuando la página frontend intenta pedir una API de origen diferente (protocolo/dominio/puerto), el backend debe dar permiso explícito.
Same-Origin PolicyPolítica del mismo origenLa piedra angular de la seguridad del navegador: solo permite comunicación libre entre peticiones del mismo protocolo, dominio y puerto, bloqueando la lectura de datos entre orígenes diferentes.
ProxyProxyEn el entorno de desarrollo, el servidor proxy reenvía peticiones al backend en lugar del navegador, eludiendo las restricciones del mismo origen.
0.0.0.0Todas las interfacesCuando un servicio escucha en 0.0.0.0, acepta conexiones desde cualquier interfaz de red (local, red local, etc.).
Well-known PortsPuertos conocidosNombre colectivo de los puertos 0–1023, reservados para protocolos estándar como HTTP (80), HTTPS (443), SSH (22).
PIDID de procesoNúmero único que el sistema operativo asigna a cada programa en ejecución, para gestionar y terminar procesos.
lsofListar archivos abiertosComando de macOS/Linux para ver qué proceso ocupa un puerto (lsof -i :puerto).
HMRReemplazo de Módulos en CalienteFunción del servidor de desarrollo: al modificar código, el navegador se actualiza automáticamente sin necesidad de refrescar manualmente. Funciona internamente mediante WebSocket.

Resumen

Los puertos y localhost son los conceptos más básicos y frecuentes en el entorno de desarrollo:

  • Puerto = "Número de habitación" para distinguir servicios en una máquina (0–65535)
  • localhost = Dirección especial para "encontrarse a uno mismo" (127.0.0.1); los datos no salen del ordenador
  • Conflicto de puertos significa esencialmente "una habitación solo puede tener una placa"
  • CORS significa esencialmente "puerto diferente = origen diferente", requiere CORS o un proxy para resolverse

Recuerda estas cuatro frases y podrás diagnosticar rápidamente la mayoría de los problemas de red en tu entorno de desarrollo.