← Cloud · AWS← Cloud · AWS
Cloud · AWSCloud · AWS19 Th7, 2026Jul 19, 202622 phút đọc18 min read

Networking & VPCNetworking & VPC

Part of the Cloud knowledge base — AWS deep dive. Complements DevOps Roadmap.

Tổng quan

Networking là nơi AWS giống nhất với việc vận hành một data center của riêng bạn, bởi vì nó đúng là một data center — chỉ được ảo hóa. Virtual Private Cloud (VPC) là một lát cắt được cô lập về mặt logic của mạng AWS mà bạn hoàn toàn kiểm soát: bạn chọn dải địa chỉ IP, chia nó thành các subnet, quyết định cái gì có thể tiếp cận được từ internet và cái gì không, và đặt firewall ở mọi lớp. Gần như mọi workload bạn chạy — EC2, RDS, ECS, EKS, Lambda-trong-VPC — đều sống bên trong một VPC, nên một mô hình tư duy lung lay về networking sẽ làm suy yếu mọi thứ ở bên trên nó.

Trang này được xây từ trong ra ngoài: VPC và các subnet của nó, cách traffic đi vào và đi ra (gateway và route table), hai lớp firewall (security group và NACL), cách các VPC kết nối với nhau và với on-prem (peering, Transit Gateway, PrivateLink), cách bạn phân phối traffic (Elastic Load Balancing), cách người dùng tìm thấy bạn (Route 53 DNS), cách bạn cache trên phạm vi toàn cầu (CloudFront), và cách bạn thấy được điều đang diễn ra (Flow Logs). Nó khép lại bằng việc lập kế hoạch CIDR và một bố cục VPC tối giản, thực tế bằng Terraform.

Mô hình tư duy cốt lõi: một VPC là một mạng riêng bạn sở hữu; một subnet là một lát cắt của nó ghim vào một AZ; một route table quyết định traffic của một subnet đi đâu; và các gateway là những cánh cửa ra thế giới bên ngoài. “Public” và “private” subnet không phải là một cài đặt — chúng là hệ quả của việc route table của chúng trỏ tới đâu.

Kiến thức nền tảng

VPC và subnet

Public vs private subnet — điểm khác biệt định danh:

Public subnetPrivate subnet
Route table có route tớiInternet Gateway (0.0.0.0/0 → IGW)NAT Gateway hoặc không có gì
Inbound từ internetCó thể (với một public/Elastic IP)Không bao giờ trực tiếp
Outbound ra internetTrực tiếp qua IGWQua NAT (trong một public subnet) hoặc không có
Cư dân điển hìnhLoad balancer, bastion host, NAT gatewayApp server, database, internal service

Quy tắc kinh nghiệm: đặt càng ít càng tốt vào public subnet. Chỉ có các internet-facing load balancer và NAT gateway mới thực sự cần ở đó. App server và database thuộc về private subnet, chỉ tiếp cận được thông qua load balancer.

Gateway, route table, và IP

Route table là bộ não định tuyến. Mỗi subnet được liên kết với đúng một route table; bảng này là một danh sách destination CIDR → target. Route local (CIDR của chính VPC → local) luôn hiện diện và không thể bị xóa — đó là cái cho phép các subnet nói chuyện với nhau. Mọi thứ khác bạn tự thêm: 0.0.0.0/0 → igw-... làm cho một subnet thành public; 0.0.0.0/0 → nat-... cho một private subnet outbound.

Hai lớp firewall: Security Group vs NACL

AWS cho bạn hai bộ lọc packet độc lập. Hiểu sự khác biệt là điều thiết yếu.

Security Group (SG)Network ACL (NACL)
Hoạt động ởCấp instance/ENICấp subnet
Stateful?Stateful — traffic trả về tự động được cho phépStateless — phải cho phép traffic trả về một cách tường minh
RuleChỉ Allow (implicit deny)Cả Allow Deny, đánh giá theo số thứ tự rule
Mặc địnhDeny tất cả inbound, allow tất cả outboundNACL mặc định allow tất cả; NACL custom deny tất cả
Có thể tham chiếuCác security group khác (và CIDR)Chỉ CIDR
Đánh giáTất cả rule được xét cùng nhauRule khớp đầu tiên thắng (theo thứ tự số)

