NLB And ALB
The components:
Cả ALB và NLB đều có các thành phần giống nhau:
- Load Balancer: Entry point vào hệ thống
- Listener: Lắng nghe incoming connections
- Target Group: Nhóm các targets (EC2, containers, services)
- Health Check: Giám sát tình trạng targets
→ Dễ dàng chuyển đổi giữa ALB và NLB nếu không dùng tính năng đặc biệt
Mặc định:
"Khi bạn nghi ngờ, chọn ALB" vì:
- ALB có nhiều tính năng built-in
- NLB phức tạp hơn, cần kinh nghiệm và cẩn thận hơn
Ngoại trừ:
Chọn NLB khi câu trả lời cho một trong các câu hỏi sau là "Yes":
Clients có kết nối qua UDP hoặc giao thức không phải HTTP không?
- ALB: Chỉ hỗ trợ HTTP/1.1, HTTP/2, gRPC
- NLB: Hỗ trợ UDP, TCP, HTTP/3
- Use case: Gaming (UDP), IoT protocols, HTTP/3
Bạn có cần tối ưu hóa hiệu suất không?
- ALB: Layer 7 - inspect HTTP request details → latency cao hơn
- NLB: Layer 4 - forward TCP/UDP connection → latency thấp hơn
- Use case: High-performance applications cần độ trễ thấp
Bạn có dự kiến lưu lượng truy cập tăng đột biến khổng lồ và không thể dự đoán không?
- ALB: Scale tự động nhưng mất vài phút → có thể không kịp xử lý
- NLB: Xử lý traffic spikes ngay lập tức mà không cần scale
- Use case: Super Bowl ads, flash sales (PlayStation launch), viral content
Bạn có yêu cầu địa chỉ IP tĩnh cho lưu lượng truy cập đến không?
- ALB: DNS name với IP động (có thể thay đổi khi scale)
- NLB: Static IP addresses out-of-the-box
- Use case: Third-party firewall rules, legacy systems không resolve hostname
The comparison
| ALB | NLB |
---|
Protocols | HTTP/1, HTTP/2, gRPC | TCP, UDP |
Performance | Low Latency | Very Low Latency |
Traffic Spikes | ⚠️ Inform AWS Support about huge traffic spikes | ✅ Deals with huge and unexpected traffic spikes |
Static IP Addresses | ❌ No. However, you could place an NLB in front of an ALB. | ✅ Yes |
TLS Termination | ✅ Yes | ✅ Yes |
Targets | EC2 Instance, IP Address, Lambda | EC2 Instance, IP Address, ALB |
Client IP preservation | Use HTTP header X-Forwarded-For | Optional, but comes with limitations |
Routing Algorithm | Round Robin or Least Outstanding Requests | Random |
Deregistering targets | ALB stops sending requests and waits for open requests | NLB stops opening new connections, but the application needs to terminate connections properly |
Multiplexing | ✅ Yes, reuses connections to targets | ❌ No, does not reuse connections to targets |
Maximum number of targets | 1000-5000 | 500-1000 |
Security Group | Security group of ALB controls inbound traffic, targets reachable from ALB only | Security group of targets control inbound traffic, targets reachable from clients |
Request based routing | ✅ Yes, based on hostname, path, header, … | ❌ No |
WAF | ✅ Yes | ❌ No |
Authentication | ✅ Yes (OpenID Connect, SAML, …) | ❌ No |
Slow Start Mode | ✅ Yes | ❌ No |
Sticky Session | ✅ Yes | ❌ No |
IPv6 | ✅ Yes | ✅ Yes |
Costs | 💰💰💰 | 💰💰 (But causes more connections and therefore higher load on targets.) |
NLB Use Case
- API Gateway + VPC Link + NLB (Bài thực hành trong blog này)
- Gaming/Real-time Applications
Game Clients → NLB (UDP) → Game Servers (EC2/ECS)
- High-Performance Trading/Financial Systems
Trading Apps → NLB → Trading Engines (ultra-low latency)
- Legacy Applications với Static IP
Legacy Systems → Firewall (whitelist static IPs) → NLB → Modern Services
- Multi-Protocol Load Balancing
HTTP/TCP/UDP Clients → NLB → Mixed Protocol Services
- Global Load Balancing với Route 53
Global Users → Route 53 → NLB (multiple regions) → Services
- Container/Kubernetes Ingress
External Traffic → NLB → AWS Load Balancer Controller → EKS Pods
- Database Load Balancing
Applications → NLB → Database Cluster (MySQL/PostgreSQL)
- Hybrid Cloud Architectures
On-premises → VPN/Direct Connect → NLB → AWS Services
- Event-Driven/Streaming Architectures
Event Producers → NLB → Kafka/Kinesis → Event Consumers
- Use Cases – PrivateLink

