Skip to content

Port và localhost

Hướng dẫn: khi npm run dev, terminal hiện http://localhost:5173, bạn có nghĩ: localhost là gì? 5173 nghĩa là gì? Sao đôi khi báo EADDRINUSE? Chương này giải thích những concept ngày nào cũng thấy nhưng ít khi hiểu sâu.

Trước khi bắt đầu, khuyến nghị bổ sung:


0. Mở đầu: localhost:5173 ngày nào cũng thấy là gì?

1
2
3
4
5
1. 你执行 npm run dev
终端
$ npm run dev

> vite

  准备就绪...
监听
浏览器
等待你打开浏览器...
💡 你在终端里敲下启动命令
什么是 HTTP 服务器?
🏪
想象一个前台窗口HTTP 服务器就像一个"永远开着的服务窗口"——它一直等在那里,有人来问就回答,没人来就静静等着。
📋
只懂一种"暗号"这个窗口只听得懂 HTTP 协议的请求格式(比如 GET /index.html),然后把对应的文件内容返回给你。
⚙️
开发服务器 = 加强版窗口Vite、Webpack 的开发服务器不只是"原样返回文件",它还会即时编译你的代码(Vue → JS、TS → JS、Sass → CSS),然后再返回给浏览器。
一句话总结:开发服务器 = 一个运行在 localhost 上的 HTTP 服务器 + 即时代码编译器。它监听某个端口,浏览器来请求,它就把编译好的代码返回。

Dev nào cũng quen dòng này:

➜  Local:   http://localhost:5173/

Nhưng dòng ngắn này chứa nhiều concept:

  • http:// → protocol (nói thứ tiếng gì)
  • localhost → target address (tìm ai)
  • :5173 → port (tìm rồi, gõ cửa nào)

Hiểu 3 thứ này = hiểu 90% network issues dev env.


1. Port là gì? (IP = toà nhà, port = số phòng)

1.1 Ẩn dụ trực quan

Tưởng tượng server là toà nhà:

  • IP (vd 192.168.1.100) = địa chỉ toà nhà — "đi toà nào"
  • Port (vd :80) = số phòng — "vào phòng nào"

1 toà có thể có cùng lúc nhà hàng (phòng 80), café (443), văn phòng (22). Tương tự, 1 máy có thể chạy cùng lúc Web server, DB, SSH, mỗi cái 1 port.

👇 Click thử: click "số phòng" dưới, simulate connect port khác nhau. Quan sát: port "mở" (có program listen) vs "đóng" — gì xảy ra?

选择一栋"大楼":
Web 服务器大楼IP: 192.168.1.100
80
HTTP网页访问入口
🟢 监听中
443
HTTPS加密网页入口
🟢 监听中
22
SSH远程管理通道
🟢 监听中
3306
MySQL数据库(已关闭)
🔴 已关闭
核心比喻:IP 地址 = 大楼地址,端口号 = 房间门牌号。一台电脑上可以同时运行多个服务,每个服务"占用"一个端口号,就像同一栋大楼里的不同房间。

1.2 Range port

Port là số nguyên 0–65535 (tổng 65536). Chia 3 range:

RangeSốUseVí dụ
System ports0–1023Pre-reserved cho standard protocol, user thường không dùng được80 (HTTP), 443 (HTTPS), 22 (SSH)
Registered ports1024–49151Register cho common app3306 (MySQL), 5432 (PostgreSQL), 6379 (Redis)
Dynamic ports49152–65535OS tạm cấpBrowser gửi request → OS random pick source port

Sao dev server thích dùng 3000, 5173, 8080? Vì trong "registered range", không cần admin, ít conflict với system service.

1.3 Common port speed cheat

👇 Click thử: nhập port hoặc service name search, click row để expand ví dụ.

端口服务说明暴露风险
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
系统端口预留给标准服务(HTTP、SSH 等),普通用户不能随便占用。
1024 – 49151
注册端口留给常见应用(MySQL 3306、Redis 6379 等),开发中最常遇到的范围。
49152 – 65535
动态端口操作系统临时分配的端口,比如你的浏览器发请求时,系统会随机给你一个。
安全提醒:数据库端口(3306、5432、27017、6379)绝对不要直接暴露到公网!生产环境应只允许内网访问或通过 SSH 隧道连接。