Stateful vs stateless là cái bẫy. Một security group chỉ cần một rule inbound cho port 443; response tự động được cho phép vì SG ghi nhớ kết nối. Một NACL, vì là stateless, cần cả một rule inbound cho 443 lẫn một rule outbound cho các ephemeral return port (1024–65535) — quên cái thứ hai và các kết nối sẽ treo một cách bí ẩn.

Hướng dẫn thực tế: làm gần như tất cả công việc của bạn với security group — chúng là stateful, có thể tham chiếu lẫn nhau (ví dụ “cho phép web SG tiếp cận DB SG ở port 5432” mà không cần địa chỉ IP nào cả), và dễ suy luận hơn nhiều. Dùng NACL một cách tiết kiệm như một backstop thô ở cấp subnet, chủ yếu cho các rule deny tường minh (chặn một dải IP xấu) mà SG không thể biểu diễn.

Lập kế hoạch CIDR

Làm đúng kế hoạch địa chỉ ngay từ đầu giúp tránh việc phải tái kiến trúc đau đớn về sau.

PrefixĐịa chỉDùng được (trừ 5)Sử dụng điển hình
/281611Nhỏ/dự phòng
/24256251Subnet chuẩn
/204.0964.091Subnet lớn (EKS, fleet lớn)
/1665.536Cả một VPC

Khái niệm chính

Kết nối các VPC và mạng

Lựa chọnKết nốiTopologyDùng khi
VPC PeeringHai VPC1:1, không bắc cầuMột số ít VPC cần liên kết trực tiếp
Transit Gateway (TGW)Nhiều VPC + on-premHub-and-spoke, bắc cầuHàng chục VPC; bạn cần một network hub
PrivateLink / VPC EndpointsVPC tiêu thụ → một service cụ thểRiêng tư, một chiều tới một serviceTiếp cận các AWS service hoặc một SaaS một cách riêng tư, không qua internet
Site-to-Site VPNVPC ↔ on-prem qua internetĐường hầm mã hóaKết nối hybrid, chi phí thấp
Direct ConnectVPC ↔ on-prem qua đường dây riêngLiên kết vật lý riêng tưĐộ trễ thấp nhất quán, băng thông cao tới on-prem

VPC Peering là một liên kết trực tiếp, riêng tư giữa hai VPC. Hạn chế then chốt của nó là nó không bắc cầu (non-transitive): nếu A peer B và B peer C, A không thể tiếp cận C. Đây là điều khiến peering không thể quản lý nổi khi vượt quá một vài VPC — bạn sẽ cần một full mesh (n(n-1)/2 kết nối).

Transit Gateway giải quyết điều đó: nó là một network hub cấp region mà mọi VPC (và VPN/Direct Connect của bạn) gắn vào một lần, và nó định tuyến giữa chúng một cách bắc cầu. Với bất kỳ hệ thống nhiều VPC không tầm thường nào, TGW là câu trả lời; bạn đánh đổi một chi phí nhỏ theo từng attachment/theo GB lấy một topology đơn giản hơn rất nhiều.

PrivateLink và VPC Endpoints giữ traffic tới các AWS service (hoặc SaaS đối tác) hoàn toàn trên mạng riêng của AWS:

Dùng một gateway endpoint cho S3 là một tối ưu hóa kinh điển: các private subnet chỉ cần S3 khi đó có thể bỏ qua hoàn toàn NAT gateway cho traffic đó.

Elastic Load Balancing (ELB)

ELB phân phối traffic đến vào các target khỏe mạnh ở nhiều AZ. Có ba loại:

LoạiLayerĐịnh tuyến theoDùng cho
ALB (Application)L7 (HTTP/HTTPS)Host, path, header, methodWeb app, microservice, định tuyến container, WebSocket
NLB (Network)L4 (TCP/UDP/TLS)IP + port, độ trễ cực thấpHiệu năng cực đại, static IP, giao thức không phải HTTP
GWLB (Gateway)L3Trong suốt, GENEVEChèn các virtual appliance (firewall, IDS/IPS) inline

Load balancer dùng health check để ngừng gửi traffic tới các target không khỏe mạnh, và target group để định nghĩa nhóm backend (instance, IP, hoặc Lambda). Luôn đặt một internet-facing LB trong các public subnet trải trên ≥2 AZ, với các target thực sự nằm trong các private subnet.

Route 53 — DNS và quản lý traffic

