Deploy Nuxt.js + FastAPI lên AWS ECS (Phần 2) — Route 53, CloudFront, SSL và WAF — hoatq.dev

cat blog/.md

Deploy Nuxt.js + FastAPI lên AWS ECS (Phần 2) — Route 53, CloudFront, SSL và WAF

date: tags: aws, route53, cloudfront, waf, ssl, devops, ecs

Ở Phần 1, chúng ta đã có containers chạy trên ECS Fargate, CI/CD tự động qua GitHub Actions, ALB phân phối traffic. Nhưng users vẫn đang truy cập qua URL kiểu myapp-alb-123456.ap-southeast-1.elb.amazonaws.com — không HTTPS, không CDN, không firewall.

Phần 2 này sẽ biến hệ thống thành production-ready thực sự: domain riêng, HTTPS miễn phí, CDN toàn cầu, tường lửa chống tấn công, auto-scaling, và monitoring.

Kiến trúc hoàn chỉnh

Sau khi hoàn thành Phần 2, hệ thống sẽ trông như thế này:

User → yourdomain.com

    Route 53 (DNS)

    CloudFront (CDN + HTTPS)

    WAF (Web Application Firewall)

    ALB (Application Load Balancer)
       ↙          ↘
  Nuxt.js        FastAPI
  (ECS)          (ECS)

              RDS / Secrets Manager

Mỗi layer thêm một lớp giá trị: Route 53 quản lý DNS, CloudFront cache static assets và terminate SSL, WAF chặn traffic xấu trước khi tới app, ALB route request đến đúng container.

Bước 1: ACM — SSL Certificate miễn phí

AWS Certificate Manager cung cấp SSL certificate miễn phí, tự động renew. Nhưng có một điểm quan trọng: nếu dùng với CloudFront, certificate phải tạo ở region us-east-1 (N. Virginia), bất kể ECS chạy ở region nào.

# QUAN TRỌNG: Phải dùng region us-east-1 cho CloudFront
aws acm request-certificate \
  --domain-name yourdomain.com \
  --subject-alternative-names "*.yourdomain.com" \
  --validation-method DNS \
  --region us-east-1

Wildcard *.yourdomain.com cho phép dùng chung certificate cho www.yourdomain.com, api.yourdomain.com, staging.yourdomain.com… — tiện hơn nhiều so với tạo certificate riêng cho mỗi subdomain.

Sau khi request, AWS yêu cầu validate quyền sở hữu domain bằng DNS record:

# Lấy CNAME record cần thêm vào DNS
aws acm describe-certificate \
  --certificate-arn arn:aws:acm:us-east-1:ACCOUNT_ID:certificate/xxx \
  --region us-east-1 \
  --query 'Certificate.DomainValidationOptions[0].ResourceRecord'

# Kết quả:
# {
#   "Name": "_abc123.yourdomain.com",
#   "Type": "CNAME",
#   "Value": "_def456.acm-validations.aws"
# }

Thêm CNAME record này vào DNS provider (hoặc Route 53 nếu đã chuyển). Sau 5-10 phút, certificate sẽ chuyển sang trạng thái ISSUED.

Tạo luôn một certificate ở region của ALB (VD: ap-southeast-1) cho ALB HTTPS listener:

aws acm request-certificate \
  --domain-name yourdomain.com \
  --subject-alternative-names "*.yourdomain.com" \
  --validation-method DNS \
  --region ap-southeast-1

Bước 2: Route 53 — DNS Management

Tạo Hosted Zone

aws route53 create-hosted-zone \
  --name yourdomain.com \
  --caller-reference "$(date +%s)"

Sau khi tạo, Route 53 trả về 4 name servers. Bạn cần cập nhật name servers ở nơi mua domain (Namecheap, GoDaddy, Google Domains…) để trỏ về Route 53:

# Lấy name servers của hosted zone
aws route53 get-hosted-zone \
  --id /hostedzone/ZONE_ID \
  --query 'DelegationSet.NameServers'

# Kết quả VD:
# [
#   "ns-123.awsdns-45.com",
#   "ns-678.awsdns-90.net",
#   "ns-111.awsdns-22.org",
#   "ns-333.awsdns-44.co.uk"
# ]

