Tutoriales de VPS
Puerto VPS ya en uso (2026): Address already in use, EADDRINUSE, solución de conflictos Docker/Nginx
Al iniciar un servicio en un VPS aparecen Address already in use, EADDRINUSE, bind() failed o Docker port is already allocated. Las causas comunes incluyen un proceso antiguo que no terminó, Nginx/Apache/Caddy ocupando 80/443, conflictos de mapeo de puertos de Docker, confusión de escucha dual-stack IPv4/IPv6, arranques duplicados de servicios systemd o una mala interpretación de TIME_WAIT. Este artículo diagnostica capa por capa con ss, lsof, fuser, journalctl, Docker y los registros de Nginx.

Un servicio falla al iniciarse en un VPS y en el registro aparece:
Address already in use
EADDRINUSE: address already in use
bind() to 0.0.0.0:80 failed (98: Address already in use)
port is already allocated
Este tipo de problema normalmente no es que el código se haya roto de repente, sino que el puerto en el que quieres escuchar ya está ocupado por otro proceso. Los escenarios más comunes son: Nginx y Apache peleando por 80/443, un servicio Node iniciado dos veces, un contenedor Docker que mapea el mismo puerto, o un proceso antiguo que no terminó limpiamente.
No ejecutes kill -9 de inmediato. Primero confirma quién ocupa el puerto y luego decide si detener el servicio antiguo, cambiar el puerto, modificar el mapeo de Docker o corregir la forma en que systemd lo inicia.
En Linux moderno, prioriza ss:
sudo ss -lntp
Para consultar solo un puerto, por ejemplo 80:
sudo ss -lntp | grep ':80 '
Para consultar 3000:
sudo ss -lntp | grep ':3000 '
En la salida, fíjate en:
Local Address:Port: dirección y puerto de escucha;users:(...): qué proceso lo ocupa;pid=: ID del proceso;LISTEN: indica que este puerto está siendo escuchado.
Si ves:
LISTEN 0 511 0.0.0.0:80 users:(("nginx",pid=1234,fd=6))
significa que el puerto 80 ya está ocupado por Nginx.
lsof también es muy útil:
sudo lsof -i :3000
Para mostrar solo el PID:
sudo lsof -t -i :3000
La salida típica te indica:
- el nombre del comando;
- el PID;
- el usuario;
- IPv4 / IPv6;
- el estado LISTEN.
Si no está instalado:
sudo apt install lsof -y
o:
sudo dnf install lsof -y
ss es mejor para el diagnóstico del sistema, mientras que lsof es mejor para ver rápidamente "qué proceso ocupa este puerto".
Para ver el uso del puerto:
sudo fuser -v 3000/tcp
Para mostrar solo el PID:
sudo fuser 3000/tcp
Si ya confirmaste que este proceso se puede detener, puedes usar:
sudo fuser -k 3000/tcp
Pero en producción no se recomienda matar directamente así. Lo más seguro es ver primero a qué servicio pertenece el proceso:
ps -fp PID
systemctl status 服务名 --no-pager
Si puedes usar systemctl stop, no hagas directamente kill -9.
El conflicto de puertos más común en servicios web es 80/443.
Consultar el puerto:
sudo ss -lntp | egrep ':80 |:443 '
Consultar el estado del servicio:
sudo systemctl status nginx --no-pager
sudo systemctl status apache2 --no-pager
sudo systemctl status caddy --no-pager
Si Nginx informa:
bind() to 0.0.0.0:80 failed (98: Address already in use)
normalmente es porque Apache, Caddy, otro Nginx o un contenedor Docker ya ocupa el 80.
La solución no es "matarlos a todos":
- conservar solo una entrada web;
- mover el otro servicio a 8080/8443;
- dejar que Nginx/Caddy actúe como proxy inverso;
- deshabilitar el servicio que no se usa:
sudo systemctl stop apache2
sudo systemctl disable apache2
Después de modificar la configuración de Nginx:
sudo nginx -t
sudo systemctl reload nginx
Para errores de configuración de Nginx, consulta: Errores de configuración de Nginx en VPS.
El error de Docker suele verse así:
Bind for 0.0.0.0:8080 failed: port is already allocated
Primero revisa el mapeo de puertos de los contenedores:
docker ps --format "table {{.Names}}\t{{.Ports}}"
Luego revisa los puertos del host:
sudo ss -lntp | grep ':8080 '
Causas comunes:
- dos contenedores especifican
-p 8080:80; - el Nginx del host ya ocupa el 80 y el contenedor también quiere
-p 80:80; - un contenedor antiguo no se eliminó y sigue ocupando el puerto;
- el estado de docker-proxy o de la red de Docker es anómalo.
Cómo resolverlo:
docker ps -a
docker stop 容器名
docker rm 容器名
O cambiar el mapeo de puertos:
ports:
- "8081:80"
No mapees varios servicios al 80 sin más para que funcionen. En una misma IP del host, un mismo puerto solo puede ser ocupado por un único escucha a la vez.
Si el servicio lo gestiona systemd, primero revisa:
sudo systemctl status app --no-pager
sudo journalctl -u app -n 100 --no-pager
Registro común:
Error: listen EADDRINUSE: address already in use :::3000
Failed with result 'exit-code'
Esto indica que la aplicación falló al enlazar el puerto al iniciarse; systemd solo informa que el servicio falló, no que systemd tenga un problema.
Orden de diagnóstico:
sudo ss -lntp | grep ':3000 '
ps -fp PID
sudo systemctl stop 冲突服务
sudo systemctl restart app
Si el servicio se reinicia repetidamente, también puede activar start-limit-hit. En ese caso, corrige primero el conflicto de puertos y luego:
sudo systemctl reset-failed app
sudo systemctl start app
Para un diagnóstico más detallado de fallos de inicio de systemd, consulta: Un servicio systemd no inicia en el VPS.
A veces ves claramente un solo servicio, pero aun así se reporta un conflicto de puertos; la causa puede ser la escucha dual-stack IPv4/IPv6.
Ver las direcciones de escucha:
sudo ss -lntp | grep ':80 '
Puede que veas:
0.0.0.0:80
[::]:80
El significado es aproximadamente:
0.0.0.0:80: escucha en todas las direcciones IPv4;[::]:80: escucha en direcciones IPv6;- en algunas configuraciones
[::]:80también puede aceptar IPv4 al mismo tiempo.
En Nginx se recomienda escribir explícitamente:
listen 80;
listen [::]:80;
Si solo quieres escuchar en IPv4:
listen 0.0.0.0:80;
No dejes que un servicio escuche en 0.0.0.0:80 y otro en [::]:80, y luego esperes que cada uno se las arregle por su cuenta. El comportamiento real depende del sistema y de la configuración de la aplicación, y fácilmente causa confusión en el diagnóstico.
Mucha gente ve un montón de TIME_WAIT y cree que el puerto está ocupado.
Consultar:
ss -tan | grep TIME-WAIT | wc -l
TIME_WAIT es un estado normal de TCP, normalmente relacionado con muchas conexiones cortas. Por lo general no impide que un servicio escuche en un puerto fijo como 0.0.0.0:80.
Lo que realmente hay que vigilar es:
sudo ss -lntp
si hay algún proceso en estado LISTEN ocupando el puerto objetivo.
No cambies tcp_tw_reuse, tcp_fin_timeout sin criterio. Si es agotamiento de puertos efímeros, es otro tipo de problema; si el servicio informa EADDRINUSE al iniciarse, revisa primero el proceso en LISTEN.
Común en Node.js:
Error: listen EADDRINUSE: address already in use :::3000
Diagnóstico:
sudo ss -lntp | grep ':3000 '
Si es un entorno de desarrollo, puedes cambiar el puerto:
PORT=3001 npm start
Python / Flask / FastAPI son similares:
uvicorn app:app --host 0.0.0.0 --port 8001
En producción no dejes que los servicios cambien de puerto aleatoriamente. O fijas el puerto y liberas el proceso en conflicto, o haces que Nginx haga proxy inverso al nuevo puerto y actualizas la configuración en consecuencia.
El comando común que se encuentra en internet:
sudo kill -9 $(sudo lsof -t -i:3000)
Realmente libera el puerto, pero el riesgo es que puedes matar un proceso que está sirviendo tráfico, un proxy de base de datos, un proxy inverso o una tarea en segundo plano de otra persona.
Un proceso más seguro:
sudo lsof -i :3000
ps -fp PID
systemctl status 相关服务 --no-pager
Después de confirmar que es correcto, entonces:
sudo systemctl stop 服务名
Solo cuando hayas confirmado que no es un servicio systemd ni un proceso crítico, considera kill.
Cuando encuentres Address already in use, EADDRINUSE, port is already allocated, revisa en este orden:
sudo ss -lntp | grep ':端口 'para encontrar el proceso en LISTEN.sudo lsof -i :端口para ver el nombre del proceso, el usuario y el PID.ps -fp PIDpara confirmar qué es.- Si es un servicio systemd, primero
systemctl status 服务名. - Si es Docker,
docker ps --format "table {{.Names}}\t{{.Ports}}". - Si es 80/443, comprueba si Nginx, Apache o Caddy entran en conflicto.
- Revisa
journalctl -u 服务名 -n 100para confirmar el error de la aplicación. - Si es necesario, cambia el puerto, detén el servicio en conflicto o cambia el mapeo de Docker.
- No tomes TIME_WAIT como la causa principal de conflictos de puerto de escucha.
- No hagas
kill -9a ciegas; confirma primero a quién pertenece el proceso.
El núcleo del diagnóstico de un puerto ocupado es simple: primero encuentra quién está en LISTEN y luego decide cómo proceder.
ss -lntp es la primera prioridad, lsof -i :端口 sirve para confirmar el proceso y fuser puede localizar y liberar rápidamente. Nginx/Apache/Caddy peleando por 80/443, los conflictos de mapeo de puertos de Docker y los servicios Node/Python iniciados dos veces son las causas más comunes en un VPS.
No mezcles TIME_WAIT, el firewall, los grupos de seguridad y la escucha de puertos. Address already in use se refiere a un conflicto de enlace de puerto local; el firewall y los grupos de seguridad afectan a si se puede acceder desde fuera, que es otro tipo de problema.