Route 53 là dịch vụ DNS của AWS (cái tên lấy từ port DNS kinh điển, 53). Nó làm ba việc: đăng ký (register) domain, phân giải (resolve) DNS (hosting có thẩm quyền), và định tuyến (route) một cách thông minh với health check.

Routing policy là phần thú vị:

PolicyHành viDùng cho
SimpleMột record, không logicÁnh xạ một endpoint cơ bản
WeightedChia traffic theo phần trămCanary/blue-green, A/B testing
Latency-basedGửi người dùng tới region có độ trễ thấp nhấtApp đa region toàn cầu
GeolocationĐịnh tuyến theo châu lục/quốc gia của người dùngTuân thủ, nội dung bản địa hóa
GeoproximityĐịnh tuyến theo khoảng cách địa lý, có biasKiểm soát địa lý chi tiết
FailoverPrimary → secondary khi health check failDR active-passive
Multivalue answerTrả về nhiều IP khỏe mạnhPhân tán tải phía client đơn giản

Alias record là một tính năng đặc thù của Route 53: một record A/AAAA trỏ tới một tài nguyên AWS (ALB, CloudFront, S3 website, một Route 53 record khác) bằng tên, tự động phân giải tới các IP hiện tại của nó, miễn phí khi query, và — khác với CNAME — có thể nằm ở zone apex (example.com, không chỉ www.example.com). Dùng alias record cho bất cứ thứ gì trỏ tới một AWS endpoint. Health check giám sát các endpoint và điều khiển failover cũng như việc gỡ bỏ target đã chết ở cấp DNS.

CloudFront — CDN

CloudFront là mạng phân phối nội dung toàn cầu của AWS, cache nội dung tại hơn 600 edge location gần người dùng. Nó đứng trước một origin (một S3 bucket, một ALB, hoặc bất kỳ HTTP server nào) và phục vụ các response đã cache từ edge gần nhất, cắt giảm độ trễ và giảm tải cho origin.

Một thiết lập kinh điển: static site hoặc SPA trong một private S3 bucket → CloudFront với OAC đứng phía trước → Route 53 alias record ở apex → chứng chỉ ACM (được cấp ở us-east-1, một yêu cầu bắt buộc đối với CloudFront) cho HTTPS.

VPC Flow Logs — nhìn thấy traffic của bạn

VPC Flow Logs ghi lại metadata về IP traffic (source/dest IP và port, protocol, số byte, ACCEPT/REJECT) ở cấp VPC, subnet, hoặc ENI, được gửi tới CloudWatch Logs hoặc S3. Chúng không ghi lại nội dung packet, nhưng chúng không thể thiếu cho:

