port already in use 해결법 — macOS, Windows, Linux

port already in use 에러가 뜨고 있다. Node.js 서버를 다시 띄우려는데 포트가 이미 사용중이라는 에러가 뜬다.

Error: listen EADDRINUSE: address already in use:::3000

이유는 딱 하나다. 3000번 포트를 다른 프로세스가 이미 점유하고 있다. 그 프로세스를 찾아서 죽이거나, 포트 번호를 바꾸면 끝난다.

port already in use EADDRINUSE 에러가 표시된 터미널 화면

port already in use 에러가 뜨는 이유

EADDRINUSE 에러 해결 전에 원인을 이해해두면 재발했을 때 빠르게 대응할 수 있다. EADDRINUSE는 운영체제 레벨 에러 코드다. “address already in use” — 해당 포트를 이미 다른 프로세스가 bind한 상태라는 뜻이다.

세 가지 상황에서 주로 터진다.

첫째, 이전 서버 프로세스가 아직 살아 있다. 터미널 탭을 그냥 닫거나 Ctrl+C 없이 종료하면 프로세스가 백그라운드에 남는다. 새 서버를 띄우려 하면 포트 충돌이 난다.

둘째, 크래시 후 프로세스가 좀비로 남았다. nodemon이 무한 재시작 루프에 빠지거나 앱이 비정상 종료하면 포트를 해제하지 못한 채 프로세스가 남는 경우가 있다.

셋째, 다른 앱이 같은 포트를 쓰고 있다. Docker 컨테이너, PM2가 관리하는 다른 프로세스, 또는 다른 개발 서버가 3000번 포트를 먼저 잡은 상황이다.

해결 방법 1 — 포트를 점유한 프로세스 찾아서 죽이기

포트 충돌 해결의 가장 빠른 방법이다. 어느 프로세스가 포트를 잡고 있는지 확인하고 종료하면 된다.

macOS / Linux

lsof 명령어로 프로세스를 확인한다.

# 3000번 포트를 점유한 프로세스 확인
lsof -i:3000

출력 결과의 PID 열 숫자를 찾아 kill 명령으로 종료한다.

# PID가 12345인 경우
kill -9 12345

매번 PID를 복붙하기 귀찮다면 원라이너로 처리하자.

# 원라이너 -- 3000번 포트 프로세스를 찾아 바로 죽이기
lsof -t -i:3000 | xargs kill -9

LISTEN 상태 프로세스만 보고 싶다면 grep을 추가한다.

lsof -i:3000 | grep LISTEN

Windows

CMD에서는 netstat으로 PID를 확인한 뒤 taskkill로 종료한다.

# 3000번 포트를 점유한 프로세스 확인
netstat -ano | findstr :3000

# 출력된 PID로 프로세스 종료 (PID가 12345인 경우)
taskkill /PID 12345 /F

PowerShell을 쓴다면 이 방법이 더 깔끔하다.

# 3000번 포트 점유 프로세스를 찾아 한 번에 종료
Get-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess | Stop-Process -Force

해결 방법 2 — 포트 번호 바꾸기

해당 포트가 다른 서비스에서 계속 필요한 경우, 내 서버의 포트를 바꾸는 게 빠르다.

임시로 다른 포트를 쓰려면 환경 변수로 지정한다.

# macOS / Linux
PORT=3001 npm start

# Windows CMD
set PORT=3001 && npm start

# Windows PowerShell
$env:PORT=3001; npm start

영구적으로 바꾸려면 .env 파일에 설정하자.

#.env
PORT=3001

포트를 코드에 하드코딩하는 습관이 이런 충돌의 주요 원인이다. 환경 변수로 빼두면 개발/운영 환경별로 다른 포트를 쓰기도 쉬워진다.

// 잘못된 예 -- 포트 하드코딩
app.listen(3000);

// 올바른 예 -- 환경 변수 사용
app.listen(process.env.PORT || 3000);

해결 방법 3 — 재발 방지

kill로 그때그때 해결해도 되지만, 같은 에러가 반복된다면 근본 원인을 잡아야 한다.

nodemon 환경nodemon이 비정상 재시작 루프에 빠지면 이전 프로세스가 포트를 물고 있는 채로 새 프로세스가 뜨려 한다. Ctrl+C로 nodemon을 완전히 종료하고 재시작하자. nodemon.json에 delay 옵션을 추가하면 재시작 간격을 늘려 충돌 가능성을 줄인다.

{
 "delay": "1000"
}

PM2 환경: PM2가 관리하는 프로세스가 포트를 잡고 있다면 전체 초기화 후 재시작하면 깔끔해진다.

# PM2 프로세스 전체 중지 및 삭제
pm2 stop all
pm2 delete all

# 재시작
pm2 start app.js --name "my-app"

Docker 환경: 컨테이너를 중지하지 않고 터미널만 닫은 경우 컨테이너가 백그라운드에서 포트를 잡고 있다. 실행 중인 컨테이너를 확인하고 중지하자.

# 실행 중인 컨테이너 확인
docker ps

# 컨테이너 중지
docker stop [컨테이너 ID]

# 3000번 포트를 쓰는 컨테이너만 필터링
docker ps --filter "publish=3000"

자주 묻는 질문

kill했는데 또 같은 에러가 뜨는 이유는?

같은 포트를 점유하는 프로세스가 두 개 이상일 수 있다. lsof -i:3000 출력에서 LISTEN 상태인 PID를 전부 종료하자. PM2나 Docker처럼 프로세스를 자동 재시작하는 매니저가 있다면, 매니저 자체를 먼저 중지해야 한다. 그렇지 않으면 죽여도 바로 다시 뜬다.

sudo 없이 kill이 안 될 때는?

다른 사용자 권한으로 실행된 프로세스는 sudo kill -9 [PID]로 종료해야 한다. 본인이 시작한 개발 서버라면 sudo 없이도 종료할 수 있다. kill -9 대신 kill -15(SIGTERM, 소프트 종료)를 먼저 시도하는 것도 방법이다.

3000번이 아닌 포트에서 에러가 나는 경우는?

에러 메시지 맨 끝 숫자가 실제 포트 번호다. 다음처럼 다른 포트 번호가 붙을 수 있다.

Error: listen EADDRINUSE: address already in use :::8080
Error: listen EADDRINUSE: address already in use 0.0.0.0:4200
Error: listen EADDRINUSE: address already in use 0.0.0.0:5000

명령어의 :3000 부분을 해당 포트 번호로 바꿔서 동일하게 처리하면 된다.

한줄 정리: port already in use 에러가 뜨면 lsof -i:[포트]로 점유 프로세스를 찾아 kill -9로 죽이자. 원라이너는 lsof -t -i:3000 | xargs kill -9다. 재발한다면 PM2, Docker, nodemon 매니저까지 확인하자.

댓글 남기기