2. localhost là gì? (tự tìm chính mình)

2.1 Core concept: "loopback"

localhost là domain đặc biệt, luôn trỏ về chính máy bạn.

Khi bạn gõ http://localhost:3000 vào browser:

  1. Browser hỏi OS: "IP của localhost là gì?"
  2. OS trả lời ngay: "127.0.0.1" (không cần DNS lookup)
  3. Packet gửi tới 127.0.0.1, nhưng không thật sự rời máy
  4. OS qua "loopback interface" gửi packet vòng lại
  5. Program listen port 3000 nhận request, trả response

Cả quá trình không qua dây mạng, không qua router, không cần Internet.

👇 Click thử: click "send request", quan sát hành trình packet. Click "alias card" dưới hiểu các cách viết localhost.

🔗
🌐
浏览器你在地址栏输入 URL
📖
DNS 解析localhost → 127.0.0.1(不出网)
🔄
网络层数据包发往 127.0.0.1(环回接口)
⚙️
本机服务端口 3000 上的程序接收请求
📨
返回响应{ "message": "Hello!" }
你的应用(浏览器)
请求不离开本机
本地服务(:3000)
localhost 的"马甲"们(点击查看说明)
localhost→ 127.0.0.1
127.0.0.1→ 127.0.0.1
::1→ ::1
0.0.0.0→ 0.0.0.0
标准域名别名: 这是写在你电脑 /etc/hosts 文件里的映射。浏览器看到 localhost 时,直接解析为 127.0.0.1,不会去问 DNS 服务器。
核心概念:localhost 就是"自己找自己"。数据包通过环回接口(loopback interface)在本机内部折返,不经过网线、不经过路由器,速度极快且完全安全。

2.2 localhost vs 127.0.0.1 vs 0.0.0.0

3 concept hay confused, nhưng nghĩa khác hoàn toàn:

Cách viếtNghĩaAi access được
localhost / 127.0.0.1Loopback, chỉ máy bạnChỉ máy bạn
0.0.0.0Listen mọi network interfaceMáy bạn + thiết bị khác trong LAN
192.168.x.xLAN IPThiết bị trong LAN

Scenario thực:

bash
# Chỉ mình access (an toàn, hợp dev)
npm run dev -- --host localhost

# Điện thoại cũng access (hợp mobile debug)
npm run dev -- --host 0.0.0.0

Nhiều framework (Vite, Next.js) default listen localhost, nên điện thoại dù cùng WiFi cũng không access được. Muốn dùng phone debug? Add --host là OK.


3. Port conflict: vấn đề thường gặp nhất

3.1 Sao conflict?

1 port cùng lúc chỉ 1 program listen được. Như 1 phòng chỉ 1 hộ ở.

Nếu start service thứ 2 trên cùng port, gặp lỗi kinh điển:

Error: listen EADDRINUSE :::3000

Dịch: "Phòng 3000 đã có người, vào không được!"

Scenario hay gặp:

  • Dev server cũ chưa tắt sạch, còn chạy ở background
  • 2 project khác nhau dùng cùng default port
  • 1 system service đã chiếm port bạn muốn

👇 Click thử: thử start nhiều lần. Khi conflict, so sánh "direct start" vs "smart start".

尝试启动:React 项目(默认端口 5173)
当前运行的服务1 个
Vite 前端:5173🟢 运行中
端口冲突:一个端口同一时刻只能被一个程序监听。如果你看到 EADDRINUSE 错误,说明这个端口已经被占了。要么杀掉旧进程,要么换个端口。

3.2 Debug + fix

Process debug rất cố định:

macOS / Linux:

bash
# B1: xem ai chiếm port 3000
lsof -i :3000

# B2: có PID, force kill
kill -9 <PID>

Windows:

bash
# B1: xem ai chiếm port 3000
netstat -ano | findstr :3000

# B2: kill process
taskkill /PID <PID> /F