Best Practices

  1. Thiết kế kế hoạch CIDR trước khi tạo bất cứ thứ gì, và không bao giờ để chồng lấn. Các VPC có thể sẽ từng peer, tham gia một Transit Gateway, hoặc kết nối với on-prem phải có các dải khác biệt. Chồng lấn là lỗi networking duy nhất bạn không thể sửa mà không xây lại, nên hãy dành riêng các khối không chồng lấn cho mỗi môi trường và region ngay từ đầu.

  2. Dùng bố cục multi-AZ, public/private subnet làm mặc định. Một public và một private subnet cho mỗi AZ trải trên ≥2 AZ là baseline cho bất kỳ VPC production nào. Nó cho bạn cả khả năng tiếp cận internet ở nơi cần và khả năng chống chịu một data-center failure với gần như không tốn thêm chi phí.

  3. Chỉ đặt những gì phải public vào public subnet. Các internet-facing load balancer và NAT gateway thuộc về đó; app server và database thì không. Giữ compute và data trong private subnet, chỉ tiếp cận được qua LB, sẽ thu nhỏ đáng kể bề mặt tấn công của bạn.

  4. Làm firewall bằng security group, không phải NACL. SG là stateful, có thể tham chiếu lẫn nhau, và dễ suy luận hơn nhiều. Tham chiếu SG-tới-SG (ví dụ cho phép app SG tiếp cận DB SG ở port database) thay vì hardcode IP, và dành NACL cho các rule deny thô ở cấp subnet.

  5. Tuân theo least privilege trong security group. Chỉ mở đúng các port và source cụ thể mà mỗi tier cần; tránh 0.0.0.0/0 trên bất cứ thứ gì trừ public HTTPS. Một database SG chỉ nên chấp nhận traffic từ SG của app tier — không bao giờ từ internet, và không bao giờ trên một dải port rộng.

  6. Triển khai NAT gateway theo từng AZ để có HA, và cắt giảm chi phí NAT ở nơi bạn có thể. Một NAT gateway đơn lẻ là một single point of failure ở cấp AZ và một chi phí data-transfer xuyên AZ. Chạy một cái cho mỗi AZ để chống chịu, và dùng S3/DynamoDB gateway endpoint để traffic đó hoàn toàn bỏ qua NAT.

  7. Dùng VPC endpoint để giữ traffic AWS riêng tư và rẻ hơn. Interface (PrivateLink) và gateway endpoint giữ các lời gọi tới S3, ECR, SSM, Secrets Manager, và nhiều nữa trên mạng AWS — cải thiện bảo mật (không có đường qua internet) và thường giảm phí xử lý dữ liệu của NAT.

  8. Chọn Transit Gateway thay vì một mesh các peering một khi bạn có nhiều hơn một vài VPC. Peering không bắc cầu và mở rộng theo kết nối. Một Transit Gateway hub-and-spoke giữ cho một hệ thống nhiều VPC và hybrid đang lớn dần luôn quản lý được và định tuyến bắc cầu được.

  9. Chọn đúng load balancer cho giao thức. ALB cho HTTP/HTTPS với định tuyến dựa trên nội dung; NLB khi bạn cần hiệu năng cực đại, một static IP, giữ nguyên client source-IP, hoặc một giao thức không phải HTTP; GWLB chỉ cho việc chèn appliance inline. Dùng một ALB ở nơi bạn cần một IP cố định (hoặc ngược lại) buộc bạn phải xoay xở vụng về.

  10. Đặt một LB trong public subnet đứng trước các app internet-facing, với target trong private subnet. Terminate TLS ở load balancer, health-check các target, và không bao giờ phơi các backend instance trực tiếp. Đây là baseline về độ tin cậy và bảo mật cho bất kỳ web workload nào.

  11. Ưu tiên Route 53 alias record cho các AWS endpoint. Alias record tự động phân giải tới các IP hiện tại của tài nguyên, miễn phí khi query, và hoạt động ở zone apex nơi CNAME không thể. Dùng các routing policy (weighted, latency, failover) để làm canary, định tuyến đa region, và DR active-passive ở lớp DNS.

  12. Đặt CloudFront đứng trước nội dung tĩnh và cache được. Nó cắt giảm độ trễ trên phạm vi toàn cầu, giảm tải origin của bạn, terminate TLS ở edge, và — với Origin Access Control — cho phép bạn phục vụ một private S3 bucket một cách an toàn. Nhớ rằng chứng chỉ CloudFront phải được cấp ở us-east-1.

  13. Mã hóa traffic khi truyền, đầu-cuối tới đầu-cuối. Dùng HTTPS/TLS ở load balancer và CloudFront, và đừng dừng ở edge — ưu tiên TLS giữa LB và backend cho các workload nhạy cảm. AWS Certificate Manager cấp và tự động gia hạn chứng chỉ miễn phí.

  14. Bật VPC Flow Logs trên mọi VPC production. Chúng là công cụ chính của bạn để chẩn đoán các lỗi kết nối (một SG/NACL REJECT hiện ra ngay lập tức) và cho việc điều tra bảo mật. Chuyển chúng tới một account trung tâm cùng với các audit log khác của bạn.

  15. Bảo vệ các endpoint internet-facing bằng WAF và Shield. Gắn AWS WAF vào ALB và CloudFront để lọc các web exploit và bot phổ biến, và dựa vào Shield Standard (miễn phí) cộng với Shield Advanced ở nơi cần thiết để chống DDoS. Edge là nơi bạn muốn hấp thụ traffic độc hại, trước khi nó chạm tới origin của bạn.

  16. Định nghĩa toàn bộ networking bằng code. VPC, subnet, route table, SG, và endpoint chính là loại tài nguyên liên kết chằng chịt, dễ cấu hình sai, thuộc về Terraform/CloudFormation — có thể review, diff, và tái lập được. Ghép một VPC bằng tay đảm bảo sẽ có drift và một mạng không thể xây lại được.

Worked example — a minimal multi-AZ VPC (Terraform)

Một VPC public/private trải trên hai AZ: các subnet internet-facing cho một load balancer, các private subnet cho tier app/database, và một NAT gateway cho outbound của private.

