Quay lại bài viết
22 thg 5, 2026
11 min read

AWS VPC: Hiểu VPC qua lăng kính của một Packet

Bạn vừa deploy một API e-commerce lên AWS. Theo best practice, EC2 được đặt trong private subnet — không có đường đi trực tiếp từ internet vào. Một Application Load Balancer ngồi ở public subnet đón request từ client rồi forward vào EC2.

Trong một request duy nhất, 3 hành trình mạng xảy ra bên trong VPC:

  1. Client → EC2: request từ internet đi qua IGW, ALB ở public subnet, rồi vào EC2 ở private subnet
  2. EC2 → Stripe: EC2 gọi API thanh toán bên ngoài — đi qua NAT Gateway rồi ra internet
  3. EC2 → S3: EC2 cần lấy file từ S3 — đi qua VPC Gateway Endpoint, không ra internet

Bài viết này sẽ theo dấu cả 3 hành trình, giới thiệu từng component VPC khi packet đi qua nó.

Giả định cụ thể:

EntityIP
Client (Hanoi)1.2.3.4
ALB (public subnet)Private: 10.0.1.10, Public IP: 52.10.10.10
NAT Gateway (public subnet)Private: 10.0.1.20, Public IP: 52.20.20.20
EC2 (private subnet)10.0.2.50
Stripe (third-party)3.5.6.7
S352.219.40.5
VPC CIDR10.0.0.0/16
Public Subnet CIDR10.0.1.0/24
Private Subnet CIDR10.0.2.0/24

1. VPC — Khu đô thị

Trước khi packet chạm bất kỳ component nào, nó cần biết mình đang đi vào đâu. VPC chính là ranh giới đó.

VPC là một không gian địa chỉ IP cô lập mà bạn tự định nghĩa trong AWS. Khi tạo VPC, bạn chọn một CIDR block — ví dụ 10.0.0.0/16 — và từ đó bạn có 65,536 địa chỉ IP để sử dụng. VPC scope ở cấp Region, nghĩa là nó trải rộng trên tất cả Availability Zones trong Region đó.

Hãy tưởng tượng VPC là một khu đô thị private: bạn được cấp một lô đất (CIDR block), trên đó bạn quy hoạch các khu phố (subnet), kéo đường giao thông (route table), gắn cổng ra/vào (gateway), và lắp hệ thống bảo vệ (Security Group).

Bản thân VPC không xử lý packet. Nó chỉ là container logic — mọi xử lý thực sự diễn ra ở các component bên trong. Nhưng không có VPC, không có gì tồn tại.

Một chi tiết thú vị: khi EC2 boot lên, hệ điều hành bên trong nhận IP thông qua DHCP. Thực tế IP đã được AWS pick sẵn từ trước khi OS boot — khi tạo ENI, control plane chọn IP từ subnet rồi lưu vào database. Khi đó, EC2 không biết đến địa chỉ này và cần sử dụng DHCP protocol để xác nhận IP đó.


2. Subnet — Khu phố

Trong khu đô thị VPC, bạn cần quy hoạch các khu phố — đó chính là Subnet (mạng con). Mỗi subnet chia CIDR của VPC thành dải nhỏ hơn, gắn với đúng một Availability Zone.

Trong kiến trúc của chúng ta:

  • 10.0.1.0/24Public Subnet ở AZ ap-southeast-1a — nơi ALB và NAT Gateway sống
  • 10.0.2.0/24Private Subnet ở AZ ap-southeast-1a — nơi EC2 sống

Một điều quan trọng: subnet không bẩm sinh là public hay private. Tính chất đó hoàn toàn do route table gắn vào nó quyết định:

  • Route table có 0.0.0.0/0 → igw-xxxpublic subnet (traffic đi ra internet qua IGW)
  • Route table có 0.0.0.0/0 → nat-xxxprivate subnet (traffic ra internet qua NAT Gateway)
  • Route table không có default route → isolated subnet (không ra internet được)

Đây chính là lý do EC2 ở private subnet không thể bị internet access trực tiếp — nó không có public IP, nên IGW không có mapping nào cho nó. Kể cả ai đó gửi packet đến private IP như 10.0.2.50, địa chỉ đó thuộc dải RFC 1918 (dải IP dành riêng cho mạng nội bộ) — không thể route trên internet công cộng và sẽ không bao giờ đến được AWS.

