Docker Port Is Already Allocated: Cách tìm tiến trình chiếm cổng trên Windows và Linux
Hướng dẫn xử lý port is already allocated, address already in use và EADDRINUSE trong Docker Compose mà không tắt nhầm tiến trình.
Bài viết bởi Phạm Minh Thiện
Front-end Developer, trực tiếp thực hành Next.js, NestJS, Docker, Nginx và VPS Ubuntu.
Bài viết đã được kiểm tra lại ngày 18/7/2026.
Mục lục bài viết
Khi Docker Compose khởi động container, Docker phải bind một cổng trên máy host. Nếu cổng đó đã được ứng dụng khác hoặc container khác sử dụng, bạn sẽ gặp lỗi như:
Bind for 0.0.0.0:8080 failed: port is already allocated
Trên Windows, thông báo có thể dài hơn:
ports are not available: exposing port TCP 127.0.0.1:8080:
listen tcp4 127.0.0.1:8080: bind: An attempt was made to access a socket...
Node.js chạy ngoài Docker có thể báo:
Error: listen EADDRINUSE: address already in use :::3000
Ba thông báo khác nhau nhưng đều đặt ra một câu hỏi: tiến trình nào đang giữ cổng host và mình nên dừng nó hay đổi cổng?

1. Hiểu đúng 8080:3000
Trong Compose:
services:
web:
ports:
- "8080:3000"
Ý nghĩa:
HOST_PORT:CONTAINER_PORT
8080 :3000
Trình duyệt gọi localhost:8080. Docker chuyển request đến cổng 3000 bên trong container.
Hai container có thể cùng nghe cổng 3000 bên trong vì chúng nằm trong network namespace riêng. Nhưng chúng không thể cùng chiếm một host port 8080 trên cùng địa chỉ bind.
2. Kiểm tra container Docker đang chiếm cổng
Bắt đầu bằng:
docker ps --format 'table {{.Names}}\t{{.Ports}}\t{{.Status}}'
Ví dụ:
NAMES PORTS STATUS
old-web 0.0.0.0:8080->3000/tcp Up 2 hours
postgres-dev 127.0.0.1:5432->5432/tcp Up 2 hours
Container old-web đang giữ cổng 8080. Nếu đó là stack cũ không còn dùng:
docker stop old-web
docker rm old-web
Nếu container được tạo bởi Compose, ưu tiên vào đúng thư mục dự án rồi dùng:
docker compose down
Cách này dọn đúng container và network thuộc project, thay vì xóa thủ công từng thành phần.
3. Tìm tiến trình chiếm cổng trên Linux
Dùng ss:
sudo ss -lntp | grep ':8080'
Hoặc lsof nếu đã cài:
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN
Ví dụ:
LISTEN 0 4096 0.0.0.0:8080 0.0.0.0:* users:(("docker-proxy",pid=2145,fd=4))
Nếu là docker-proxy, quay lại docker ps để tìm container. Nếu là node, nginx, java hoặc process khác, xem đầy đủ thông tin trước khi dừng:
ps -fp 2145
sudo systemctl status <ten-service>
Không nên chạy kill -9 ngay. Hãy thử dừng đúng service hoặc gửi tín hiệu kết thúc bình thường trước.

