Fix nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)

beginner Nginx2026-03-23| Linux (Ubuntu, Debian, CentOS, RHEL), Nginx 1.x, chạy với user không phải root hoặc thiếu capabilities

Error Message

nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
#nginx#bind#permission#port#emerg

Lỗi Gặp Phải

Bạn khởi động hoặc tải lại Nginx và ngay lập tức thấy thông báo này trong terminal hoặc log:

nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
nginx: [emerg] bind() to 0.0.0.0:443 failed (13: Permission denied)
nginx: [emerg] still could not bind()

Nginx thoát ra. Không có traffic nào được phục vụ. Toàn bộ hệ thống dừng lại.

Nguyên Nhân

Linux coi các cổng dưới 1024 là cổng đặc quyền. Chỉ root — hoặc tiến trình được cấp quyền CAP_NET_BIND_SERVICE một cách tường minh — mới có thể bind chúng. Thông thường, Nginx khởi động với quyền root, chiếm cổng 80 và 443, sau đó fork các tiến trình worker dưới một user bị hạn chế như www-data hoặc nginx. Lỗi này có nghĩa là tiến trình master chưa bao giờ đến được bước binding đó. Các nguyên nhân phổ biến:

  • Nginx được khởi chạy trực tiếp với user không phải root
  • Binary thiếu capability CAP_NET_BIND_SERVICE
  • Một service override của systemd chạy Nginx với user không có đặc quyền ngay từ đầu
  • Một container hoặc sandbox đang chặn quyền truy cập cổng đặc quyền

Cần lưu ý: đây không phải lỗi Address already in use. Cổng ở đây hoàn toàn trống — Nginx chỉ đơn giản là không có quyền để chiếm nó.

Cách Khắc Phục Từng Bước

1. Kiểm tra cách Nginx đang được khởi động

Trước khi chỉnh sửa bất cứ thứ gì, hãy tìm hiểu user nào đang thực sự chạy Nginx:

ps aux | grep nginx
# hoặc kiểm tra systemd unit:
systemctl cat nginx

Nếu dòng User= trong file service trỏ đến một tài khoản không phải root và không có capabilities nào được thiết lập, đó chính là vấn đề của bạn.

2. Khởi động Nginx với quyền root (cách thông thường)

Nginx được thiết kế để khởi động với quyền root. Tiến trình master bind các cổng trước, sau đó ngay lập tức chuyển xuống user worker được định nghĩa trong nginx.conf. Không cần thiết lập gì đặc biệt.

sudo systemctl start nginx
# hoặc trực tiếp:
sudo nginx

Nếu cách này hoạt động, lần khởi động trước của bạn đã bỏ sót sudo. Đó là toàn bộ vấn đề.

3. Cấp CAP_NET_BIND_SERVICE cho binary (khi chạy không cần root)

Bạn muốn chạy Nginx mà không cần root theo thiết kế? Hãy chỉ cấp đúng capability mà nó thực sự cần:

sudo setcap 'cap_net_bind_service=+ep' /usr/sbin/nginx

Xác nhận capability đã được thiết lập:

getcap /usr/sbin/nginx
# Kết quả mong đợi:
# /usr/sbin/nginx cap_net_bind_service=+ep

Xong. Nginx giờ có thể bind cổng 80 và 443 mà không cần quyền root.

4. Khắc phục systemd service bị cấu hình sai

Đôi khi vấn đề nằm ở chính file unit — systemd đang hạ quyền trước khi Nginx thậm chí thử bind. Hãy override service để khắc phục:

sudo systemctl edit nginx

Thiết lập để tiến trình master khởi động với quyền root:

[Service]
User=root

Áp dụng thay đổi:

sudo systemctl daemon-reload
sudo systemctl restart nginx

5. Môi trường Docker / container

Các container thường chặn cổng đặc quyền theo mặc định. Bạn có hai lựa chọn sạch:

Lựa chọn A — Để Nginx lắng nghe trên cổng cao (ví dụ: 8080) bên trong container, và để Docker ánh xạ nó sang cổng 80 trên host:

docker run -p 80:8080 my-nginx-image

Cập nhật cấu hình Nginx bên trong container:

listen 8080;

Lựa chọn B — Thêm capability NET_BIND_SERVICE trực tiếp vào container:

docker run --cap-add=NET_BIND_SERVICE -p 80:80 my-nginx-image

Kiểm Tra Sau Khi Sửa

Sau khi áp dụng bất kỳ cách khắc phục nào ở trên, hãy kiểm tra Nginx có thực sự đang chạy không:

sudo systemctl status nginx

Tìm trạng thái active (running). Sau đó xác nhận nó đang lắng nghe đúng cổng:

sudo ss -tlnp | grep nginx
# hoặc:
sudo netstat -tlnp | grep :80

Kết quả mong đợi:

LISTEN  0  511  0.0.0.0:80   0.0.0.0:*  users:(("nginx",pid=1234,fd=6))

Cuối cùng, gửi một request nhanh để đảm bảo traffic thực sự đang được xử lý:

curl -I http://localhost

Lưu Ý Thêm

  • Đừng nhầm lẫn với lỗi 403 Forbidden — lỗi này xảy ra lúc khởi động, ở tầng OS socket. Nó không liên quan gì đến web root hay quyền file của bạn.
  • Nâng cấp gói Nginx sẽ xóa thiết lập setcap. Capability được gắn với file binary. Mỗi khi cập nhật gói thay thế /usr/sbin/nginx, bạn sẽ cần chạy lại setcap. Hãy cân nhắc thêm nó vào post-install hook hoặc deploy script.
  • Kiểm tra SELinux hoặc AppArmor trước trên RHEL/CentOS. Ngay cả root cũng có thể bị chặn trên các hệ thống SELinux đang ở chế độ enforcing. Chạy getenforce để xem chế độ hiện tại. Nếu là Enforcing, dùng semanage port -a -t http_port_t -p tcp 80 để cho phép cổng một cách tường minh.
  • Nếu bạn đang xử lý các vấn đề quyền file liên quan — như chmod trên socket file hoặc thư mục log — thì Unix Permissions Calculator trên ToolCraft rất tiện dụng. Nó cho phép bạn xây dựng giá trị chmod một cách trực quan mà không cần ghi nhớ ký hiệu octal.

Related Error Notes