Skip to content

포트와 localhost

💡 학습 가이드: npm run dev를 실행하면 터미널에 http://localhost:5173이 나옵니다. localhost가 무엇인지, 5173은 무엇을 의미하는지 생각해 본 적이 있나요? 왜 가끔 EADDRINUSE 오류가 발생할까요? 이 장에서는 일상 개발에서 매일 보지만 깊이 파고들지 않았던 개념들을 한 번에 정리합니다.

시작하기 전에 두 가지 "기본 벽돌"을 먼저 보충하는 것을 권장합니다:


0. 서론: 매일 보는 localhost:5173은 대체 무엇인가?

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.

모든 개발자의 일상에는 이 출력이 빠지지 않습니다:

➜  Local:   http://localhost:5173/

하지만 이 짧은 한 줄에 몇 가지 핵심 개념이 숨겨져 있습니다:

  • http:// → 통신 프로토콜 (어떤 언어로 대화할 것인가)
  • localhost → 목적 주소 (누구를 찾을 것인가)
  • :5173 → 포트 번호 (찾은 후 어느 문을 두드릴 것인가)

이 세 가지를 이해하면 개발 환경 네트워크 문제의 90%를 이해할 수 있습니다. 이제 하나씩 분석해 봅시다.


1. 포트란 무엇인가? (IP는 건물, 포트는 호실 번호)

1.1 직관적 비유

서버를 한 건물이라고 상상해 보세요:

  • IP 주소(예: 192.168.1.100)는 건물의 주소 — "어느 건물로 갈 것인가"를 알려줍니다.
  • 포트 번호(예: :80)는 건물 내 호실 번호 — "어느 방으로 들어갈 것인가"를 알려줍니다.

한 건물에는 레스토랑(80호), 카페(443호), 사무실(22호)이 동시에 있을 수 있습니다. 마찬가지로 한 컴퓨터에서 웹 서버, 데이터베이스, SSH 서비스가 각각 다른 포트를 차지하며 동시에 실행될 수 있습니다.

👇 직접 해보기: 아래의 "방 문패"를 클릭하여 다른 포트에 연결을 시도해 보세요. 포트가 "열려 있을 때"(프로그램이 수신 중)와 "닫혀 있을 때" 각각 어떤 일이 발생하는지 관찰하세요.

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 포트 번호의 범위

포트 번호는 0–65535 사이의 정수입니다 (총 65536개). 이 많은 포트는 세 가지 구간으로 나뉩니다:

구간범위용도예시
시스템 포트0 – 1023표준 프로토콜용 예약, 일반 사용자가 임의로 사용 불가80 (HTTP), 443 (HTTPS), 22 (SSH)
등록 포트1024 – 49151일반적인 애플리케이션 등록용3306 (MySQL), 5432 (PostgreSQL), 6379 (Redis)
동적 포트49152 – 65535운영 체제가 임시 할당브라우저가 요청을 보낼 때 시스템이 임의의 소스 포트 할당

개발 서버가 3000, 5173, 8080을 좋아하는 이유는? 이들이 모두 "등록 포트" 범위에 있어 관리자 권한 없이도 수신 가능하고, 시스템 서비스와 충돌하기 어렵기 때문입니다.

1.3 개발 중 자주 나오는 포트 번호 빠른 참조

👇 직접 해보기: 포트 번호나 서비스명을 검색하고, 아무 행이나 클릭하면 사용 예시가 펼쳐집니다.

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. localhost란 무엇인가? (스스로를 찾기)

2.1 "루프백"의 핵심 개념

localhost는 특수한 도메인 이름으로, 항상 자신의 컴퓨터를 가리킵니다.

브라우저에 http://localhost:3000을 입력하면 다음이 발생합니다:

  1. 브라우저가 운영 체제에 묻습니다: "localhost의 IP가 무엇인가요?"
  2. 운영 체제가 바로 답합니다: "127.0.0.1" (DNS 조회 없음)
  3. 데이터 패킷이 127.0.0.1로 발송되지만, 실제로 기기를 떠나지 않습니다
  4. 운영 체제가 "루프백 인터페이스(loopback interface)"를 통해 데이터 패킷을 되돌려 보냅니다
  5. 3000 포트에서 수신 중인 프로그램이 요청을 받아 응답을 반환합니다

