Ping được nhưng không connect được

5 câu hỏi~30 phútTừ khóa: ICMP, TCP connect, Connection refused, timed out, server.address, ufw, firewalld, NSG, Security Group, inbound/outbound, nc, Test-NetConnection

Trước giờ mình chưa phân biệt được "ping tới" và "connect được tới", cũng không biết là cần mở port. Ping VM thấy trả lời rồi mà gọi API vẫn không được. Giải thích giúp mình.

Đây là nhầm lẫn rất phổ biến. Nhớ một câu: ping được chỉ chứng minh tới được máy, không chứng minh vào được app.

1. Bài toán

order-service chạy trên Azure VM 10.0.1.4, port 8080. Developer ở VM khác cùng VNet thử:

$ ping 10.0.1.4
64 bytes from 10.0.1.4: icmp_seq=1 ttl=64 time=1.2 ms     <-- OK

$ curl http://10.0.1.4:8080/orders/123
curl: (28) Failed to connect to 10.0.1.4 port 8080: Connection timed out

"Máy sống mà sao không gọi được?"

2. Vấn đề: ping và connect là hai thứ khác nhau

pingconnect (curl, JDBC, browser)
Giao thứcICMP (echo request/reply)TCP
Có port không?KhôngCó, ví dụ 8080
Ai trả lời?Kernel của máy đíchKernel + một process đang listen port đó
Chứng minhCó đường tới máy (nếu ICMP không bị chặn)Vào được đúng app

Ví von: ping là đứng dưới đường gọi "tòa nhà ơi" và có bảo vệ đáp lại. Connect là lên đúng phòng 8080 gõ cửa. Tòa nhà có thể đang mở, nhưng:

3. Giải pháp: 4 nguyên nhân và dấu hiệu

Nguyên nhân 1: App không chạy hoặc sai port → Connection refused

curl: (7) Failed to connect to 10.0.1.4 port 8080: Connection refused

Gói SYN tới được máy, nhưng không có process listen 8080, kernel trả RST ngay. Refused thì nhanh, chứng tỏ firewall không chặn. Kiểm tra: app crash, đang chạy 8081, hay chưa start.

Nguyên nhân 2: App bind 127.0.0.1 → refused từ máy khác

sudo ss -ltnp | grep 8080
LISTEN 0 100 127.0.0.1:8080  users:(("java",pid=1234))

Trên VM curl localhost:8080 được, máy khác thì refused. Sửa:

server:
  address: 0.0.0.0   # hoặc bỏ dòng address (mặc định là mọi interface)

Trong Docker cũng vậy: app trong container phải listen 0.0.0.0 và phải có -p 8080:8080.

Nguyên nhân 3: Firewall của OS → timed out

Ubuntu dùng ufw, RHEL dùng firewalld, Windows có Windows Defender Firewall. Mặc định chặn inbound nên SYN bị vứt im lặng, client chờ đến hết timeout.

Nguyên nhân 4: Firewall của cloud (Azure NSG / AWS Security Group) → timed out

Gói tin bị chặn trước cả khi tới VM. Bạn mở ufw rồi vẫn timeout là vì lớp này. Azure NSG mặc định cho phép trong VNet (AllowVnetInBound) nhưng chặn inbound từ Internet; khi tạo VM thường chỉ mở 22.

Laptop ──Internet──> [NSG / Security Group] ──> [ufw / firewalld] ──> [process listen?] ──> App
                         chặn: timeout              chặn: timeout      không có: refused
                                                                       bind 127.0.0.1: refused

4. Debug từng bước

Bước 1: Tới được máy chưa?

ping 10.0.1.4        # không trả lời chưa chắc là chết: ICMP có thể bị chặn

Bước 2: Test đúng port, từ máy client

# Linux / macOS
nc -zv 10.0.1.4 8080
curl -v http://10.0.1.4:8080/actuator/health

# Windows PowerShell
Test-NetConnection 10.0.1.4 -Port 8080
# TcpTestSucceeded : True / False

Bước 3: Trên VM, app có listen không, listen ở đâu?

sudo ss -ltnp | grep 8080
curl -v http://localhost:8080/actuator/health   # local được -> app ổn, lỗi ở lớp mạng
sudo journalctl -u order-service -n 50          # nếu chạy bằng systemd