Nhiều framework hiện đại (Vite, CRA) gặp conflict sẽ hỏi "đổi port khác?". Nhưng hiểu nguyên lý giúp bạn debug khi framework không giúp được.


4. "Same-Origin Policy" và CORS

4.1 "Origin" là gì?

Browser có security mechanism Same-Origin Policy: chỉ protocol + domain + port đều giống mới tính "same-origin".

Address AAddress BSame-origin?Lý do
http://localhost:5173http://localhost:5173/about CùngProtocol, domain, port đều giống
http://localhost:5173http://localhost:3000 KhácPort khác (5173 vs 3000)
http://localhost:5173https://localhost:5173 KhácProtocol khác (http vs https)

4.2 Sao FE-BE split chắc chắn gặp CORS?

Khi architecture là:

FE (Vite)  →  http://localhost:5173
BE (Express) →  http://localhost:3000

FE load từ :5173, rồi fetch('/api/users') request :3000port khác, trigger CORS!

2 cách giải thường gặp:

Cách 1: BE config CORS

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

Cách 2: FE config proxy (khuyến nghị)

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

Nguyên lý proxy: Vite dev server "forward" request giúp bạn. Browser tưởng đang giao tiếp với :5173 (same-origin), thực ra Vite âm thầm forward sang :3000.


5. Debug thực chiến: 3 vấn đề thường gặp

👇 Click thử: chọn vấn đề bạn từng gặp, theo step debug. Mỗi step có "execute" xem output.

选择一个常见问题:
🔴
端口被占用Error: listen EADDRINUSE :::3000
排查步骤 (1/3)
$lsof -i :3000
查看谁在用这个端口
排查口诀:先确认服务有没有启动(lsof / netstat),再确认端口对不对,最后确认是不是跨域问题。90% 的 localhost 问题都逃不出这三步。

6. Glossary

TermNghĩa
PortSố 0-65535, phân biệt network service trên cùng máy. Mỗi service "listen" 1 port, chờ client connect.
localhostDomain đặc biệt, luôn trỏ máy bạn (127.0.0.1). Dùng để access service local mà không cần Internet.
Loopback InterfaceVirtual network interface của OS. Packet gửi 127.0.0.1 không rời máy, vòng lại qua interface này.
EADDRINUSEError Node.js / OS báo: port bạn muốn listen đã bị program khác chiếm.
CORSCross-Origin Resource Sharing. Browser security, FE request lib khác origin (protocol/domain/port khác) cần BE explicit cho phép.
Same-Origin PolicyFoundation security browser: chỉ cùng protocol-domain-port mới free communicate.
ProxyTrong dev env, proxy server thay browser forward request, bypass same-origin.
0.0.0.0Khi service listen 0.0.0.0 = accept connection từ mọi network interface (máy bạn, LAN).
Well-known PortsTên gọi của 0-1023, pre-reserved cho HTTP (80), HTTPS (443), SSH (22).
PIDProcess ID, số OS cấp cho mỗi process đang chạy.
lsofList open files, command macOS/Linux xem process nào chiếm port (lsof -i :port).
HMRHot Module Replacement: dev server feature, sửa code → browser auto update, không reload. Dùng WebSocket báo browser.

Tổng kết

Port + localhost là concept basic + thường gặp nhất dev env:

  • Port = "số nhà" phân biệt service trên 1 máy (0–65535)
  • localhost = "tự tìm chính mình" (127.0.0.1), data không rời máy
  • Port conflict bản chất "1 số nhà chỉ 1 bảng tên"
  • CORS bản chất "port khác = origin khác", cần CORS hoặc proxy giải

Nhớ 4 câu này, đa số network issue dev env định vị nhanh.

2026 cho VN dev

  • Tailscale Funnel: expose localhost ra Internet không cần ngrok
  • Cloudflare Tunnel: alternative ngrok, free + stable
  • Vite + HMR: 99% framework hiện đại default HMR
  • Docker compose: dev env consistent, port mapping rõ
  • WSL2 networking: trên Windows, port forward giữa WSL và host
  • npx kill-port 3000: 1-click kill process trên port