기술 · 실용 가이드
Node EADDRINUSE? 프로세스를 죽이기 전에 바인드·리스너·감독자를 증명하세요
전체 주소와 포트를 보존하고 같은 네임스페이스에서 리스너를 찾아 실제 소유자를 통해 멈춘 뒤 한 번의 재시작을 검증합니다.

이 가이드는 EADDRINUSE를 “Node 종료” 명령이 아니라 바인드 소유권 감사로 다룹니다. 오류 객체를 보존하고 주소, IP 패밀리, 네트워크 네임스페이스로 충돌 범위를 좁힙니다.
그다음 리스너 PID를 실제로 관리하는 터미널, 감독자, 서비스 또는 컨테이너까지 추적합니다. 소켓 해제를 확인한 뒤에만 한 번 재시작하고 관찰 가능한 결과로 완료를 판단합니다.
1. 전체 바인드 오류 고정
재시작 전에 code, syscall, address, port 또는 소켓 경로, 실제 실행 명령, cwd, Node 버전과 감독 프로세스를 기록합니다. EADDRINUSE는 로컬 주소가 사용 중이라는 뜻이지 소유자를 알려 주지 않습니다.
:::3000을 단순히 “3000번 포트 사용 중”으로 줄이지 마세요. 와일드카드 주소, IP 패밀리와 네트워크 네임스페이스도 충돌 조건입니다.
2. 포트보다 주소와 패밀리 먼저 읽기
host를 생략하면 Node는 보통 ::, IPv6가 없으면 0.0.0.0에 바인드합니다. 많은 시스템에서 IPv6 와일드카드는 IPv4도 받아 같은 포트의 IPv4 바인드와 충돌합니다.
127.0.0.1, 0.0.0.0, ::1, ::는 같지 않습니다. 설계상 필요하지 않다면 바인드를 넓히거나 IPv6를 꺼서 오류를 숨기지 마세요.
3. 같은 네임스페이스에서 리스너 검사
Linux에서는 ss -ltnp 또는 정확한 포트 필터를 씁니다. -l은 listen, -n은 숫자, -p는 프로세스 정보입니다. 필요한 최소 권한만 사용하세요.
macOS는 lsof, Windows는 Get-NetTCPConnection과 Get-Process를 쓸 수 있습니다. 컨테이너에서는 호스트 게시 포트와 실패한 컨테이너 네임스페이스를 모두 검사합니다.
4. PID에서 실제 소유자 추적
리스너 PID가 감독자의 자식일 수 있습니다. 명령줄과 부모를 기록하고 nodemon, PM2, systemd, Docker Compose, Kubernetes 또는 IDE의 소유 여부를 확인합니다.
nodemon 사례는 저장 재시작 때 ::와 5000이 충돌할 수 있음을 보여 줍니다. 모든 Node를 죽이지 말고 감독과 종료 수명주기를 고치세요.
5. 소유자를 통해 중지하고 해제 확인
터미널 작업, PM2 앱, systemd unit, 관련 컨테이너 등 실제 소유자의 stop 기능을 씁니다. 강제 종료는 정체와 범위를 증명한 뒤 마지막에 사용합니다.
같은 소켓 검사를 다시 실행해 리스너가 사라지고 바로 재생성되지 않는지 확인합니다. killall node와 광범위한 sudo 명령은 피하세요.
6. 구조상 필요할 때만 포트 변경
의도한 두 서비스가 다른 endpoint를 써야 하거나 배포가 동적 포트를 할당할 때만 변경합니다. 무작정 포트를 옮기면 오래된 감독자가 남습니다.
port 0을 쓰면 listening 후 실제 주소를 클라이언트에 전달합니다. 고정 포트의 proxy, firewall, discovery, health check 계약은 함께 바꿉니다.
7. 한 번 재시작하고 리스너 증명
먼저 reload와 여러 worker를 끄고 한 인스턴스만 시작합니다. PID/컨테이너, 로컬 주소, 포트, 패밀리와 health route를 확인한 뒤 감독자를 복원합니다.
재발하면 owner, parent, namespace와 timeline을 비교합니다. 깨끗한 소켓 뒤 반복되는 충돌은 중복 실행 또는 재시작 경쟁이며 캐시나 Node 설치 문제의 증거가 아닙니다.