전체 과정이 네트워크 케이블, 라우터, 인터넷 연결을 거치지 않습니다.

👇 직접 해보기: "요청 보내기"를 클릭하여 데이터 패킷의 전체 여정을 관찰하세요. 그런 다음 아래의 "가면 카드"를 클릭하여 localhost의 다양한 표기법과 차이를 알아보세요.

🔗
🌐
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

이 세 가지 개념은 자주 혼동되지만 의미가 완전히 다릅니다:

표기의미누가 접근할 수 있는가
localhost / 127.0.0.1루프백 주소, 자기 자신만본인 컴퓨터만
0.0.0.0모든 네트워크 인터페이스 수신본인 + LAN 내 다른 기기
192.168.x.xLAN IPLAN 내 기기

실제 시나리오:

bash
# 자신만 접근 가능 (안전, 개발에 적합)
npm run dev -- --host localhost

# 휴대폰도 접근 가능 (모바일 디버깅에 적합)
npm run dev -- --host 0.0.0.0

많은 프레임워크(Vite, Next.js 등)는 기본적으로 localhost를 수신하므로, 같은 WiFi에 연결된 휴대폰으로도 접근할 수 없습니다. 휴대폰으로 디버깅하고 싶다면 --host 매개변수를 추가하세요.


3. 포트 충돌: 가장 흔한 개발 환경 문제

3.1 왜 충돌이 발생하나요?

하나의 포트를 동시에 하나의 프로그램만 수신할 수 있습니다. 한 방에 한 가구만 살 수 있는 것과 같습니다.

같은 포트에서 두 번째 서비스를 시작하려고 하면 이 전형적인 오류를 보게 됩니다:

Error: listen EADDRINUSE :::3000

사람의 말로 번역하면: "3000호에 이미 누가 살고 있어서 들어갈 수 없습니다!"

흔한 충돌 시나리오:

  • 이전 개발 서버가 완전히 종료되지 않고 백그라운드에서 계속 실행 중
  • 서로 다른 두 프로젝트가 같은 기본 포트 사용
  • 어떤 시스템 서비스가 이미 원하는 포트를 차지

👇 직접 해보기: 아래 시뮬레이터에서 서비스를 여러 번 시작해 보세요. 포트 충돌 시 "직접 시작"과 "스마트 시작"의 다른 처리 방식을 비교해 보세요.

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

3.2 문제 해결 및 해결

포트 충돌을 겪었을 때 해결 절차는 매우 일정합니다:

macOS / Linux:

bash
# 첫 번째: 누가 3000 포트를 차지하고 있는지 확인
lsof -i :3000

# 두 번째: PID를 확인한 후 강제 종료
kill -9 <PID>

Windows:

bash
# 첫 번째: 누가 3000 포트를 차지하고 있는지 확인
netstat -ano | findstr :3000

# 두 번째: 프로세스 종료
taskkill /PID <PID> /F

많은 현대 프레임워크(Vite, Create React App 등)는 포트 충돌 시 "다른 포트로 변경할까요?"라고 자동으로 묻습니다. 하지만 기본 원리를 이해하면 프레임워크가 도와주지 못하는 까다로운 문제를 더 빠르게 해결할 수 있습니다.


4. 개발 중 "동일 출처 정책"과 CORS

4.1 "출처"란 무엇인가?

브라우저에는 동일 출처 정책(Same-Origin Policy)이라는 보안 메커니즘이 있습니다: 프로토콜, 도메인, 포트 세 가지가 모두 동일해야 "동일 출처"로 인정됩니다.

주소 A주소 B동일 출처 여부이유
http://localhost:5173http://localhost:5173/about✅ 동일 출처프로토콜, 도메인, 포트 모두 같음
http://localhost:5173http://localhost:3000❌ 다른 출처포트 다름 (5173 vs 3000)
http://localhost:5173https://localhost:5173❌ 다른 출처프로토콜 다름 (http vs https)

4.2 왜 프론트/백엔드 분리는 반드시 CORS를 만나게 되나요?