Lab Introduction
- AWS experience: Intermediate
- Time to complete: 40 minutes
- AWS Region: US East (N. Virginia) us-east-1
- Services used: VPC resource, EC2, IAM, NLB, API Gateway
Prerequisites
- AWS Account với quyền Admin
- Account của bạn đã có sẵn key pair
- Kiến thức cơ bản về Cloudformation
- Kiến thức về API gateway, Load Balancer, Asuto Scaling group
- SSH để connect vào EC2
Architecture Diagram

Task Details
- Tạo VPC resource, NLB, ASG, Web-server vv sử dụng Cloudformation
- Test kết nối đến NLB
- Tạo VPC Link
- Tạo và config API Gateway
- Turn off security group evaluation for PrivateLink
- Test kết nối đến API Gateway
Chúng ta sẽ tạo các resource theo hình sau:

Tải file Cloudformation template tại đây
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Private NLB with Auto Scaling Group for Web API'
Parameters:
KeyPairName:
Type: AWS::EC2::KeyPair::KeyName
Description: Name of an existing EC2 KeyPair to enable SSH access to the instances
ConstraintDescription: Must be the name of an existing EC2 KeyPair
Resources:
# 1. VPC
SoaVpcMain:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.7.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: soa-vpc-main
# 2. Public Subnets
SoaSubnetPublic01:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SoaVpcMain
CidrBlock: 10.7.1.0/24
AvailabilityZone: !Sub ${AWS::Region}a
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: soa-subnet-public-01
SoaSubnetPublic02:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SoaVpcMain
CidrBlock: 10.7.2.0/24
AvailabilityZone: !Sub ${AWS::Region}b
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: soa-subnet-public-02
# 3. Private Subnets
SoaSubnetPrivate01:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SoaVpcMain
CidrBlock: 10.7.3.0/24
AvailabilityZone: !Sub ${AWS::Region}a
Tags:
- Key: Name
Value: soa-subnet-private-01
SoaSubnetPrivate02:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SoaVpcMain
CidrBlock: 10.7.4.0/24
AvailabilityZone: !Sub ${AWS::Region}b
Tags:
- Key: Name
Value: soa-subnet-private-02
# 4. Internet Gateway
SoaIgwMain:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: soa-igw-main
SoaIgwMainAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref SoaVpcMain
InternetGatewayId: !Ref SoaIgwMain
# 5. NAT Gateway
SoaEipNatGateway:
Type: AWS::EC2::EIP
DependsOn: SoaIgwMainAttachment
Properties:
Domain: vpc
Tags:
- Key: Name
Value: soa-eip-nat-gateway
SoaNatGatewayPublic01:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt SoaEipNatGateway.AllocationId
SubnetId: !Ref SoaSubnetPublic01
Tags:
- Key: Name
Value: soa-nat-gateway-public-01
# 6. Public Route Table
SoaRtPublic:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref SoaVpcMain
Tags:
- Key: Name
Value: soa-rt-public
SoaRoutePublicInternet:
Type: AWS::EC2::Route
DependsOn: SoaIgwMainAttachment
Properties:
RouteTableId: !Ref SoaRtPublic
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref SoaIgwMain
SoaRtPublicAssociation01:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SoaSubnetPublic01
RouteTableId: !Ref SoaRtPublic
SoaRtPublicAssociation02:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SoaSubnetPublic02
RouteTableId: !Ref SoaRtPublic
# 7. Private Route Table
SoaRtPrivate:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref SoaVpcMain
Tags:
- Key: Name
Value: soa-rt-private
SoaRoutePrivateInternet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref SoaRtPrivate
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref SoaNatGatewayPublic01
SoaRtPrivateAssociation01:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SoaSubnetPrivate01
RouteTableId: !Ref SoaRtPrivate
SoaRtPrivateAssociation02:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref SoaSubnetPrivate02
RouteTableId: !Ref SoaRtPrivate
# 8. IAM Role cho SSM Session Manager
SoaRoleEc2SsmAccess:
Type: AWS::IAM::Role
Properties:
RoleName: soa-role-ec2-ssm-access
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Tags:
- Key: Name
Value: soa-role-ec2-ssm-access
SoaInstanceProfileEc2SsmAccess:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: soa-instance-profile-ec2-ssm-access
Roles:
- !Ref SoaRoleEc2SsmAccess
# 9. Security Group cho NLB
SoaSgNlbPrivate:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: soa-sg-nlb-private
GroupDescription: Security group for private NLB
VpcId: !Ref SoaVpcMain
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 10.7.0.0/16
Description: HTTP access from VPC
Tags:
- Key: Name
Value: soa-sg-nlb-private
# 10. Security Group cho Web API
SoaSgWebApi:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: soa-sg-web-api
GroupDescription: Security group for web API instances
VpcId: !Ref SoaVpcMain
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref SoaSgNlbPrivate
Description: HTTP access from NLB
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
Description: All outbound traffic
Tags:
- Key: Name
Value: soa-sg-web-api
# 11. Target Group
SoaTgWebApi:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: soa-tg-web-api
Port: 80
Protocol: TCP
VpcId: !Ref SoaVpcMain
TargetType: instance
HealthCheckEnabled: true
HealthCheckPath: /
HealthCheckProtocol: HTTP
HealthCheckIntervalSeconds: 30
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
Tags:
- Key: Name
Value: soa-tg-web-api
# 12. Private Network Load Balancer
SoaNlbPrivateWebApi:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: soa-nlb-private-web-api
Type: network
Scheme: internal
SecurityGroups:
- !Ref SoaSgNlbPrivate
Subnets:
- !Ref SoaSubnetPrivate01
- !Ref SoaSubnetPrivate02
Tags:
- Key: Name
Value: soa-nlb-private-web-api
SoaNlbListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref SoaTgWebApi
LoadBalancerArn: !Ref SoaNlbPrivateWebApi
Port: 80
Protocol: TCP
# 13. Launch Template
SoaLtWebApiTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: soa-lt-web-api-template
VersionDescription: web api
LaunchTemplateData:
ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}'
InstanceType: t2.micro
KeyName: !Ref KeyPairName
IamInstanceProfile:
Arn: !GetAtt SoaInstanceProfileEc2SsmAccess.Arn
SecurityGroupIds:
- !Ref SoaSgWebApi
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum update -y
yum install -y httpd.x86_64
systemctl start httpd.service
systemctl enable httpd.service
echo "Hello World from $(hostname -f)" > /var/www/html/index.html
# Signal CloudFormation that instance is ready
/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource SoaAsgWebApi --region ${AWS::Region}
TagSpecifications:
- ResourceType: instance
Tags:
- Key: Name
Value: soa-ec2-web-api
# 14. Auto Scaling Group
SoaAsgWebApi:
Type: AWS::AutoScaling::AutoScalingGroup
DependsOn:
- SoaRoutePrivateInternet
- SoaNatGatewayPublic01
Properties:
AutoScalingGroupName: soa-asg-web-api
LaunchTemplate:
LaunchTemplateId: !Ref SoaLtWebApiTemplate
Version: !GetAtt SoaLtWebApiTemplate.LatestVersionNumber
VPCZoneIdentifier:
- !Ref SoaSubnetPrivate01
- !Ref SoaSubnetPrivate02
TargetGroupARNs:
- !Ref SoaTgWebApi
DesiredCapacity: 1
MinSize: 1
MaxSize: 2
HealthCheckType: ELB
HealthCheckGracePeriod: 300
Tags:
- Key: Name
Value: soa-asg-web-api
PropagateAtLaunch: false
CreationPolicy:
ResourceSignal:
Count: 1
Timeout: PT10M
UpdatePolicy:
AutoScalingRollingUpdate:
MinInstancesInService: 0
MaxBatchSize: 1
PauseTime: PT10M
WaitOnResourceSignals: true
# 15. Auto Scaling Policy
SoaAsgPolicyTargetTracking:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AutoScalingGroupName: !Ref SoaAsgWebApi
PolicyType: TargetTrackingScaling
TargetTrackingConfiguration:
PredefinedMetricSpecification:
PredefinedMetricType: ASGAverageCPUUtilization
TargetValue: 50.0
# 16. Bastion Host để test
SoaSgBastion:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: soa-sg-bastion
GroupDescription: Security group for bastion host
VpcId: !Ref SoaVpcMain
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
Description: All outbound traffic
Tags:
- Key: Name
Value: soa-sg-bastion
SoaEc2Bastion:
Type: AWS::EC2::Instance
DependsOn:
- SoaRoutePublicInternet
- SoaIgwMainAttachment
Properties:
ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}'
InstanceType: t2.micro
KeyName: !Ref KeyPairName
SubnetId: !Ref SoaSubnetPublic01
IamInstanceProfile: !Ref SoaInstanceProfileEc2SsmAccess
SecurityGroupIds:
- !Ref SoaSgBastion
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum update -y
yum install -y curl
# Install SSM agent (should be pre-installed on AL2023)
yum install -y amazon-ssm-agent
systemctl enable amazon-ssm-agent
systemctl start amazon-ssm-agent
Tags:
- Key: Name
Value: soa-ec2-bastion
Outputs:
VpcId:
Description: VPC ID
Value: !Ref SoaVpcMain
Export:
Name: !Sub ${AWS::StackName}-VpcId
NlbDnsName:
Description: Private NLB DNS Name
Value: !GetAtt SoaNlbPrivateWebApi.DNSName
Export:
Name: !Sub ${AWS::StackName}-NlbDnsName
BastionPublicIp:
Description: Bastion Host Public IP
Value: !GetAtt SoaEc2Bastion.PublicIp
Export:
Name: !Sub ${AWS::StackName}-BastionPublicIp
TestCommand:
Description: Command to test the NLB using SSM Session Manager
Value: !Sub 'aws ssm start-session --target <INSTANCE_ID> --region ${AWS::Region}'
SsmConnectInstructions:
Description: Instructions to connect and test
Value: |
1. Connect to bastion: aws ssm start-session --target <BASTION_INSTANCE_ID>
2. Test NLB: curl http://<NLB_DNS_NAME>
3. Connect to web instance: aws ssm start-session --target <WEB_INSTANCE_ID>
1.1 Tóm tắt các resource được tạo:
🌐 NETWORK INFRASTRUCTURE (11 resources):
- 1 VPC:
soa-vpc-main
(10.7.0.0/16) - 4 Subnets:
- 2 Public: 10.7.1.0/24, 10.7.2.0/24 (AZ a,b)
- 2 Private: 10.7.3.0/24, 10.7.4.0/24 (AZ a,b)
- 1 Internet Gateway:
soa-igw-main
- 1 NAT Gateway:
soa-nat-gateway-public-01
(trong public subnet 01) - 1 Elastic IP: Cho NAT Gateway
- 2 Route Tables: Public + Private với routes tương ứng
- 4 Route Table Associations: Gắn subnets vào route tables
🔐 SECURITY & IAM (4 resources):
- 1 IAM Role:
soa-role-ec2-ssm-access
(với AmazonSSMManagedInstanceCore) - 1 Instance Profile:
soa-instance-profile-ec2-ssm-access
- 3 Security Groups:
soa-sg-nlb-private
: Cho NLB (allow port 80 từ VPC)soa-sg-web-api
: Cho Web API (allow port 80 từ NLB SG)soa-sg-bastion
: Cho Bastion (chỉ outbound traffic)
⚖️ LOAD BALANCING (3 resources):
- 1 Target Group:
soa-tg-web-api
(TCP port 80, HTTP health check) - 1 Network Load Balancer:
soa-nlb-private-web-api
(internal, private subnets) - 1 Listener: Port 80 TCP → Target Group
🚀 AUTO SCALING (3 resources):
- 1 Launch Template:
soa-lt-web-api-template
(AL2023, t2.micro, Apache) - 1 Auto Scaling Group:
soa-asg-web-api
(Min:1, Des:1, Max:2) - 1 Scaling Policy: Target tracking 50% CPU
🖥️ COMPUTE (1 resource):
- 1 Bastion Host:
soa-ec2-bastion
(public subnet, SSM access)