# 1. The VPC — a /16 gives ~65k addresses and room to grow
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = { Name = "app-vpc" }
}

# 2. Internet Gateway — the door to the public internet
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main.id
  tags   = { Name = "app-igw" }
}

# 3. Public + private subnets across two AZs
resource "aws_subnet" "public" {
  for_each                = { a = "10.0.1.0/24", b = "10.0.2.0/24" }
  vpc_id                  = aws_vpc.main.id
  cidr_block              = each.value
  availability_zone       = "ap-southeast-1${each.key}"
  map_public_ip_on_launch = true            # makes it a "public" subnet
  tags = { Name = "public-${each.key}" }
}

resource "aws_subnet" "private" {
  for_each          = { a = "10.0.11.0/24", b = "10.0.12.0/24" }
  vpc_id            = aws_vpc.main.id
  cidr_block        = each.value
  availability_zone = "ap-southeast-1${each.key}"
  tags = { Name = "private-${each.key}" }
}

# 4. NAT gateway (in a public subnet) so private instances get outbound
resource "aws_eip" "nat" { domain = "vpc" }
resource "aws_nat_gateway" "nat" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public["a"].id
  tags          = { Name = "app-nat" }
}

# 5. Route tables — public routes to IGW, private routes to NAT
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id   # <-- this makes it public
  }
}
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.nat.id     # <-- outbound-only via NAT
  }
}

resource "aws_route_table_association" "public" {
  for_each       = aws_subnet.public
  subnet_id      = each.value.id
  route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "private" {
  for_each       = aws_subnet.private
  subnet_id      = each.value.id
  route_table_id = aws_route_table.private.id
}

Toàn bộ sự phân biệt public/private rút gọn về khối 4–5 của các route table: một subnet là public vì bảng của nó gửi 0.0.0.0/0 tới Internet Gateway, và private vì bảng của nó gửi 0.0.0.0/0 tới NAT gateway (chỉ outbound). Thêm các security group (app SG tham chiếu DB SG), một ALB trong các public subnet, và một S3 gateway endpoint trên private route table, và bạn có một mạng có hình dáng production.

Bản CLI tương đương cho một VPC nhanh đơn lẻ, để so sánh:

VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --query Vpc.VpcId --output text)
aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.1.0/24 --availability-zone ap-southeast-1a
IGW_ID=$(aws ec2 create-internet-gateway --query InternetGateway.InternetGatewayId --output text)
aws ec2 attach-internet-gateway --vpc-id $VPC_ID --internet-gateway-id $IGW_ID

Dùng CLI để kiểm tra và thử nghiệm; dùng Terraform cho bất cứ thứ gì cần tồn tại lâu dài.

Tài liệu tham khảo

Part of the Cloud knowledge base — AWS deep dive. Complements DevOps Roadmap.

Overview

Networking is where AWS feels most like running your own data center, because it is one — virtualized. The Virtual Private Cloud (VPC) is a logically isolated slice of the AWS network that you fully control: you choose the IP address range, carve it into subnets, decide what’s reachable from the internet and what isn’t, and place firewalls at every layer. Almost every workload you run — EC2, RDS, ECS, EKS, Lambda-in-a-VPC — lives inside a VPC, so a shaky mental model of networking undermines everything above it.

This page builds from the inside out: the VPC and its subnets, how traffic gets in and out (gateways and route tables), the two firewall layers (security groups and NACLs), how VPCs connect to each other and to on-prem (peering, Transit Gateway, PrivateLink), how you distribute traffic (Elastic Load Balancing), how users find you (Route 53 DNS), how you cache globally (CloudFront), and how you see what’s happening (Flow Logs). It closes with CIDR planning and a minimal, real VPC layout in Terraform.

The core mental model: a VPC is a private network you own; a subnet is a slice of it pinned to one AZ; a route table decides where a subnet’s traffic goes; and gateways are the doors to the outside world. “Public” and “private” subnets aren’t a setting — they’re a consequence of what their route table points at.

Fundamentals

VPC and subnets

Public vs private subnet — the defining difference:

Public subnetPrivate subnet
Route table has a route toInternet Gateway (0.0.0.0/0 → IGW)NAT Gateway or nothing
Inbound from internetPossible (with a public/Elastic IP)Never directly
Outbound to internetDirect via IGWVia NAT (in a public subnet) or none
Typical residentsLoad balancers, bastion hosts, NAT gatewaysApp servers, databases, internal services