프로젝트 아키텍처가 다음과 같을 때:

프론트엔드 (Vite)  →  http://localhost:5173
백엔드 (Express) →  http://localhost:3000

프론트엔드 페이지가 :5173에서 로드된 후 fetch('/api/users'):3000의 API를 요청하면 — 포트가 달라 크로스 오리진 제한이 발동합니다!

두 가지 일반적인 해결책:

해결책 1: 백엔드에 CORS 설정

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

해결책 2: 프론트엔드에 프록시 설정 (권장)

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

프록시의 원리: Vite 개발 서버가 대신 요청을 "전달"해 줍니다. 브라우저는 :5173과 통신한다고 생각하지만(동일 출처), 실제로는 Vite가 배후에서 :3000에 요청을 전달합니다.


5. 실전 문제 해결: 세 가지 가장 흔한 문제

👇 직접 해보기: 겪어본 문제를 선택하고 단계에 따라 함께 해결해 보세요. 각 단계에서 "실행"을 클릭하면 출력을 확인할 수 있습니다.

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. 용어 대조표

영문 용어한국어 대조설명
Port포트0–65535 사이의 숫자로, 같은 기기에서 서로 다른 네트워크 서비스를 구분. 각 서비스가 하나의 포트를 "수신"하며 클라이언트 연결을 대기
localhost로컬 호스트특수한 도메인 이름으로, 항상 자기 자신(127.0.0.1)을 가리킴. 네트워크 연결 없이 자기 기기에서 실행 중인 서비스에 접근할 때 사용
Loopback Interface루프백 인터페이스운영 체제의 가상 네트워크 인터페이스. 127.0.0.1로 향하는 데이터 패킷은 기기를 떠나지 않고 이 인터페이스를 통해 "되돌아"옴
EADDRINUSE주소 이미 사용 중Node.js / 운영 체제가 보고하는 오류로, 수신하려는 포트가 이미 다른 프로그램에 의해 사용되고 있음을 나타냄
CORS크로스 오리진 리소스 공유브라우저 보안 메커니즘. 프론트엔드 페이지가 다른 출처(프로토콜/도메인/포트가 다름)의 API를 요청할 때 백엔드의 명시적 허가가 필요
Same-Origin Policy동일 출처 정책브라우저 보안의 초석: 같은 프로토콜, 같은 도메인, 같은 포트의 요청만 자유롭게 통신하도록 허용
Proxy프록시개발 환경에서 프록시 서버가 브라우저를 대신해 백엔드에 요청을 전달하여 브라우저의 동일 출처 제한을 우회
0.0.0.0모든 인터페이스서비스가 0.0.0.0을 수신할 때, 모든 네트워크 인터페이스(자기 자신, LAN 등)의 연결을 수락함을 의미
Well-known Ports잘 알려진 포트0–1023 포트의 총칭, HTTP (80), HTTPS (443), SSH (22) 등 표준 프로토콜용으로 예약됨
PID프로세스 ID운영 체제가 각 실행 중인 프로그램에 할당하는 고유 번호, 프로세스 관리 및 종료에 사용
lsof열린 파일 나열macOS/Linux 명령어, 특정 포트를 차지한 프로세스를 확인하는 데 사용 (lsof -i :포트번호)
HMR핫 모듈 교체개발 서버의 기능: 코드 수정 후 브라우저가 자동으로 업데이트되어 수동 새로고침 불필요.底层에서 WebSocket을 통해 브라우저에 알림

요약

포트와 localhost는 개발 환경에서 가장 기본적이고 빈번하게 사용되는 개념입니다:

  • 포트 = 한 기기에서 서로 다른 서비스를 구분하는 "호실 번호" (0–65535)
  • localhost = "스스로를 찾는" 특수 주소 (127.0.0.1), 데이터가 기기를 떠나지 않음
  • 포트 충돌의 본질은 "하나의 호실에 하나의 간판만 걸 수 있음"
  • CORS의 본질은 "포트가 다르면 = 출처가 다름", CORS 또는 프록시로 해결 필요

이 네 문장을 기억하면 개발 환경에서 만나는 대부분의 네트워크 문제를 빠르게 원인을 파악할 수 있습니다.