Trong mỗi subnet /24 (256 IP), AWS giữ lại 5 IP không dùng được:

IPMục đích
.0Network address
.1VPC router (gateway ảo)
.2DNS server (alias cho VPC CIDR + 2)
.3Reserved cho tương lai
.255Broadcast (VPC không hỗ trợ broadcast, nhưng vẫn reserve)

Vậy khi subnet của bạn cần 255 IP, thì CIDR /24 là không đủ, bạn sẽ cần cấp phát thêm


Flow 1: Internet → ALB → EC2

Bây giờ chúng ta bắt đầu theo dấu hành trình đầu tiên: client ở Hanoi gửi HTTPS request đến API. Packet phải đi từ internet, qua public subnet, rồi vào EC2 ở private subnet.

3. Internet Gateway — Cổng thành phố

Packet từ client 1.2.3.4 với destination 52.10.10.10 (public IP của ALB) đã đến edge network của AWS. Component đầu tiên nó gặp là Internet Gateway.

IGW làm đúng 2 việc, không hơn:

  1. Map public IP to private IP: dịch public IP sang private IP (chiều vào), và ngược lại (chiều ra)
  2. Forward packet: chuyển packet qua biên giới giữa internet và VPC

Tại hop này, IGW tra bảng mapping nội bộ và dịch:

dst: 52.10.10.10 (ALB public IP) → dst: 10.0.1.10 (ALB private IP)

Sau IGW, packet mang dst: 10.0.1.10. Từ thời điểm này, public IP không còn tồn tại bên trong VPC — mọi giao tiếp nội bộ đều qua private IP. Đây là điểm nhiều người hiểu sai: public IP chỉ “sống” ở tầng IGW, bên trong VPC không ai thấy nó.

IGW là stateless — không filter, không cache, không load balance. Nó có thể stateless vì NAT của nó là binding tĩnh 1-to-1 (một public IP luôn map với một private IP), khác với PAT của NAT Gateway phải track từng connection. Một VPC chỉ gắn được một IGW, và một IGW chỉ gắn được một VPC (nghiêm ngặt 1-to-1).

4. Route Table — Bảng chỉ đường

Packet giờ có dst: 10.0.1.10, nhưng VPC có nhiều subnet — packet đi đâu? Route Table (bảng định tuyến) trả lời câu hỏi đó.

Route Table là một bảng config chứa các rule dạng destination CIDR → target. Mỗi subnet bắt buộc phải associate với đúng một route table. Khi packet cần forward, VPC networking layer tra theo longest prefix match — rule nào có CIDR cụ thể nhất (prefix dài nhất) match destination IP sẽ thắng.

Trong kiến trúc này, 2 subnet có 2 route table khác nhau:

Public Subnet Route Table:

DestinationTargetÝ nghĩa
10.0.0.0/16localTraffic nội bộ VPC
0.0.0.0/0igw-xxxMọi traffic khác → Internet

Private Subnet Route Table:

DestinationTargetÝ nghĩa
10.0.0.0/16localTraffic nội bộ VPC
pl-xxx (S3 prefix list)vpce-xxxTraffic đến S3 → VPC Endpoint
0.0.0.0/0nat-xxxMọi traffic khác → NAT Gateway

Packet với dst: 10.0.1.10 match rule 10.0.0.0/16 → local → packet được forward đến ALB trong public subnet.

Lưu ý: route table không xử lý packet — nó chỉ là config. Thực tế việc forward diễn ra ở Nitro card (phần cứng SmartNIC mà AWS gắn vào mỗi host vật lý, ví dụ như IGW, ALB, EC2, …) khi đọc config từ route table.

5. ALB nhận request, forward đến EC2

Packet đến ALB ở public subnet. ALB terminate connection của client — nghĩa là TCP connection từ client kết thúc ở đây. ALB xử lý request rồi tạo một connection hoàn toàn mới đến EC2 ở private subnet.

Lưu ý về IP của ALB: khác với EC2 có thể giữ Elastic IP cố định, internet-facing ALB không có public IP cố định. AWS gán IP động cho các ENI của ALB (mỗi AZ một ENI), và IP này có thể thay đổi bất cứ lúc nào. Vì vậy bạn luôn phải trỏ DNS vào DNS name của ALB (ví dụ my-alb-123456.ap-southeast-1.elb.amazonaws.com), không trỏ vào IP. IP 52.10.10.10 trong bảng giả định chỉ là ảnh chụp tại thời điểm trace packet.