The rule of thumb: put as little as possible in public subnets. Only internet-facing load balancers and NAT gateways truly need to be there. App servers and databases belong in private subnets, reachable only through the load balancer.

Gateways, route tables, and IPs

Route tables are the routing brain. Each subnet is associated with exactly one route table; the table is a list of destination CIDR → target. The local route (the VPC’s own CIDR → local) is always present and can’t be removed — that’s what lets subnets talk to each other. Everything else you add: 0.0.0.0/0 → igw-... makes a subnet public; 0.0.0.0/0 → nat-... gives a private subnet outbound.

The two firewall layers: Security Groups vs NACLs

AWS gives you two independent packet filters. Understanding the difference is essential.

Security Group (SG)Network ACL (NACL)
Operates atThe instance/ENI levelThe subnet level
Stateful?Stateful — return traffic auto-allowedStateless — must allow return traffic explicitly
RulesAllow only (implicit deny)Allow and Deny, evaluated by rule number
DefaultDeny all inbound, allow all outboundDefault NACL allows all; custom denies all
Can referenceOther security groups (and CIDRs)CIDRs only
EvaluationAll rules considered togetherFirst matching rule wins (numeric order)

Stateful vs stateless is the trap. A security group only needs an inbound rule for port 443; the response is automatically allowed because SGs remember the connection. A NACL, being stateless, needs both an inbound rule for 443 and an outbound rule for the ephemeral return ports (1024–65535) — forget the second and connections mysteriously hang.

Practical guidance: do almost all your work with security groups — they’re stateful, can reference each other (e.g., “allow the web SG to reach the DB SG on 5432” with no IP addresses at all), and are far easier to reason about. Use NACLs sparingly as a coarse subnet-level backstop, mainly for explicit deny rules (blocking a bad IP range) that SGs can’t express.

CIDR planning

Getting your address plan right up front avoids painful re-architecture later.

PrefixAddressesUsable (minus 5)Typical use
/281611Tiny/reserved
/24256251Standard subnet
/204,0964,091Large subnet (EKS, big fleets)
/1665,536A whole VPC

Key Concepts

Connecting VPCs and networks

OptionConnectsTopologyUse when
VPC PeeringTwo VPCs1:1, non-transitiveA handful of VPCs need direct links
Transit Gateway (TGW)Many VPCs + on-premHub-and-spoke, transitiveDozens of VPCs; you need a network hub
PrivateLink / VPC EndpointsConsumer VPC → a specific servicePrivate, one-way to a serviceReach AWS services or a SaaS privately, no internet
Site-to-Site VPNVPC ↔ on-prem over internetEncrypted tunnelHybrid connectivity, cheap
Direct ConnectVPC ↔ on-prem over dedicated linePrivate physical linkConsistent low latency, high bandwidth to on-prem

VPC Peering is a direct, private link between two VPCs. Its critical limitation is that it’s non-transitive: if A peers B and B peers C, A cannot reach C. This is what makes peering unmanageable past a few VPCs — you’d need a full mesh (n(n-1)/2 connections).

Transit Gateway solves that: it’s a regional network hub that every VPC (and your VPN/Direct Connect) attaches to once, and it routes between them transitively. For any non-trivial multi-VPC estate, TGW is the answer; you trade a small per-attachment/per-GB cost for a vastly simpler topology.

PrivateLink and VPC Endpoints keep traffic to AWS services (or partner SaaS) entirely on the AWS private network:

Using a gateway endpoint for S3 is a classic optimization: private subnets that only need S3 can then skip the NAT gateway entirely for that traffic.

Elastic Load Balancing (ELB)

ELB distributes incoming traffic across healthy targets in multiple AZs. Three types:

TypeLayerRoutes onUse for
ALB (Application)L7 (HTTP/HTTPS)Host, path, headers, methodsWeb apps, microservices, container routing, WebSockets
NLB (Network)L4 (TCP/UDP/TLS)IP + port, ultra-low latencyExtreme performance, static IPs, non-HTTP protocols
GWLB (Gateway)L3Transparent, GENEVEInserting virtual appliances (firewalls, IDS/IPS) inline

Load balancers use health checks to stop sending traffic to unhealthy targets, and target groups to define the backend pool (instances, IPs, or Lambda). Always place an internet-facing LB in public subnets across ≥2 AZs, with the actual targets in private subnets.

Route 53 — DNS and traffic management

