Happy Dussehra! May good always win. Happy Diwali! Wishing you a bright year ahead. Merry Christmas! Warm wishes from Vizag. Happy New Year! Here’s to a great year ahead.

Archive · AWS

Serving Traffic: ALB and Route 53

Put an Application Load Balancer with HTTPS in front of EC2 or containers, issue a free ACM certificate, point Route 53 at it, and set health checks and redirects.

3 min read

  • Application Load Balancer
  • Amazon Route 53
  • AWS Certificate Manager
  • Target groups

A single EC2 instance with a public IP is fragile: it has one address, one failure domain and no managed TLS. The standard fix is an Application Load Balancer (ALB) that terminates HTTPS, spreads requests across targets in several Availability Zones and removes unhealthy ones, with Route 53 supplying the DNS name and ACM the certificate.

State of AWS on this date. ACM public certificates are free and renew automatically when used with ALB, CloudFront or API Gateway. ALBs bill per hour plus load-balancer capacity units. Target groups can contain EC2 instances, IP addresses, Lambda functions and ECS tasks.

Request path

flowchart TB
  U[User browser] -->|DNS lookup app.example.com| R53[Route 53 alias record]
  R53 -->|ALB DNS name| ALB
  subgraph VPC[VPC]
    ALB[ALB in public subnets<br/>listeners 80 and 443] -->|HTTP 301 to HTTPS| ALB
    ALB -->|forward rule| TG[Target group web-tg<br/>health check /healthz]
    TG --> A[Instance in AZ a<br/>private subnet]
    TG --> B[Instance in AZ b<br/>private subnet]
  end
  ACM[ACM certificate] -.-> ALB
  SG1[Security group alb-sg<br/>80 and 443 from anywhere] -.-> ALB
  SG2[Security group app-sg<br/>8080 from alb-sg only] -.-> A

1. Certificate

Request it in the region where the ALB lives (for CloudFront it must be us-east-1) and validate by DNS, which is easy when the zone is in Route 53:

aws acm request-certificate --domain-name app.example.com --validation-method DNS --region ap-south-1
aws acm describe-certificate --certificate-arn <arn> --query 'Certificate.DomainValidationOptions[0].ResourceRecord'
# create that CNAME in Route 53 (the console has a one-click button), then:
aws acm wait certificate-validated --certificate-arn <arn>

Keep the validation CNAME in place; ACM uses it for automatic renewals.

2. Security groups

alb-sg allows 80 and 443 from 0.0.0.0/0. app-sg allows the application port only from alb-sg, so nobody can reach the instances directly.

3. Load balancer, target group and listeners

TG=$(aws elbv2 create-target-group --name web-tg --protocol HTTP --port 8080 --vpc-id $VPC \
  --health-check-path /healthz --health-check-interval-seconds 15 --healthy-threshold-count 2 --unhealthy-threshold-count 3 \
  --query 'TargetGroups[0].TargetGroupArn' --output text)
aws elbv2 register-targets --target-group-arn $TG --targets Id=i-0abc123 Id=i-0def456

ALB=$(aws elbv2 create-load-balancer --name web-alb --subnets $PUB1 $PUB2 --security-groups $ALB_SG \
  --scheme internet-facing --type application --query 'LoadBalancers[0].LoadBalancerArn' --output text)

aws elbv2 create-listener --load-balancer-arn $ALB --protocol HTTPS --port 443 \
  --certificates CertificateArn=<arn> --ssl-policy ELBSecurityPolicy-TLS-1-2-2017-01 \
  --default-actions Type=forward,TargetGroupArn=$TG

aws elbv2 create-listener --load-balancer-arn $ALB --protocol HTTP --port 80 \
  --default-actions 'Type=redirect,RedirectConfig={Protocol=HTTPS,Port=443,StatusCode=HTTP_301}'

The ALB needs subnets in at least two AZs. The /healthz endpoint should check that the app can do useful work (and optionally its database) but return quickly. Check status:

aws elbv2 describe-target-health --target-group-arn $TG

4. DNS in Route 53

For the apex or any name pointing to an ALB, use an alias record (free, follows the ALB’s changing IPs, works at the zone apex where CNAME cannot):

aws route53 change-resource-record-sets --hosted-zone-id Z123EXAMPLE --change-batch '{
 "Changes":[{"Action":"UPSERT","ResourceRecordSet":{
   "Name":"app.example.com","Type":"A",
   "AliasTarget":{"HostedZoneId":"ZP97RAFLXTNZK","DNSName":"web-alb-123456.ap-south-1.elb.amazonaws.com","EvaluateTargetHealth":true}}}]}'
dig +short app.example.com
curl -I https://app.example.com

The HostedZoneId inside AliasTarget is the ALB’s own zone ID for the region (listed in the AWS docs), not your hosted zone. Use a low TTL (60 seconds) before migrations.

Routing and features

Feature Use
Path rules /api/* to one target group, / to another
Host rules admin.example.com to a different service
Weighted target groups Blue/green or canary releases
Fixed responses and redirects Maintenance page, HTTP to HTTPS
Sticky sessions Only if the app needs them; prefer stateless apps
Slow-start and deregistration delay Graceful deploys (set the delay to match request length)
Access logs to S3 Request-level audit and debugging

Operate and troubleshoot

  • 502 Bad Gateway: targets close connections or send invalid responses; check app logs and keep-alive timeouts (set the app’s idle timeout higher than the ALB’s 60 seconds).
  • 503: no healthy targets. describe-target-health shows why (health check failing, wrong port, security group blocking alb-sg).
  • 504: target too slow; compare with TargetResponseTime.
  • Watch CloudWatch metrics: HTTPCode_Target_5XX_Count, HTTPCode_ELB_5XX_Count, TargetResponseTime, UnHealthyHostCount; alarm on the last two.
  • Enable deletion protection on production ALBs, and manage everything in IaC so listeners and rules are reviewed.