Copy 4 name servers này vào domain registrar. DNS propagation mất 24-48 giờ, nhưng thực tế thường xong trong 1-2 giờ.

Tại sao dùng Route 53 thay vì DNS ở registrar?

  • Alias records: Route 53 hỗ trợ alias record trỏ thẳng tới ALB, CloudFront — không cần CNAME (nhanh hơn, hoạt động với root domain)
  • Health checks: Route 53 tự kiểm tra endpoint và failover khi cần
  • Latency-based routing: Route users tới region gần nhất
  • Tích hợp native: Validate ACM certificate chỉ cần 1 click trong console

Bước 3: ALB HTTPS Listener

Trước khi thêm CloudFront, hãy bật HTTPS trên ALB trước. Tạo HTTPS listener (port 443) và redirect HTTP sang HTTPS:

# Tạo HTTPS listener trên ALB
aws elbv2 create-listener \
  --load-balancer-arn arn:aws:elasticloadbalancing:ap-southeast-1:ACCOUNT_ID:loadbalancer/app/myapp-alb/xxx \
  --protocol HTTPS \
  --port 443 \
  --ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06 \
  --certificates CertificateArn=arn:aws:acm:ap-southeast-1:ACCOUNT_ID:certificate/yyy \
  --default-actions '[{
    "Type": "forward",
    "TargetGroupArn": "arn:aws:elasticloadbalancing:...:targetgroup/frontend-tg/xxx"
  }]'

# Redirect HTTP → HTTPS
aws elbv2 create-listener \
  --load-balancer-arn arn:aws:elasticloadbalancing:ap-southeast-1:ACCOUNT_ID:loadbalancer/app/myapp-alb/xxx \
  --protocol HTTP \
  --port 80 \
  --default-actions '[{
    "Type": "redirect",
    "RedirectConfig": {
      "Protocol": "HTTPS",
      "Port": "443",
      "StatusCode": "HTTP_301"
    }
  }]'

SSL policy ELBSecurityPolicy-TLS13-1-2-2021-06 chỉ cho phép TLS 1.2 và 1.3 — disable các protocol cũ (TLS 1.0, 1.1) để đảm bảo bảo mật.