4. Tìm PID chiếm cổng trên Windows
Trong PowerShell hoặc Command Prompt:
netstat -ano | findstr :8080
Ví dụ:
TCP 127.0.0.1:8080 0.0.0.0:0 LISTENING 14620
Tra tiến trình:
tasklist /FI "PID eq 14620"
PowerShell hiện đại cũng có thể dùng:
Get-NetTCPConnection -LocalPort 8080 -State Listen |
Select-Object LocalAddress, LocalPort, OwningProcess
Get-Process -Id 14620
Nếu PID thuộc Docker Desktop, hãy kiểm tra container bằng docker ps trước. Dừng Docker Desktop chỉ để giải phóng một cổng thường là giải pháp quá mạnh và làm gián đoạn tất cả container.
5. Ba cách xử lý đúng
Cách 1: Dừng tiến trình cũ
Dùng khi tiến trình cũ không còn cần thiết.
Linux service:
sudo systemctl stop my-old-app
Node.js chạy thủ công:
kill <PID>
Docker Compose:
docker compose -p old-project down
Sau đó xác minh:
sudo ss -lntp | grep ':8080' || echo 'Port 8080 is free'
Cách 2: Đổi host port
services:
web:
ports:
- "8081:3000"
Khởi động lại:
docker compose up -d --force-recreate
Truy cập http://localhost:8081.
Đây là lựa chọn tốt khi bạn cần chạy đồng thời nhiều phiên bản, ví dụ production giả lập và development.
Cách 3: Không publish port không cần thiết
Nếu API chỉ được frontend hoặc Nginx trong cùng Compose network gọi, bạn có thể không cần đưa port ra host:
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
api:
build: ./api
expose:
- "3000"
Nginx trong container gọi:
proxy_pass http://api:3000;
expose giúp mô tả cổng nội bộ nhưng không publish nó ra host. Trong cùng Compose network, các service vẫn có thể gọi nhau bằng tên service và cổng container.
6. Bind vào 127.0.0.1 hay 0.0.0.0?
ports:
- "127.0.0.1:3001:3000"
Cấu hình trên chỉ publish cổng tại loopback của host. Nó phù hợp khi Nginx trên cùng VPS sẽ proxy đến app và bạn không muốn người ngoài truy cập trực tiếp cổng 3001.
ports:
- "3001:3000"
Thông thường Docker bind lên tất cả interface host. Cổng có thể truy cập từ mạng bên ngoài nếu firewall cho phép.
Không nên mở mọi cổng ra Internet chỉ vì thấy website chưa truy cập được. Hãy xác định rõ service nào cần public.
7. Trường hợp Windows báo cổng bị cấm dù không thấy PID
Đôi khi Windows giữ một dải cổng cho hệ thống hoặc tính năng ảo hóa. Bạn có thể kiểm tra các dải TCP được loại trừ:
netsh interface ipv4 show excludedportrange protocol=tcp
Nếu cổng nằm trong dải bị loại trừ, cách an toàn nhất thường là chọn host port khác, ví dụ 8081 hoặc 18080. Không nên chỉnh dải cổng hệ thống một cách tùy tiện vì có thể ảnh hưởng Hyper-V, WSL hoặc Docker Desktop.
8. Tránh xung đột trong nhiều dự án Compose
Dùng port theo quy ước
Ví dụ:
Project A web: 3101
Project A api: 3102
Project B web: 3201
Project B api: 3202
Đặt tên project rõ ràng
docker compose -p deployeasy-dev up -d
Xem project đang chạy:
docker compose ls
Không đặt container_name khi không cần
Compose tự tạo tên dựa trên project và service. Việc hard-code container_name dễ gây xung đột khi chạy nhiều bản sao của cùng một stack.
9. Quy trình xử lý nhanh
Linux:
docker ps --format 'table {{.Names}}\t{{.Ports}}'
sudo ss -lntp | grep ':8080'
ps -fp <PID>
docker compose down # chỉ khi đúng project
Windows:
docker ps --format "table {{.Names}}\t{{.Ports}}"
netstat -ano | findstr :8080
tasklist /FI "PID eq <PID>"
Sau đó chọn một trong ba hướng: dừng tiến trình cũ, đổi host port hoặc bỏ publish port không cần thiết.
10. Checklist xác minh
- Xác định đúng host port đang xung đột.
- Tìm container hoặc PID sở hữu cổng.
- Không dừng nhầm database hay service production.
- Cập nhật
portsnếu cần chạy song song. - Chỉ publish các cổng thực sự cần truy cập từ host.
- Chạy lại
docker compose up -d. - Kiểm tra bằng
docker compose psvàcurl.
11. Câu hỏi thường gặp
Vì sao đổi 3000 bên phải mà lỗi vẫn còn?
Cổng xung đột thường nằm bên trái. Với 8080:3000, host đang giữ cổng 8080. Đổi container port không giải phóng host port đó.
docker compose down -v có nên dùng không?
Không dùng chỉ để sửa lỗi cổng. Tùy cấu hình, -v có thể xóa volume chứa database. docker compose down thường đã đủ để dừng container và giải phóng port.
Hai project có thể cùng dùng cổng container 3000 không?
Có. Mỗi container có network namespace riêng. Chúng chỉ xung đột khi cùng publish vào một host port.
Nguồn tham khảo
Đọc tiếp
Bài viết liên quan
Docker Compose không nhận .env và PostgreSQL báo password authentication failed
Phân biệt .env, env_file, environment; kiểm tra biến trong container và sửa mật khẩu PostgreSQL khi volume đã khởi tạo.
Đọc bài →Docker bị Killed hoặc Exit Code 137 trên VPS: Cách xác định đúng nguyên nhân
Hướng dẫn kiểm tra Docker Exit Code 137, OOMKilled, RAM, swap và cách tối ưu quá trình build trên VPS cấu hình thấp.
Đọc bài →Docker Compose production: Node.js, PostgreSQL và backup
Cấu hình Docker Compose production cho Node.js và PostgreSQL với healthcheck, volume, network riêng, secret, log rotation, backup và rollback.
Đọc bài →