Bước 4: Firewall OS

sudo ufw status
sudo ufw allow 8080/tcp
# hoặc chỉ cho một subnet:
sudo ufw allow from 10.0.0.0/24 to any port 8080 proto tcp

# RHEL / CentOS
sudo firewall-cmd --add-port=8080/tcp --permanent && sudo firewall-cmd --reload

Bước 5: Firewall cloud (Azure NSG)

az network nsg rule create \
  --resource-group rg-orders --nsg-name order-vm-nsg \
  --name allow-8080-from-dev --priority 310 \
  --direction Inbound --access Allow --protocol Tcp \
  --source-address-prefixes 10.0.0.0/24 \
  --destination-port-ranges 8080

Nên giới hạn source-address-prefixes, đừng để * (cả Internet).

Bước 6: Test lại

nc -zv 10.0.1.4 8080
Connection to 10.0.1.4 8080 port [tcp/*] succeeded!

5. Cách hoạt động: bảng giải mã thông báo lỗi

Thông báoChuyện gì xảy raNghi ngờ
Connection refusedTới máy, nhận RST ngayApp không chạy, sai port, bind 127.0.0.1
Connection timed outSYN đi mà không ai đápFirewall OS/cloud, sai IP, máy tắt
No route to hostKhông có đường/host không có trong mạng, hoặc firewall reject bằng ICMPSai subnet, routing, firewalld reject
Unknown host / Could not resolve hostChưa tới bước mạng, DNS lỗiSai tên, DNS (bài 9.4)
Kết nối được nhưng Empty reply / resetApp nhận rồi đóngGọi HTTP vào port HTTPS, proxy cấu hình sai

Trong Java: java.net.ConnectException: Connection refused, java.net.SocketTimeoutException: Connect timed out, java.net.UnknownHostException.

6. So sánh: chiều ngược lại, ping không được nhưng connect được

$ ping 203.0.113.10
Request timed out.

$ curl -I https://api.example.com
HTTP/2 200

Hoàn toàn bình thường. Nhiều cloud/firewall chặn ICMP (Azure Load Balancer public không trả ping, nhiều công ty chặn ICMP ra ngoài). Vì vậy đừng dùng ping để kết luận service chết, luôn test bằng TCP tới đúng port.

pingnc/curl portKết luận
OKOKMọi thứ ổn
OKrefusedMáy ổn, app/port/bind sai
OKtimeoutFirewall chặn port
FailOKICMP bị chặn, app ổn
FailtimeoutMáy tắt, sai IP, hoặc chặn hết

7. Vì sao phải "mở port", và mở thế nào cho an toàn

Internet ──443──> Nginx (VM app) ──127.0.0.1:8080──> order-service
                                                       │ 5432, chỉ từ 10.0.1.0/24
                                                       v
                                                  Postgres VM 10.0.2.5
NSG db-vm: Allow TCP 5432 from 10.0.1.0/24; Deny còn lại
pg_hba.conf: host orders app_user 10.0.1.0/24 scram-sha-256

SSH 22 cũng vậy: chỉ cho IP quản trị hoặc dùng Azure Bastion.

Mở port rồi mà vẫn không được?

Thường là mới mở một trong hai lớp. Kiểm tra lần lượt:

  1. Đã mở cả ufw và NSG chưa? NSG có thể gắn ở cả NIC và subnet, phải cho phép ở cả hai.
  2. Rule NSG có priority thấp hơn (ưu tiên hơn) một rule Deny nào không?
  3. Source prefix có đúng IP của bạn không? Từ laptop ra Internet, IP nguồn là IP public của nhà/công ty, không phải IP LAN.
  4. App có listen 0.0.0.0 không (ss -ltnp)?
  5. Bạn gọi IP public hay private? Từ laptop ngoài Azure phải gọi IP public (VM phải có public IP hoặc qua LB).
  6. Mạng công ty có chặn outbound port lạ như 8080 không? Thử từ mạng khác.

Vì sao gọi localhost được mà IP thì không?

Đúng như bạn đoán, có khác biệt ở đường đi. localhost đi qua interface loopback, không qua card mạng, thường không bị firewall chặn. Gọi bằng IP 10.0.1.4 thì đi qua interface mạng thật. Hai lý do hay gặp:

Thêm một bẫy: localhost có thể resolve ra ::1 (IPv6) trong khi app chỉ listen IPv4, hoặc ngược lại. Gặp chuyện lạ thì thử thẳng 127.0.0.1.

Order-service gọi Postgres bị SocketTimeoutException: Connect timed out, mình mở port 5432 cho cả Internet cho nhanh được không?

Chạy thì được nhưng không nên. Database mở ra Internet sẽ bị quét và dò password liên tục. Đúng cách:

# Từ VM app, test đúng chiều
nc -zv 10.0.2.5 5432

Phỏng vấn hỏi "ping được nhưng không gọi được API" thì trả lời sao?

Q1. Server ping được nhưng không gọi được API, bạn debug thế nào?

🇻🇳 Tiếng Việt:

Ping dùng ICMP, không có port, nên chỉ chứng minh tới được máy. Em test TCP đúng port bằng nc -zv hoặc Test-NetConnection. Nếu refused thì app không chạy, sai port hoặc bind 127.0.0.1, em kiểm tra bằng ss -ltnp. Nếu timeout thì firewall chặn: kiểm tra firewall OS (ufw/firewalld) và firewall cloud (NSG/Security Group). Cuối cùng curl -v để xem tầng HTTP.

🇬🇧 English:

Ping uses ICMP, which has no ports, so it only proves the host is reachable. I test TCP on the actual port with nc -zv or Test-NetConnection. If it is refused, the app is not running, is on another port, or is bound to 127.0.0.1, which I check with ss -ltnp. If it times out, a firewall is dropping packets, so I check the OS firewall such as ufw or firewalld and the cloud firewall such as an NSG or Security Group. Finally I use curl -v to check the HTTP layer.

Q2. Connection refused khác connection timed out thế nào?

🇻🇳 Tiếng Việt:

Refused nghĩa là gói tin tới được máy nhưng không có process listen, kernel trả RST ngay. Timed out nghĩa là không ai trả lời, thường do firewall drop gói, sai IP hoặc máy tắt.

🇬🇧 English:

Refused means the packet reached the host but nothing was listening, so the kernel replied with RST immediately. Timed out means nobody answered, usually because a firewall dropped the packet, the IP is wrong, or the host is down.

Q3. Mở port database thế nào cho an toàn?

🇻🇳 Tiếng Việt:

Firewall mặc định deny inbound, em chỉ mở đúng port cần, từ đúng nguồn cần. Postgres 5432 chỉ cho subnet của application, không mở Internet. Thêm pg_hba.conf giới hạn subnet, admin truy cập qua VPN hoặc Bastion. App thì expose 443 qua Nginx, giữ 8080 nội bộ.

🇬🇧 English:

Firewalls deny inbound by default, so I only open the ports needed, from the sources that need them. Postgres on 5432 is allowed only from the application subnet, never from the Internet, and pg_hba.conf restricts it too. Admins connect through a VPN or Bastion. The application exposes only 443 through Nginx and keeps 8080 internal.

Cách nhớ ngắn gọn


Tự kiểm tra

Vì sao ping không thể dùng để kiểm tra port 8080?

Ping dùng ICMP, không có khái niệm port. Phải dùng TCP: nc -zv host 8080, curl -v, Test-NetConnection -Port 8080.

Gặp Connection refused, bạn kiểm tra gì đầu tiên?

Trên server: ss -ltnp xem app có chạy, đúng port, và bind 0.0.0.0 hay 127.0.0.1.

Đã ufw allow 8080/tcp mà vẫn timeout từ laptop. Lý do có thể?

NSG/Security Group của cloud chưa mở, source prefix sai, gọi IP private từ ngoài, hoặc mạng công ty chặn outbound.

Ping không được nhưng curl https được, có mâu thuẫn không?

Không. ICMP bị chặn còn TCP 443 được mở.

Vì sao không cần mở port cho gói trả lời?

Firewall stateful tự cho phép traffic thuộc connection đã được thiết lập.