Thêm routing rule cho /api/* trên HTTPS listener:

aws elbv2 create-rule \
  --listener-arn arn:aws:elasticloadbalancing:...:listener/xxx \
  --priority 10 \
  --conditions '[{"Field":"path-pattern","Values":["/api/*"]}]' \
  --actions '[{"Type":"forward","TargetGroupArn":"arn:...backend-tg..."}]'

Bước 4: CloudFront — CDN toàn cầu

CloudFront đặt content gần users hơn thông qua edge locations trên toàn thế giới. Với Nuxt.js SSR, CloudFront cache static assets (JS, CSS, images) ở edge, giảm load cho ECS containers.

Tạo CloudFront Distribution

aws cloudfront create-distribution \
  --distribution-config '{
    "CallerReference": "myapp-2026",
    "Comment": "MyApp Production",
    "Enabled": true,
    "Origins": {
      "Quantity": 1,
      "Items": [
        {
          "Id": "alb-origin",
          "DomainName": "myapp-alb-xxx.ap-southeast-1.elb.amazonaws.com",
          "CustomOriginConfig": {
            "HTTPPort": 80,
            "HTTPSPort": 443,
            "OriginProtocolPolicy": "https-only",
            "OriginSslProtocols": {
              "Quantity": 1,
              "Items": ["TLSv1.2"]
            }
          }
        }
      ]
    },
    "DefaultCacheBehavior": {
      "TargetOriginId": "alb-origin",
      "ViewerProtocolPolicy": "redirect-to-https",
      "AllowedMethods": {
        "Quantity": 7,
        "Items": ["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"]
      },
      "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6",
      "OriginRequestPolicyId": "216adef6-5c7f-47e4-b989-5492eafa07d3",
      "Compress": true
    },
    "Aliases": {
      "Quantity": 1,
      "Items": ["yourdomain.com"]
    },
    "ViewerCertificate": {
      "ACMCertificateArn": "arn:aws:acm:us-east-1:ACCOUNT_ID:certificate/xxx",
      "SSLSupportMethod": "sni-only",
      "MinimumProtocolVersion": "TLSv1.2_2021"
    },
    "HttpVersion": "http2and3",
    "PriceClass": "PriceClass_200"
  }'

Giải thích các config quan trọng:

  • OriginProtocolPolicy: https-only: CloudFront giao tiếp với ALB qua HTTPS — encrypted end-to-end
  • ViewerProtocolPolicy: redirect-to-https: Tự redirect HTTP → HTTPS cho users
  • CachePolicyId: 658327ea...Managed-CachingOptimized — cache policy mặc định tốt cho hầu hết trường hợp
  • OriginRequestPolicyId: 216adef6...Managed-AllViewer — forward tất cả headers, query strings, cookies tới origin
  • HttpVersion: http2and3: Bật HTTP/3 (QUIC) — nhanh hơn cho mobile users
  • PriceClass_200: Dùng edge locations ở tất cả regions trừ South America — balance giữa giá và performance

Cache behaviors cho API và static assets

API requests (/api/*) không nên cache — mỗi request phải tới backend. Static assets thì cache aggressively:

# Behavior cho /api/* — KHÔNG cache, forward tất cả
aws cloudfront create-distribution \
  # ... thêm CacheBehaviors:
  "CacheBehaviors": {
    "Quantity": 2,
    "Items": [
      {
        "PathPattern": "/api/*",
        "TargetOriginId": "alb-origin",
        "ViewerProtocolPolicy": "https-only",
        "AllowedMethods": {
          "Quantity": 7,
          "Items": ["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"]
        },
        "CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
        "OriginRequestPolicyId": "216adef6-5c7f-47e4-b989-5492eafa07d3"
      },
      {
        "PathPattern": "/_nuxt/*",
        "TargetOriginId": "alb-origin",
        "ViewerProtocolPolicy": "redirect-to-https",
        "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6",
        "Compress": true
      }
    ]
  }
  • /api/*: CachePolicyId = 4135ea2d...Managed-CachingDisabled — pass qua CloudFront thẳng tới ALB
  • /_nuxt/*: Nuxt 3 build static assets vào /_nuxt/ với hashed filenames — cache vĩnh viễn cũng không sao vì mỗi build tạo filename mới

Bước 5: Route 53 — Trỏ domain về CloudFront

Giờ trỏ domain về CloudFront distribution:

aws route53 change-resource-record-sets \
  --hosted-zone-id ZONE_ID \
  --change-batch '{
    "Changes": [
      {
        "Action": "CREATE",
        "ResourceRecordSet": {
          "Name": "yourdomain.com",
          "Type": "A",
          "AliasTarget": {
            "HostedZoneId": "Z2FDTNDATAQYW2",
            "DNSName": "d1234abcdef.cloudfront.net",
            "EvaluateTargetHealth": false
          }
        }
      },
      {
        "Action": "CREATE",
        "ResourceRecordSet": {
          "Name": "yourdomain.com",
          "Type": "AAAA",
          "AliasTarget": {
            "HostedZoneId": "Z2FDTNDATAQYW2",
            "DNSName": "d1234abcdef.cloudfront.net",
            "EvaluateTargetHealth": false
          }
        }
      }
    ]
  }'

Một vài điểm quan trọng:

  • Z2FDTNDATAQYW2: Đây là Hosted Zone ID cố định của CloudFront — không phải zone ID của bạn, mà là constant dùng chung cho tất cả CloudFront distributions
  • Record A + AAAA: A cho IPv4, AAAA cho IPv6 — CloudFront hỗ trợ cả hai
  • Alias record: Không phải CNAME — alias hoạt động ở root domain (yourdomain.com), CNAME thì không

Nếu muốn www.yourdomain.com cũng hoạt động:

# www → redirect về root domain
aws route53 change-resource-record-sets \
  --hosted-zone-id ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "www.yourdomain.com",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "DNSName": "d1234abcdef.cloudfront.net",
          "EvaluateTargetHealth": false
        }
      }
    }]
  }'

Nhớ thêm www.yourdomain.com vào Aliases của CloudFront distribution.

Bước 6: WAF — Bảo vệ khỏi tấn công

AWS WAF đặt trước CloudFront, filter traffic trước khi tới ứng dụng. Setup cơ bản nhưng hiệu quả:

# Tạo Web ACL cho CloudFront (phải ở us-east-1)
aws wafv2 create-web-acl \
  --name myapp-waf \
  --scope CLOUDFRONT \
  --region us-east-1 \
  --default-action '{"Allow": {}}' \
  --rules '[
    {
      "Name": "AWS-AWSManagedRulesCommonRuleSet",
      "Priority": 1,
      "Statement": {
        "ManagedRuleGroupStatement": {
          "VendorName": "AWS",
          "Name": "AWSManagedRulesCommonRuleSet"
        }
      },
      "OverrideAction": {"None": {}},
      "VisibilityConfig": {
        "SampledRequestsEnabled": true,
        "CloudWatchMetricsEnabled": true,
        "MetricName": "CommonRuleSet"
      }
    },
    {
      "Name": "AWS-AWSManagedRulesKnownBadInputsRuleSet",
      "Priority": 2,
      "Statement": {
        "ManagedRuleGroupStatement": {
          "VendorName": "AWS",
          "Name": "AWSManagedRulesKnownBadInputsRuleSet"
        }
      },
      "OverrideAction": {"None": {}},
      "VisibilityConfig": {
        "SampledRequestsEnabled": true,
        "CloudWatchMetricsEnabled": true,
        "MetricName": "KnownBadInputs"
      }
    },
    {
      "Name": "AWS-AWSManagedRulesSQLiRuleSet",
      "Priority": 3,
      "Statement": {
        "ManagedRuleGroupStatement": {
          "VendorName": "AWS",
          "Name": "AWSManagedRulesSQLiRuleSet"
        }
      },
      "OverrideAction": {"None": {}},
      "VisibilityConfig": {
        "SampledRequestsEnabled": true,
        "CloudWatchMetricsEnabled": true,
        "MetricName": "SQLiRuleSet"
      }
    },
    {
      "Name": "RateLimit",
      "Priority": 4,
      "Statement": {
        "RateBasedStatement": {
          "Limit": 2000,
          "AggregateKeyType": "IP"
        }
      },
      "Action": {"Block": {}},
      "VisibilityConfig": {
        "SampledRequestsEnabled": true,
        "CloudWatchMetricsEnabled": true,
        "MetricName": "RateLimit"
      }
    }
  ]' \
  --visibility-config '{
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "myapp-waf"
  }'

4 rules này cover phần lớn threats:

  • AWSManagedRulesCommonRuleSet: Chặn các attack pattern phổ biến (XSS, path traversal, bad bots…)
  • AWSManagedRulesKnownBadInputsRuleSet: Chặn request patterns đã biết là malicious (Log4j, Java deserialization…)
  • AWSManagedRulesSQLiRuleSet: Chặn SQL injection
  • RateLimit 2000/5min per IP: Chặn brute force và DDoS cơ bản — 1 IP gửi quá 2000 requests trong 5 phút sẽ bị block

Attach WAF vào CloudFront:

aws wafv2 associate-web-acl \
  --web-acl-arn arn:aws:wafv2:us-east-1:ACCOUNT_ID:global/webacl/myapp-waf/xxx \
  --resource-arn arn:aws:cloudfront::ACCOUNT_ID:distribution/DIST_ID

Thêm rule cho API rate limiting chặt hơn

API endpoints thường cần rate limit thấp hơn trang chủ:

# Rate limit riêng cho /api/* — 500 requests/5 phút per IP
{
  "Name": "APIRateLimit",
  "Priority": 0,
  "Statement": {
    "RateBasedStatement": {
      "Limit": 500,
      "AggregateKeyType": "IP",
      "ScopeDownStatement": {
        "ByteMatchStatement": {
          "SearchString": "/api/",
          "FieldToMatch": {"UriPath": {}},
          "PositionalConstraint": "STARTS_WITH",
          "TextTransformations": [{"Priority": 0, "Type": "NONE"}]
        }
      }
    }
  },
  "Action": {"Block": {}},
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "APIRateLimit"
  }
}

Bước 7: Auto Scaling

Hệ thống cần tự scale khi traffic tăng:

# Đăng ký service với Application Auto Scaling
aws application-autoscaling register-scalable-target \
  --service-namespace ecs \
  --scalable-dimension ecs:service:DesiredCount \
  --resource-id service/myapp-cluster/myapp-service \
  --min-capacity 2 \
  --max-capacity 10

# Scale dựa trên CPU utilization
aws application-autoscaling put-scaling-policy \
  --service-namespace ecs \
  --scalable-dimension ecs:service:DesiredCount \
  --resource-id service/myapp-cluster/myapp-service \
  --policy-name cpu-scaling \
  --policy-type TargetTrackingScaling \
  --target-tracking-scaling-policy-configuration '{
    "TargetValue": 70.0,
    "PredefinedMetricSpecification": {
      "PredefinedMetricType": "ECSServiceAverageCPUUtilization"
    },
    "ScaleInCooldown": 300,
    "ScaleOutCooldown": 60
  }'

# Scale dựa trên request count (qua ALB)
aws application-autoscaling put-scaling-policy \
  --service-namespace ecs \
  --scalable-dimension ecs:service:DesiredCount \
  --resource-id service/myapp-cluster/myapp-service \
  --policy-name request-scaling \
  --policy-type TargetTrackingScaling \
  --target-tracking-scaling-policy-configuration '{
    "TargetValue": 1000.0,
    "PredefinedMetricSpecification": {
      "PredefinedMetricType": "ALBRequestCountPerTarget",
      "ResourceLabel": "app/myapp-alb/xxx/targetgroup/frontend-tg/yyy"
    },
    "ScaleInCooldown": 300,
    "ScaleOutCooldown": 60
  }'

Hai policies hoạt động song song:

  • CPU trên 70%? Scale out
  • Mỗi target nhận quá 1000 requests/phút? Scale out
  • Traffic giảm? Scale in sau 5 phút cooldown

ScaleOutCooldown: 60 nghĩa là scale out nhanh (1 phút), nhưng ScaleInCooldown: 300 scale in chậm (5 phút) — tránh hiện tượng “flapping” khi traffic dao động.

Bước 8: Security Groups — Khóa chặt traffic

Một sai lầm phổ biến: để ALB nhận traffic từ mọi nơi. Khi đã có CloudFront, ALB chỉ nên nhận traffic từ CloudFront:

# Security Group cho ALB — chỉ cho phép CloudFront
aws ec2 create-security-group \
  --group-name myapp-alb-sg \
  --description "ALB - CloudFront only"

# AWS publish danh sách IP ranges của CloudFront
# Dùng AWS-managed prefix list thay vì hardcode IPs
aws ec2 authorize-security-group-ingress \
  --group-id sg-alb-xxx \
  --ip-permissions '[
    {
      "IpProtocol": "tcp",
      "FromPort": 443,
      "ToPort": 443,
      "PrefixListIds": [{"PrefixListId": "pl-3b927c52"}]
    }
  ]'

pl-3b927c52 là AWS-managed prefix list cho CloudFront IPs (ở ap-southeast-1). AWS tự cập nhật list này khi CloudFront thêm IP mới — bạn không cần maintain.

# Security Group cho ECS tasks — chỉ nhận từ ALB
aws ec2 authorize-security-group-ingress \
  --group-id sg-ecs-xxx \
  --ip-permissions '[
    {
      "IpProtocol": "tcp",
      "FromPort": 3000,
      "ToPort": 3000,
      "UserIdGroupPairs": [{"GroupId": "sg-alb-xxx"}]
    },
    {
      "IpProtocol": "tcp",
      "FromPort": 8000,
      "ToPort": 8000,
      "UserIdGroupPairs": [{"GroupId": "sg-alb-xxx"}]
    }
  ]'

Traffic flow bây giờ: Internet → CloudFront → WAF → ALB (chỉ từ CloudFront) → ECS (chỉ từ ALB). Không ai bypass được CloudFront/WAF để tấn công trực tiếp vào ALB hay containers.

Bước 9: Monitoring và Alerting

Hệ thống chạy rồi, nhưng bạn cần biết khi nào nó có vấn đề — trước khi users báo lỗi.

CloudWatch Alarms

# Alarm khi ECS service unhealthy
aws cloudwatch put-metric-alarm \
  --alarm-name myapp-unhealthy-tasks \
  --namespace AWS/ECS \
  --metric-name CPUUtilization \
  --dimensions Name=ClusterName,Value=myapp-cluster Name=ServiceName,Value=myapp-service \
  --statistic Average \
  --period 60 \
  --threshold 90 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 3 \
  --alarm-actions arn:aws:sns:ap-southeast-1:ACCOUNT_ID:myapp-alerts

# Alarm khi ALB 5xx errors tăng
aws cloudwatch put-metric-alarm \
  --alarm-name myapp-5xx-errors \
  --namespace AWS/ApplicationELB \
  --metric-name HTTPCode_Target_5XX_Count \
  --dimensions Name=LoadBalancer,Value=app/myapp-alb/xxx \
  --statistic Sum \
  --period 300 \
  --threshold 50 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 1 \
  --alarm-actions arn:aws:sns:ap-southeast-1:ACCOUNT_ID:myapp-alerts

# Alarm khi WAF block rate cao bất thường
aws cloudwatch put-metric-alarm \
  --alarm-name myapp-waf-blocks \
  --namespace AWS/WAFV2 \
  --metric-name BlockedRequests \
  --dimensions Name=WebACL,Value=myapp-waf Name=Rule,Value=ALL \
  --statistic Sum \
  --period 300 \
  --threshold 1000 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 1 \
  --alarm-actions arn:aws:sns:ap-southeast-1:ACCOUNT_ID:myapp-alerts \
  --region us-east-1

Setup SNS topic để nhận alert qua email hoặc Slack:

aws sns create-topic --name myapp-alerts
aws sns subscribe \
  --topic-arn arn:aws:sns:ap-southeast-1:ACCOUNT_ID:myapp-alerts \
  --protocol email \
  --notification-endpoint your-email@example.com

Chi phí tổng thể

Với setup production-ready hoàn chỉnh (2 ECS tasks, CloudFront, WAF, Route 53):

ServiceChi phí/tháng
ECS Fargate (0.5 vCPU, 1GB, 2 tasks)~$30
ALB~$20
CloudFront (100GB transfer)~$10
Route 53 (1 hosted zone + queries)~$1
ACM (SSL certificates)$0
WAF (3 managed rules + rate limit)~$12
CloudWatch (logs + alarms)~$5
ECR (10 images)~$1
Tổng~$79/tháng

So với tự setup Nginx + Let’s Encrypt + fail2ban trên VPS ($15/tháng), giá cao hơn nhưng bạn được:

  • Auto-scaling khi traffic tăng đột biến
  • CDN toàn cầu — users ở US, EU truy cập nhanh như local
  • WAF managed rules — AWS update rules khi có threat mới
  • Zero-downtime deployment mỗi lần push code
  • Không cần thức đêm vì server chết

Checklist hoàn chỉnh

Tổng hợp toàn bộ 2 phần, đây là checklist để đưa một hệ thống Nuxt.js + FastAPI lên production trên AWS:

Phần 1 — Core Infrastructure:

  1. Dockerize frontend (Nuxt.js) và backend (FastAPI) với multi-stage builds
  2. Tạo ECR repositories, push images
  3. Setup ECS Cluster + Task Definition + Service trên Fargate
  4. Cấu hình ALB với target groups và routing rules
  5. Viết GitHub Actions CI/CD workflow

Phần 2 — Production-Ready: 6. Request SSL certificates qua ACM (us-east-1 cho CloudFront + region local cho ALB) 7. Tạo Route 53 hosted zone, cập nhật name servers ở registrar 8. Bật HTTPS trên ALB (listener 443 + redirect 80→443) 9. Setup CloudFront distribution với cache behaviors riêng cho API và static assets 10. Trỏ domain về CloudFront qua Route 53 alias records 11. Tạo WAF Web ACL với managed rules + rate limiting 12. Lock security groups: ALB chỉ nhận từ CloudFront, ECS chỉ nhận từ ALB 13. Setup auto-scaling policies (CPU + request count) 14. Cấu hình CloudWatch alarms + SNS notifications

14 bước nghe nhiều, nhưng phần lớn chỉ cần setup một lần. Sau đó, workflow hàng ngày chỉ là push code — mọi thứ tự động.


Bạn đã từng setup hệ thống trên AWS chưa? Có phần nào thấy khó hiểu hoặc muốn mình đi sâu hơn? Chia sẻ qua email nhé!

// reactions



hoatq@dev : ~/blog $