Route 53 is AWS’s DNS service (the name is the classic DNS port, 53). It does three things: register domains, resolve DNS (authoritative hosting), and route intelligently with health checks.

Routing policies are the interesting part:

PolicyBehaviorUse for
SimpleOne record, no logicBasic single-endpoint mapping
WeightedSplit traffic by percentageCanary/blue-green, A/B testing
Latency-basedSend users to the lowest-latency regionGlobal multi-region apps
GeolocationRoute by user’s continent/countryCompliance, localized content
GeoproximityRoute by geographic distance, with biasFine-grained geographic control
FailoverPrimary → secondary on health-check failureActive-passive DR
Multivalue answerReturn several healthy IPsSimple client-side load spreading

Alias records are a Route 53-specific feature: an A/AAAA record that points at an AWS resource (ALB, CloudFront, S3 website, another Route 53 record) by name, resolves to its current IPs automatically, is free to query, and — unlike a CNAME — can sit at the zone apex (example.com, not just www.example.com). Use alias records for anything pointing at an AWS endpoint. Health checks monitor endpoints and drive failover and DNS-level removal of dead targets.

CloudFront — the CDN

CloudFront is AWS’s global content delivery network, caching content at 600+ edge locations close to users. It fronts an origin (an S3 bucket, an ALB, or any HTTP server) and serves cached responses from the nearest edge, cutting latency and offloading the origin.

A canonical setup: static site or SPA in a private S3 bucket → CloudFront with OAC in front → Route 53 alias record at the apex → ACM certificate (issued in us-east-1, a hard requirement for CloudFront) for HTTPS.

VPC Flow Logs — seeing your traffic

VPC Flow Logs capture metadata about IP traffic (source/dest IP and port, protocol, bytes, ACCEPT/REJECT) at the VPC, subnet, or ENI level, delivered to CloudWatch Logs or S3. They don’t capture packet contents, but they’re indispensable for:

Best Practices

  1. Design the CIDR plan before creating anything, and never overlap. VPCs that might ever peer, join a Transit Gateway, or connect to on-prem must have distinct ranges. Overlap is the one networking mistake you cannot fix without rebuilding, so reserve non-overlapping blocks per environment and region up front.

  2. Use a multi-AZ, public/private subnet layout by default. One public and one private subnet per AZ across ≥2 AZs is the baseline for any production VPC. It gives you both internet reachability where needed and resilience to a data-center failure for almost no extra cost.

  3. Put only what must be public in public subnets. Internet-facing load balancers and NAT gateways belong there; app servers and databases do not. Keeping compute and data in private subnets, reachable only through the LB, dramatically shrinks your attack surface.

  4. Do your firewalling with security groups, not NACLs. SGs are stateful, can reference each other, and are far easier to reason about. Reference SG-to-SG (e.g., allow the app SG to reach the DB SG on the database port) instead of hardcoding IPs, and reserve NACLs for coarse subnet-level deny rules.

  5. Follow least privilege in security groups. Open only the specific ports and sources each tier needs; avoid 0.0.0.0/0 on anything but public HTTPS. A database SG should accept traffic only from the app tier’s SG — never from the internet, and never on a wide port range.

  6. Deploy NAT gateways per-AZ for HA, and cut NAT cost where you can. A single NAT gateway is an AZ-level single point of failure and a cross-AZ data-transfer cost. Run one per AZ for resilience, and use S3/DynamoDB gateway endpoints so that traffic bypasses NAT entirely.

  7. Use VPC endpoints to keep AWS traffic private and cheaper. Interface (PrivateLink) and gateway endpoints keep calls to S3, ECR, SSM, Secrets Manager, and more on the AWS network — improving security (no internet path) and often reducing NAT data-processing charges.

  8. Choose Transit Gateway over a mesh of peerings once you have more than a few VPCs. Peering is non-transitive and scales as connections. A hub-and-spoke Transit Gateway keeps a growing multi-VPC and hybrid estate manageable and transitively routable.

  9. Pick the right load balancer for the protocol. ALB for HTTP/HTTPS with content-based routing; NLB when you need extreme performance, a static IP, client source-IP preservation, or a non-HTTP protocol; GWLB only for inline appliance insertion. Using an ALB where you need a fixed IP (or vice versa) forces awkward workarounds.

  10. Front internet-facing apps with an LB in public subnets and targets in private subnets. Terminate TLS at the load balancer, health-check the targets, and never expose backend instances directly. This is the reliability and security baseline for any web workload.

  11. Prefer Route 53 alias records for AWS endpoints. Alias records resolve to the resource’s current IPs automatically, cost nothing to query, and work at the zone apex where CNAMEs can’t. Use routing policies (weighted, latency, failover) to do canaries, multi-region routing, and active-passive DR at the DNS layer.

  12. Put CloudFront in front of static and cacheable content. It cuts latency globally, offloads your origin, terminates TLS at the edge, and — with Origin Access Control — lets you serve a private S3 bucket safely. Remember CloudFront certificates must be issued in us-east-1.

  13. Encrypt traffic in transit end to end. Use HTTPS/TLS at load balancers and CloudFront, and don’t stop at the edge — prefer TLS between the LB and backends for sensitive workloads. AWS Certificate Manager issues and auto-renews certificates for free.

  14. Enable VPC Flow Logs on every production VPC. They’re your primary tool for diagnosing connectivity failures (an SG/NACL REJECT jumps out immediately) and for security investigation. Ship them to a central account alongside your other audit logs.

  15. Protect internet-facing endpoints with WAF and Shield. Attach AWS WAF to ALBs and CloudFront to filter common web exploits and bots, and rely on Shield Standard (free) plus Shield Advanced where warranted for DDoS. The edge is where you want to absorb malicious traffic, before it reaches your origin.

  16. Define all networking as code. VPCs, subnets, route tables, SGs, and endpoints are exactly the kind of interconnected, easy-to-misconfigure resources that belong in Terraform/CloudFormation — reviewable, diffable, and reproducible. Clicking a VPC together by hand guarantees drift and an un-rebuildable network.