Stack name: soa-cfn-nlb-asg-stack
KeyPairName: Chọn Key pair đã có sẵn trong Account


Review lại và Submit
Đợi cho đến khi Stack được tạo thành công

2. Test kết nối đến NLB
3. Tạo VPC Link
Tại Console API Gateway -> VPC Link -> Create

Có thể mất 7-10 phút để VPC Link status chuyển trạng thái sang Available (chỉ có thể đợi)

4. Tạo và config API Gateway
Tại Console API Gateway -> API -> Create API
Chọn Build REST API

API name: soa-apigw-web-api
API endpoint type: Regional

Chọn API của bạn
Chọn Create Method

For Method type, select GET
.
For Integration type, select VPC link.
Turn on VPC proxy integration.
For HTTP method, select GET
.
For VPC link, select [Use stage variable] and enter ${stageVariables.vpcLinkId}
in the text box below.
For Endpoint URL: http://<NLB_DNS_NAME>

Choose Create method.

Deploy API
Stage name: develop

Update stage variable:

Stage variables
- Name:
vpcLinkId
- Value:
giá trị VPC link ID


Save và hoàn tất
Tại đây cho dù chúng ta có access đến URL của API Gateway thì kết quả sẽ là Server error


5. Turn off security group evaluation for PrivateLink
Để...
Mở Cloudshell và run lệnh sau:
aws elbv2 set-security-groups --load-balancer-arn <NLB-ARN-URL> \
--security-groups <NLB-SG-ID> --enforce-security-group-inbound-rules-on-private-link-traffic off
- Thay
<NLB-ARN-URL>
bằng ARN của NLB - Thay
<NLB-SG-ID>
bằng Security group ID của NLB
Bên dưới là command của mình
aws elbv2 set-security-groups \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:067057696393:loadbalancer/net/soa-nlb-private-web-api/11171a3019aa5282 \
--security-groups sg-0b9495c41a2b09471 \
--enforce-security-group-inbound-rules-on-private-link-traffic off
Mở Cloudshell và run

6. Test kết nối đến API Gateway
Challenge (Optional)
- Có thể custom domain cho api gateway
- Demo phía trên mình dùng web apache để thể hiện server web api, bạn có thể connect đến web api để cài đặt api khác theo mục đích. Thực hiện tets nhiều phương thức post, get, put vv
- Có thể liên kết với Cognito để thực hiện authen cho api gateway
Troubleshooting
- Sau khi run command để Turn off security group evaluation for PrivateLink, nếu access url của API gateway mà kết quả vẫn ko hiển thị nội dung web: Bạn nên clear cache, hoặc tets với private browser
Clean up resources
- Delete API Gateway:
soa-apigw-web-api
- delete VPC Link:
soa-vpc-link
- Delete Cloudformation stack:
soa-cfn-nlb-asg-stack
Tài liệu tham khảo: