Logo

Personal Ops Runbook

Personal runbook covering infrastructure operations for Cloud, Kubernetes, OpenStack, and Ceph environments. Includes deployment and teardown procedures, node management, cluster monitoring setup, and incident response workflows compiled from day-to-day operational work. Intended strictly for personal reference — configurations and scripts are environment-specific and not guaranteed to work as-is elsewhere.

Hiểu về ip_local_port_range: Vì sao bạn không nên chạy dịch vụ trên các cổng nằm trong dải này?


1. Tổng quan

Khi phát triển ứng dụng backend hoặc triển khai hệ thống phân tán, một trong những lỗi phổ biến mà nhiều kỹ sư gặp phải là:

OSError: [Errno 98] Address already in use

Thông báo trên thường xuất hiện khi một ứng dụng cố gắng mở dịch vụ (LISTEN) trên một cổng đã bị chiếm dụng. Tuy nhiên, trong một số trường hợp, dù không có tiến trình nào rõ ràng đang "LISTEN", lỗi này vẫn xảy ra. Nguyên nhân sâu xa có thể đến từ một cơ chế của hệ điều hành Linux: ip_local_port_range.


2. ip_local_port_range là gì?

ip_local_port_range là dải cổng (port range) mà hệ điều hành sử dụng để gán ngẫu nhiên cho các kết nối outbound (ví dụ: khi máy A kết nối đến máy B).

Ví dụ:

Khi máy chủ thực hiện kết nối TCP outbound:

[ 10.10.10.1:60001 ] ---> [ 10.10.10.2:5432 ]
  • 60001cổng tạm thời (ephemeral port) do kernel chọn từ ip_local_port_range
  • 5432 là cổng của PostgreSQL mà máy đích đang lắng nghe

2.1 Cách kiểm tra

cat /proc/sys/net/ipv4/ip_local_port_range

Kết quả:

1025 65000

Tức là Linux sẽ chọn các cổng từ 1025 đến 65000 để làm cổng nguồn cho các kết nối outbound.


3. Minh họa luồng kết nối

┌────────────────────────┐                 ┌────────────────────────────┐
│   APP (Flask, etc.)       connect to          Database/PostgreSQL   │
│                         ─────────────▶        10.10.10.2:5432       │
│   10.10.10.1:60001                                                  │
└────────────────────────┘                 └────────────────────────────┘
  • Cổng 60001 được lấy từ ip_local_port_range để tạo socket kết nối ra ngoài
  • Nếu một ứng dụng khác cố tình bind vào cổng 60001, xung đột có thể xảy ra

4. Ví dụ thực tế

4.1 Flask bị lỗi do port bị chiếm

Bạn chạy Flask trên port 60001:

python3 app.py

Lỗi:

OSError: [Errno 98] Address already in use

Bạn kiểm tra:

netstat -tlnp | grep 60001

Không thấy gì. Nhưng khi chạy:

lsof -i :60001

Thấy:

ceph-osd  3013825 ceph  628u  TCP 10.10.10.1:60001->10.10.10.2:6836 (ESTABLISHED)

Tức là cổng 60001 đang được dùng làm outbound TCP socket.


5. Vì sao không nên bind dịch vụ vào các port trong dải này?

5.1 Nguy cơ xung đột

Hệ điều hành có quyền chọn bất kỳ cổng nào trong ip_local_port_range để dùng làm source port. Nếu bạn cố bind dịch vụ vào cổng đó, sẽ dễ gây lỗi.

5.2 Khó debug

Các kết nối outbound không ở trạng thái LISTEN, khiến các công cụ như netstat -tlnp không phát hiện được, dẫn đến hiểu nhầm là port còn trống.


6. Giải pháp

6.1 Tránh dùng cổng trong ip_local_port_range

  • Kiểm tra dải cổng:
cat /proc/sys/net/ipv4/ip_local_port_range
  • Tránh dùng các port trong khoảng này để chạy dịch vụ backend, frontend, proxy, etc.

6.2 Sử dụng cổng ngoài dải ephemeral

Một số cổng gợi ý:

Cổng Ứng dụng thường dùng Ghi chú
80 HTTP Cần root
443 HTTPS Cần root
5000 Flask Mặc định
8000 Django, uvicorn Rất phổ biến
8080 Dev server, reverse proxy Thường dùng
8888 Jupyter Notebook An toàn
≥65001 Nếu dải ephemeral kết thúc tại 65000 Có thể dùng

6.3 Thay đổi dải ephemeral port (nếu cần thiết)

Chỉ thực hiện khi bạn kiểm soát hoàn toàn hệ thống và có lý do chính đáng.

Tạm thời:

echo "20000 40000" > /proc/sys/net/ipv4/ip_local_port_range

Vĩnh viễn:

echo "net.ipv4.ip_local_port_range = 20000 40000" >> /etc/sysctl.conf
sysctl -p

7. Giải pháp tương đương nếu bạn cần chạy nhiều dịch vụ

Giải pháp Miễn phí License Ghi chú
NGINX reverse proxy BSD Gộp nhiều dịch vụ qua 1 port như 80/443
HAProxy GPL Cân bằng tải, routing nâng cao
Caddy Apache Tự động HTTPS, cấu hình đơn giản
Systemd socket activation GPL Chia sẻ socket giữa các service (nâng cao)

8. Lời khuyên

  • Không nên dùng bất kỳ cổng nào trong ip_local_port_range để bind dịch vụ.
  • Luôn kiểm tra dải ephemeral trước khi chọn port cho ứng dụng backend.
  • Nếu bạn cần nhiều cổng, nên dùng reverse proxy để gom về 1 port chuẩn.
  • Tránh hardcode port trùng với cổng của các service phổ biến như Ceph, Docker, Kubernetes...

9. Tài liệu tham khảo