Packet mới do ALB tạo ra:

src: 10.0.1.10 (ALB private IP) dst: 10.0.2.50 (EC2 private IP)

Client IP ban đầu (1.2.3.4) được ALB gắn vào HTTP header X-Forwarded-For để EC2 biết ai là người gửi thật.

Packet này cần đi từ public subnet sang private subnet. Route table tra: dst: 10.0.2.50 match 10.0.0.0/16 → local — traffic nội bộ VPC, forward qua ranh giới subnet.

6. Tổng kết Flow 1

Tổng kết transformation tại mỗi hop:

#Componentsrc IPdst IPHành động
1IGW1.2.3.452.10.10.1010.0.1.10NAT 1:1
2Route Table1.2.3.410.0.1.10local → ALB
3ALB1.2.3.410.0.1.1010.0.1.1010.0.2.50New connection
4Route Table10.0.1.1010.0.2.50local → private subnet
5SG10.0.1.1010.0.2.50Stateful check (ref SG)
6EC210.0.1.1010.0.2.50App nhận request

Flow 2: EC2 → S3 — Đường tắt nội bộ

EC2 nhận request từ client, giờ cần lấy một file ảnh từ S3 bucket. Theo route table của private subnet, traffic đến internet sẽ đi qua NAT Gateway → IGW → Internet → S3. Nhưng S3 cũng là service AWS — tại sao phải đi vòng qua internet, vừa chậm vừa tốn tiền NAT Gateway?

8. VPC Gateway Endpoint — Không qua internet, không tốn tiền

VPC Endpoint (điểm kết nối nội bộ VPC) giải quyết đúng vấn đề này. Với S3 và DynamoDB, AWS cung cấp Gateway Endpoint — một target trừu tượng trong route table, không có ENI, không có IP.

Khi bạn tạo Gateway Endpoint cho S3, AWS tự thêm route vào route table:

DestinationTarget
pl-xxx (S3 prefix list)vpce-xxx

Flow khi EC2 gọi S3:

  1. EC2 tạo HTTPS request đến s3.amazonaws.com src 10.0.2.50, dst 52.219.40.5 (IP của S3)
  2. Route Table (private subnet) match với rule pl-s3 → vpce-s3-xxx. Forward qua AWS Backbone Network (không ra internet)
  3. S3 nhận request, src vẫn là 10.0.2.50 (KHÔNG bị NAT)

Điểm đặc biệt của Gateway Endpoint:

  • Không có ENI, không có IP — nó chỉ là một rule trong route table
  • Không NAT source IP — S3 thấy request đến từ 10.0.2.50 (private IP của EC2). Điều này cho phép bucket policy restrict theo VPC Endpoint (aws:sourceVpce)
  • Hoàn toàn miễn phí — không tính theo giờ, không tính theo GB

Ngoài Gateway Endpoint (chỉ cho S3 và DynamoDB), AWS còn có Interface Endpoint (PrivateLink) cho hầu hết service khác (SSM, SQS, Secrets Manager, ECR, …). Interface Endpoint tạo một ENI thật trong subnet với private IP, có Security Group, nhưng tốn tiền theo giờ + GB.


Flow 3: EC2 → Stripe — Ra internet qua NAT Gateway

EC2 xử lý xong request, giờ cần gọi api.stripe.com để charge credit card. Stripe là third-party service nằm ngoài AWS — packet phải ra internet. Nhưng EC2 ở private subnet, không có route đến IGW. Làm sao?

9. NAT Gateway — Cổng ra internet cho private subnet

NAT Gateway nằm ở public subnet, có Elastic IP, cho phép resource ở private subnet gửi request ra internet nhưng chặn internet gửi request vào.

Tại sao cần NAT Gateway? Toàn bộ service trong private subnet chỉ có private IP, không có Elastic IP — mà internet không biết route đến private IP, nên chúng không thể giao tiếp trực tiếp với internet. NAT Gateway nằm ở public subnet, có EIP, đóng vai trò đại diện cho các service trong private subnet: nó nhận packet từ chúng, thay source IP bằng EIP của mình, rồi gửi ra internet thay.

Nhưng một NAT Gateway chỉ có một EIP — làm sao đại diện cho hàng chục, hàng trăm service cùng lúc? Câu trả lời nằm ở port. NAT Gateway sử dụng kỹ thuật PAT: mỗi connection từ private subnet được gán một port riêng trên EIP. Ví dụ, EC2 10.0.2.50 mở connection đến Stripe → NAT Gateway gán port 40001, cùng EC2 đó mở thêm connection đến logging service → gán port 40002. Khi response trả về EIP trên port 40001, NAT Gateway tra bảng mapping, biết port này thuộc về connection Stripe của 10.0.2.50 và chuyển response về đúng chỗ.

Port được gán theo từng connection (theo bộ 5 giá trị gọi là 5-tuple: source IP, source port, destination IP, destination port, protocol), không phải theo từng EC2. Một EC2 có thể dùng hàng nghìn port nếu nó mở nhiều connection đồng thời. Đây là lý do NAT Gateway có giới hạn khoảng 55,000 connection đồng thời cho mỗi destination — xấp xỉ số ephemeral port khả dụng trên một EIP.

Flow cụ thể:

  1. EC2 (10.0.2.50) tạo packet src 10.0.2.50, dst 3.5.6.7
  2. Route Table (private subnet) match 3.5.6.7 với rule 0.0.0.0/0 → nat-xxx. Forward đến NAT Gateway
  3. Sau khi đi qua NAT Gateway (public subnet, private IP: 10.0.1.20), src 10.0.2.50src 10.0.1.20. Lưu connection vào tracking table (nhớ 10.0.2.50 để dịch ngược)
  4. Route Table (public subnet) match 3.5.6.7 với rule 0.0.0.0/0 → igw-xxx. Forward đến IGW
  5. Sau khi đi qua Internet Gateway, nó sẽ dịch private IP thành EIP của NAT Gateway src 10.0.1.20src 52.20.20.20
  6. Internet Stripe thấy request từ 52.20.20.20

Chú ý 2 lần NAT xảy ra trên đường đi:

HopTrướcSauLoại NAT
NAT Gatewaysrc: 10.0.2.50src: 10.0.1.20Many-to-1 (nhiều EC2 share 1 IP)
IGWsrc: 10.0.1.20src: 52.20.20.201-to-1 (EIP mapping)

So sánh nhanh IGW vs NAT Gateway:

IGWNAT Gateway
Vị tríBiên giới VPCPublic subnet
NAT loại1-to-1 (mỗi EIP map 1 private IP)Many-to-1 (nhiều private IP share 1 EIP)
ChiềuHai chiều (in + out)Chỉ chiều ra (chặn inbound không mời, cho phép return traffic nhờ connection tracking)
Có ENI?Không
Cần Elastic IP?Không (gắn vào resource)Có, cho Public NAT GW (Private NAT GW thì không cần)
Chi phíMiễn phíTính theo giờ + GB data

Tổng kết

Qua 3 hành trình, bạn đã gặp tất cả component chính trong VPC — không phải qua danh sách, mà qua chính công việc thực tế của chúng:

ComponentBạn gặp ở FlowCông việc thuần tuý
VPCTất cảKhông gian địa chỉ cô lập
SubnetTất cảChia VPC thành các vùng, gắn theo AZ
Route TableTất cảBảng config: destination → target
IGWFlow 1, 3NAT 1:1 + forward qua biên giới internet
ALBFlow 1Terminate connection, forward đến backend
ENIFlow 1Card mạng ảo, giữ IP + SG
Security GroupFlow 1Stateful firewall ở ENI level
VPC EndpointFlow 2Đường tắt đến AWS service, không qua internet
NAT GatewayFlow 3Source NAT cho private subnet ra internet

Khi debug connectivity, hãy nghĩ theo hành trình của packet:

  • Client không vào được? → IGW attached chưa? ALB SG có mở port 443 không?
  • ALB không forward được đến EC2? → EC2 SG có reference ALB SG không?
  • EC2 không gọi được S3? → Gateway Endpoint đã tạo chưa? Route table có rule cho S3 prefix list không?
  • EC2 không gọi được third-party API? → NAT Gateway tạo chưa? Route table private subnet có 0.0.0.0/0 → nat-xxx không?

Bạn có thể dùng VPC Reachability Analyzer — một tool của AWS cho phép bạn chọn source và destination, rồi nó tự phân tích path và chỉ ra chính xác packet bị chặn ở đâu.

Liên quan