Guía
Django: That port is already in use. Qué hacer con el puerto 8000
14 de septiembre de 20263 min de lectura
Django es directo al respecto:
Error: That port is already in use.
Sin alternativa, sin cambiarse en silencio al 8001. Es la decisión correcta, porque un servidor de desarrollo que cambia su dirección sin avisar causa bugs más raros que uno que se niega a partir. Sabes de inmediato qué está mal.
Lo primero que hay que revisar
Algo está escuchando en el 8000. Pregunta qué:
lsof -i :8000
Si la respuesta es python o python3, casi con certeza es un runserver anterior que no salió.
lsof -ti :8000 | xargs kill
-t imprime solo los IDs de proceso, xargs se los pasa todos a un kill, y un kill normal manda SIGTERM para que el proceso cierre bien. Tira -9 solo si se niega.
El autoreloader corre dos procesos
Esto sorprende a quien lee la salida. El servidor de desarrollo de Django normalmente corre dos procesos de Python: un padre que observa tus archivos, y un hijo que efectivamente atiende las peticiones. El recargador reinicia al hijo cuando cambia el código.
Así que lsof -i :8000 mostrando dos entradas python no son dos servidores, es un runserver comportándose normal. Si matas solo al hijo, el padre puede levantar otro. La forma con xargs maneja esto bien porque termina todo lo que ocupa el puerto de una vez.
Si quieres ver la relación:
ps -ef | grep runserver
Ahí van a estar el padre y el hijo con sus IDs, y puedes ver que uno es padre del otro.
Correr en otro puerto
Django lo hace fácil, y es la jugada correcta cuando tienes varios proyectos:
python manage.py runserver 8001
También puedes atarlo a una dirección específica:
python manage.py runserver 0.0.0.0:8000
Esa última expone el servidor a toda tu red, que es lo que quieres para probar desde el teléfono y algo para pensar en una red compartida. 127.0.0.1:8000 lo deja solo en tu máquina.
Cuando no es Django
El puerto 8000 es popular más allá de Django. El propio http.server de Python lo usa por defecto, muchas herramientas también, y es una opción común para contenedores.
Si lsof muestra docker-proxy o com.docke, tienes un contenedor:
docker ps --filter "publish=8000"
docker stop <contenedor>
Matar docker-proxy acá no sirve de nada. Docker vuelve a publicar el puerto, y si el contenedor tiene política de reinicio vuelve igual.
El proceso huérfano sin terminal
Un camino común hacia este estado: corriste runserver dentro de una terminal, cerraste la ventana sin Ctrl+C, y el proceso quedó huérfano. No tiene terminal visible, sigue atendiendo, y ocupa el 8000.
Ctrl+C es la salida limpia. Manda SIGTERM, Django apaga al hijo y al padre, y el puerto queda libre. Cerrar la ventana no garantiza eso.
Si nada escucha pero el puerto sigue ocupado
lsof -i :8000 no imprime nada, y Django igual se niega. Eso es TIME_WAIT, un estado de TCP que reserva un puerto recién cerrado por unos treinta segundos. No hay proceso, así que no hay nada que matar. Esperar es el arreglo.
Más sobre eso en qué significa realmente EADDRINUSE, y sobre cómo funcionan los rangos en rangos de puertos explicados.
Bosun muestra qué está ocupando el puerto 8000 desde la barra de menú, colapsa los dos procesos del recargador en una sola fila, y nombra los contenedores de Docker en vez de mostrar docker-proxy. macOS 14 o posterior, prueba de 14 días.
Ve esto en vez de escribirlo
Bosun vive en tu barra de menú y muestra cada puerto abierto en tu Mac, en vivo, mapeado al proceso detrás. Un clic para matarlo, SIGTERM primero. Útil la primera vez que pasa esto. Realmente útil la quinta vez que pasa en una misma tarde.