Worked example — a minimal multi-AZ VPC (Terraform)

A public/private VPC across two AZs: internet-facing subnets for a load balancer, private subnets for app/database tiers, and a NAT gateway for private outbound.

# 1. The VPC — a /16 gives ~65k addresses and room to grow
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags = { Name = "app-vpc" }
}

# 2. Internet Gateway — the door to the public internet
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.main.id
  tags   = { Name = "app-igw" }
}

# 3. Public + private subnets across two AZs
resource "aws_subnet" "public" {
  for_each                = { a = "10.0.1.0/24", b = "10.0.2.0/24" }
  vpc_id                  = aws_vpc.main.id
  cidr_block              = each.value
  availability_zone       = "ap-southeast-1${each.key}"
  map_public_ip_on_launch = true            # makes it a "public" subnet
  tags = { Name = "public-${each.key}" }
}

resource "aws_subnet" "private" {
  for_each          = { a = "10.0.11.0/24", b = "10.0.12.0/24" }
  vpc_id            = aws_vpc.main.id
  cidr_block        = each.value
  availability_zone = "ap-southeast-1${each.key}"
  tags = { Name = "private-${each.key}" }
}

# 4. NAT gateway (in a public subnet) so private instances get outbound
resource "aws_eip" "nat" { domain = "vpc" }
resource "aws_nat_gateway" "nat" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public["a"].id
  tags          = { Name = "app-nat" }
}

# 5. Route tables — public routes to IGW, private routes to NAT
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id   # <-- this makes it public
  }
}
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.nat.id     # <-- outbound-only via NAT
  }
}

resource "aws_route_table_association" "public" {
  for_each       = aws_subnet.public
  subnet_id      = each.value.id
  route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "private" {
  for_each       = aws_subnet.private
  subnet_id      = each.value.id
  route_table_id = aws_route_table.private.id
}

The whole public/private distinction reduces to lines 4–5 of the route tables: a subnet is public because its table sends 0.0.0.0/0 to the Internet Gateway, and private because its table sends 0.0.0.0/0 to the NAT gateway (outbound-only). Add security groups (app SG referencing DB SG), an ALB in the public subnets, and an S3 gateway endpoint on the private route table, and you have a production-shaped network.

The CLI equivalent for a single quick VPC, for comparison:

VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 --query Vpc.VpcId --output text)
aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.1.0/24 --availability-zone ap-southeast-1a
IGW_ID=$(aws ec2 create-internet-gateway --query InternetGateway.InternetGatewayId --output text)
aws ec2 attach-internet-gateway --vpc-id $VPC_ID --internet-gateway-id $IGW_ID

Use the CLI for inspection and experiments; use Terraform for anything that must survive.

References