jvinhit//lab

Search posts

Type to search across journal entries.

↑ ↓ navigate ↵ open esc close

AWS cho Frontend Developer · Phần 1 — Tư duy nền tảng, vòng đời một request và lộ trình 16 phần

Mở đầu series: điều gì xảy ra với file và request sau khi rời localhost, sơ đồ vòng đời một request qua Route 53, CloudFront, S3 và ALB, Region và Edge Location, IAM tối thiểu, lab thiết lập tài khoản và lộ trình 16 phần.

Bạn viết React, Vue hoặc Next.js. Code chạy ngon ở localhost:5173, nhưng khi lên AWS thì 403 khi F5, CORS đỏ cả console, deploy xong user vẫn thấy bản cũ, API thì timeout sau đúng 60 giây. Bạn hỏi DevOps, họ trả lời bằng một chuỗi từ lạ: behavior, OAC, target group, invalidation. Series này giải thích chính xác điều gì xảy ra với file và request của bạn sau khi rời máy local, để bạn tự chỉ ra được lỗi đang nằm ở chặng nào và mở đúng chỗ để sửa.

Phần 1 lo phần tư duy: vì sao một dòng npm run dev bị tách thành tám dịch vụ rời, sơ đồ vòng đời một request mà mọi bài sau đều là phóng to một hộp trong đó, ba khái niệm địa lý ảnh hưởng trực tiếp tới tốc độ trang, IAM ở mức đủ để đọc hiểu lỗi AccessDenied, và một lab 30 phút để bạn có tài khoản AWS an toàn với phanh chi phí.

Thuật ngữ kỹ thuật giữ nguyên tiếng Anh (origin, behavior, cache key, target group, invalidation, edge location) vì đó là chữ bạn sẽ thấy trong AWS Console, trong CLI và trong câu hỏi của DevOps. Phần dịch là phần giải thích.

Lộ trình 16 phần

PhầnChủ đềNguồn gốc
1Tư duy nền tảng và vòng đời một requestChương 0, 1
2Route 53, ACM và HTTP headerChương 2 (2.1–2.3)
3CORS, VPC và Security GroupChương 2 (2.4–2.5, lab)
4S3: nơi file build nằm và cách upload đúngChương 3 (3.1–3.4)
5Presigned URL và VersioningChương 3 (3.5–3.6, lab)
6CloudFront: CDN, behavior và cache keyChương 4 (4.1–4.3)
7CloudFront: chiến lược cache, invalidation, SPA routingChương 4 (4.4–4.6)
8CloudFront Functions, Lambda@Edge, nén, signed URL, sổ tay lỗiChương 4 (4.7–4.10, lab)
9ALB: cửa ngõ vào backendChương 5
10Nơi code chạy: EC2, ECS, Lambda, Amplify, Next.jsChương 6
11API Gateway và CognitoChương 7
12Biến môi trường: build-time, runtime, secretChương 8
13CI/CD: GitHub Actions, OIDC, preview environmentChương 9
14Giám sát và sổ tay debug 6 bướcChương 10
15Bảo mật, hiệu năng và chi phíChương 11, 12
16Lộ trình 8 tuần, dự án, từ điển, checklist, phỏng vấnChương 13–17

Ba phần đầu là nền móng, đọc tuần tự. Phần 4 đến 8 (S3 và CloudFront) là trục chính của series và cũng nên đọc theo thứ tự, vì mỗi lab dựng tiếp trên lab trước. Từ phần 9 trở đi bạn nhảy cóc được theo nhu cầu: đang phải nối API thì đọc phần 9, bị hỏi “deploy Next.js kiểu gì” thì đọc phần 10, đang viết pipeline thì đọc phần 13. Phần 14 là sổ tay debug, mở ra bất cứ lúc nào production báo lỗi.


Series này không nhằm biến bạn thành DevOps

Có một ranh giới rất rõ giữa “frontend biết AWS” và “DevOps”. Bạn không cần biết thiết kế VPC nhiều tầng, tối ưu chi phí RDS hay viết Terraform module cho cả công ty. Nhưng bạn rất cần biết những thứ ở cột trái:

Thứ frontend bắt buộc hiểuThứ có thể để DevOps lo
Build của mình được lưu ở đâu, ai phục vụ nó cho trình duyệtCách tạo VPC, subnet, NAT Gateway
Vì sao deploy xong mà user vẫn thấy bản cũ (cache)Cấu hình auto-scaling policy cho EC2
Vì sao F5 vào /products/123 bị 403/404 còn click từ trang chủ thì đượcBackup, snapshot, disaster recovery
CORS bị chặn thì phải sửa ở S3, CloudFront, ALB hay backendTối ưu chi phí hạ tầng cả tổ chức
Biến VITE_API_URL thực chất nằm ở đâu sau khi buildThiết kế IAM permission boundary
Lỗi 502 / 503 / 504 khác nhau ra sao và là lỗi của aiQuản lý AWS Organizations, SCP
Upload ảnh trực tiếp từ browser lên S3 sao cho an toànVận hành Kubernetes cluster

Series tập trung 100% vào cột trái, và chỉ chạm vào cột phải ở mức “đủ để nói chuyện với DevOps mà không bị lạc”.

Cách học đúng

Đọc lý thuyết 30%, thực hành 70%. Từ phần 3 đến phần 13, hầu như bài nào cũng có mục Lab. Đừng đọc hết rồi mới làm: đọc xong bài nào, mở AWS Console làm luôn bài đó. Kiến thức hạ tầng chỉ dính lại khi bạn tự tay gây ra lỗi và tự sửa, giống như cách bạn thật sự hiểu useEffect chỉ sau lần đầu tự tạo ra vòng lặp vô hạn.

Trước khi bắt đầu

Bạn cần một tài khoản AWS cá nhân. Đăng ký cần thẻ Visa/Mastercard; AWS giữ tạm 1 USD để xác minh rồi hoàn lại.

Nguy hiểm: Việc đầu tiên sau khi tạo tài khoản là vào Billing → Budgets, tạo budget 5 USD kèm cảnh báo email. Đây là cái phanh an toàn. Rất nhiều người học AWS nhận hoá đơn bất ngờ chỉ vì quên tắt một tài nguyên (ALB, NAT Gateway, RDS là ba thứ hay bị quên nhất). Lab cuối bài hướng dẫn từng bước.


Đổi góc nhìn: từ npm run dev sang hạ tầng

Ở local, mọi thứ gói trong một dòng lệnh. Vite dựng một web server, nó vừa phục vụ file tĩnh, vừa proxy /api sang backend, vừa tự sinh HTTPS giả nếu cần. Tất cả trên localhost, cùng một tiến trình, không có mạng thật, không có cache, không có firewall. Đoạn cấu hình quen thuộc này chính là “hạ tầng” của bạn ở local:

// vite.config.ts — toàn bộ "hạ tầng" ở local nằm trong vài dòng này
export default defineConfig({
  server: {
    port: 5173,
    proxy: {
      '/api': { target: 'http://localhost:3000', changeOrigin: true },
    },
  },
});

Lên AWS, một dòng lệnh đó bị tách thành nhiều dịch vụ riêng biệt, mỗi dịch vụ do một nhóm cấu hình khác nhau quản lý, và chúng chỉ nói chuyện với nhau qua mạng:

LOCAL (1 tiến trình)              AWS (nhiều dịch vụ rời)
─────────────────────             ────────────────────────────────
                                  Route 53        ← tên miền
┌──────────────────┐              CloudFront      ← CDN + cache + HTTPS
│ vite dev server  │   ═══►       S3              ← file build tĩnh
│ - serve tĩnh     │              ALB             ← chia request tới backend
│ - proxy /api     │              ECS/Lambda      ← code backend chạy
│ - HMR            │              Security Group  ← firewall
│ - không cache    │              ACM             ← chứng chỉ HTTPS
└──────────────────┘              CloudWatch      ← log & số liệu

Đối chiếu từng việc Vite đang làm với thứ thay thế nó trên AWS:

Việc Vite làm ở localThứ làm việc đó trên AWSBài nói kỹ
Phục vụ file tĩnh trong dist/S3 chứa file, CloudFront phục vụPhần 4, 6
server.proxy cho /apiBehavior /api/* trong CloudFront trỏ tới ALBPhần 6, 9
HTTPS tự ký ở devACM cấp chứng chỉ, CloudFront và ALB kết thúc TLSPhần 2
HMR, reload khi sửa codeKhông có. Mỗi thay đổi là một lần build + deploy + invalidatePhần 7, 13
Không cache gì cảCache ở edge CloudFront và cache trong trình duyệtPhần 7
Không có firewallSecurity Group, bucket policy, IAMPhần 3, 4

Hệ quả trực tiếp cho công việc hằng ngày của bạn:

  • Mỗi chặng đều có thể làm hỏng request. Lỗi “API không gọi được” giờ có ít nhất sáu nguyên nhân khả dĩ ở sáu nơi khác nhau.
  • Có cache ở giữa. Ở local không có. Trên AWS, file của bạn được sao chép ra hàng trăm máy chủ khắp thế giới và chúng không tự biết bạn vừa deploy.
  • Không còn proxy tự động. server.proxy trong vite.config.ts chỉ tồn tại ở dev. Production phải tự dựng lại cơ chế tương đương, và đó chính là việc của CloudFront hoặc ALB.
  • Mọi thứ đều phải khai báo tường minh. Kể cả việc “cho phép cổng 443 đi vào”.

Câu thần chú: Mỗi khi gặp lỗi trên AWS, hãy tự hỏi: “Request này đang đứng ở chặng nào, và chặng đó có biết nó cần làm gì với request không?” Gần như mọi lỗi hạ tầng của frontend đều trả lời được bằng câu hỏi này.


Vòng đời một request — sơ đồ quan trọng nhất series

Đây là sơ đồ bạn nên vẽ lại bằng tay cho đến khi thuộc. Mọi bài sau đều là phóng to một hộp trong sơ đồ này. Ví dụ: người dùng gõ https://shop.example.com/products/123, trang là một SPA React đặt trên S3, API chạy trong ECS sau ALB, tất cả đứng sau một CloudFront distribution.

① NGƯỜI DÙNG gõ https://shop.example.com/products/123
        │
        ▼
② DNS — Route 53
   "shop.example.com là IP nào?" → trả về IP của CloudFront (bản ghi ALIAS/A)
        │
        ▼
③ BẮT TAY TLS (HTTPS)
   CloudFront xuất chứng chỉ từ ACM → trình duyệt kiểm tra → kênh mã hoá
        │
        ▼
④ CLOUDFRONT (edge location gần user nhất, ví dụ Singapore)
   Xét path "/products/123" khớp BEHAVIOR nào?
   ├── Behavior "/api/*"      → origin = ALB   (đi tiếp ⑤)
   ├── Behavior "/static/*"   → origin = S3    (đi tiếp ⑥)
   └── Behavior mặc định "*"  → origin = S3    (đi tiếp ⑥)
   Có trong CACHE ở edge không?
   ├── CÓ (HIT)     → trả ngay, KHÔNG đi tiếp. ~10–40ms.
   └── KHÔNG (MISS) → đi tiếp xuống origin
        │
   ┌────┴────────────────────────────────┐
   ▼                                     ▼
⑤ ALB (trong VPC)                     ⑥ S3 BUCKET
   - Listener 443                        - Tìm object theo key
   - Rule: path /api/* →                 - "products/123" không tồn tại
     Target Group "api-tg"                 → trả 403/404
   - Chọn 1 target khoẻ mạnh             - CloudFront bắt 403
        │                                  → trả về /index.html (200)
        ▼                                    │
⑦ BACKEND (ECS task / EC2 / Lambda)          │
   - Security Group phải cho phép            │
     cổng từ ALB                             │
   - Xử lý, truy vấn DB, trả JSON            │
        │                                    │
        └──────────────────┬─────────────────┘
                           ▼
⑧ CLOUDFRONT nhận response từ origin
   - Đọc header Cache-Control để quyết định LƯU bao lâu
   - Nén gzip/brotli nếu cần
   - Gắn thêm security header (nếu có Response Headers Policy)
        │
        ▼
⑨ TRÌNH DUYỆT nhận HTML
   - Parse HTML → thấy <script src="/assets/main-a3f9.js">
   - Gửi request MỚI cho từng asset → quay lại bước ④
   - JS chạy → React mount → fetch('/api/products/123') → quay lại ④
        │
        ▼
⑩ GIAO DIỆN HIỆN RA

Đọc sơ đồ này ra được gì

  • Một lần tải trang = rất nhiều lần chạy qua sơ đồ. HTML là 1 request, mỗi file JS/CSS/ảnh là 1 request, mỗi lời gọi API là 1 request. Mỗi cái đều có thể hit hoặc miss cache độc lập với nhau.
  • CloudFront quyết định đi S3 hay ALB bằng path. Đây là lý do frontend và API có thể chung một tên miền → không cần CORS. Rất quan trọng, phần 3 và phần 6 nói kỹ.
  • Cache nằm ở bước ④, trước origin. Deploy file mới lên S3 không làm edge biết. Phải invalidate hoặc đổi tên file.
  • S3 không hiểu routing của SPA. S3 chỉ biết “có object tên này không”. /products/123 không phải object → 403/404. Phải cấu hình CloudFront trả index.html.
  • Backend nằm sâu nhất, trong VPC. Trình duyệt không nói chuyện trực tiếp với nó. Mọi thứ phải qua ALB hoặc API Gateway.

Thử đếm cho một trang thật: index.html (1) + ba file JS (3) + một file CSS (1) + bốn ảnh (4) + hai lời gọi API lúc mount (2) = mười một lần chạy qua sơ đồ; chín lần có thể là cache HIT không rời edge, hai lần API bắt buộc phải xuống tới ECS. Khi thấy trang “chậm”, câu hỏi đúng là: trong mười một request đó, cái nào miss cache và cái nào phải đi xa nhất.

Bốn câu hỏi bạn sẽ hỏi lại ở mọi bài sau: file này nằm ở đâu; request đang đứng ở chặng nào (②–⑨); chặng đó có cache không và cache có biết bạn vừa deploy không; ai đã trả lỗi này, CloudFront, S3, ALB hay backend (mỗi bên có “chữ ký” riêng trong response, phần 14 liệt kê).


Region, Availability Zone, Edge Location

Ba khái niệm địa lý này hay bị lẫn, và chúng ảnh hưởng trực tiếp đến tốc độ trang web của bạn.

  • Region (ví dụ ap-southeast-1): một khu vực địa lý lớn, chứa nhiều trung tâm dữ liệu. Singapore, Tokyo, Virginia… Backend và S3 bucket đặt ở đâu quyết định độ trễ cho lần MISS cache. Người dùng Việt Nam → chọn ap-southeast-1 (Singapore).
  • Availability Zone, AZ (ví dụ ap-southeast-1a): một (hoặc vài) trung tâm dữ liệu độc lập bên trong một region. Mỗi region có 3–6 AZ. ALB trải qua nhiều AZ để một AZ sập thì web vẫn sống. Bạn ít khi động tới, nhưng nên biết vì sao ALB bắt chọn ít nhất 2 subnet.
  • Edge Location (600+ điểm): điểm hiện diện của CloudFront, nhỏ, đặt rất gần người dùng. Có ở Hà Nội, TP.HCM. Đây là nơi file của bạn thực sự được phục vụ khi cache hit, và là lý do CloudFront làm trang nhanh lên rõ rệt.

Vài mã region bạn sẽ gặp nhiều nhất: ap-southeast-1 (Singapore), ap-northeast-1 (Tokyo), us-east-1 (N. Virginia). Mã này xuất hiện trong URL của S3, trong ARN, trong aws configure, nên hãy nhớ ít nhất mã của region bạn chọn.

Người dùng ở Hà Nội                 Region ap-southeast-1 (Singapore)
┌────────────┐                      ┌──────────────────────────────┐
│  Browser   │ ~15ms  ┌──────────┐  │  AZ-1a     AZ-1b     AZ-1c   │
│            ├───────►│  Edge    │  │  ┌────┐    ┌────┐    ┌────┐  │
└────────────┘        │  Hà Nội  │  │  │ECS │    │ECS │    │ECS │  │
                      └────┬─────┘  │  └────┘    └────┘    └────┘  │
                cache MISS │ ~40ms  │      ▲  ALB rải tải          │
                           └────────┼──────┘                       │
                                    │  S3 bucket (toàn region)     │
                                    └──────────────────────────────┘

Cache HIT  = 15ms                     (không rời Hà Nội)
Cache MISS = 15 + 40 + 40 + 15 ≈ 110ms+ (phải sang Singapore và về)

Khoảng cách 15ms so với 110ms là lý do series dành hai bài (phần 6, phần 7) chỉ để nói về cache.

Ngoại lệ cần nhớ đời: Chứng chỉ HTTPS (ACM) dùng cho CloudFront bắt buộc phải tạo ở region us-east-1 (N. Virginia), dù website của bạn phục vụ ai, ở đâu. Lý do: CloudFront là dịch vụ toàn cầu, phần điều khiển của nó đặt ở us-east-1, và nó chỉ nhìn thấy chứng chỉ trong region đó rồi tự phân phối ra mọi edge. Tạo nhầm region là lỗi kinh điển: chứng chỉ tạo xong nhưng không hiện trong danh sách chọn của CloudFront. Chứng chỉ cho ALB thì ngược lại, phải cùng region với ALB. Vì vậy một tên miền có cả CloudFront lẫn ALB nhận HTTPS trực tiếp sẽ cần hai chứng chỉ ở hai region.


IAM — mức tối thiểu frontend cần biết

IAM (Identity and Access Management) là hệ thống phân quyền của AWS. Bạn không cần thành chuyên gia, nhưng sẽ gặp nó mỗi ngày khi CI/CD báo AccessDenied.

Bốn khái niệm cốt lõi

  • User: một danh tính cho con người hoặc hệ thống, có mật khẩu và/hoặc access key. Hạn chế tạo user có access key: key bị lộ là mất tài khoản.
  • Role: một “bộ quyền mượn tạm”, giống thẻ khách ở quầy lễ tân. Không có mật khẩu cố định. Máy chủ ECS, hàm Lambda hay GitHub Actions đều nên dùng role. Đây là cách làm đúng.
  • Policy: tài liệu JSON mô tả ai (Principal) được làm gì (Action) lên cái gì (Resource), trong điều kiện nào (Condition).
  • Principle of least privilege: chỉ cấp đúng quyền cần, không hơn. Ví dụ CI/CD của bạn chỉ cần ghi lên một bucket, không cần s3:* trên tất cả bucket.

Một policy trông như thế nào

Đây là policy tối thiểu cho pipeline deploy frontend. Hãy đọc từng dòng, bạn sẽ dùng lại nó ở phần 13:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "GhiFileBuildLenBucket",
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:DeleteObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::my-app-frontend-prod",
        "arn:aws:s3:::my-app-frontend-prod/*"
      ]
    },
    {
      "Sid": "XoaCacheCloudFront",
      "Effect": "Allow",
      "Action": "cloudfront:CreateInvalidation",
      "Resource": "arn:aws:cloudfront::123456789012:distribution/E1ABCDEFGHIJKL"
    }
  ]
}

Version là phiên bản ngôn ngữ policy, luôn là 2012-10-17. Sid là nhãn tự đặt cho dễ đọc. s3:PutObject để upload file mới, s3:DeleteObject để xoá file cũ khi chạy sync --delete, s3:ListBucket để liệt kê xem cái gì cần xoá. Statement thứ hai chỉ cho phép xoá cache của đúng một distribution, không phải mọi distribution trong tài khoản.

Cạm bẫy: Chú ý hai dòng Resource của S3. arn:aws:s3:::bucket là chính cái bucket (dùng cho ListBucket), còn arn:aws:s3:::bucket/* là các object bên trong (dùng cho PutObject). Thiếu một trong hai là một trong những nguyên nhân AccessDenied phổ biến nhất khi chạy aws s3 sync. Thông báo lỗi của AWS luôn nói rõ thiếu quyền nào lên tài nguyên nào, ví dụ ... is not authorized to perform: s3:ListBucket on resource: arn:aws:s3:::my-app-frontend-prod. Đọc đúng chữ sau perform: và sau resource: là biết phải thêm dòng nào.

Đọc ARN — “địa chỉ” của mọi thứ trong AWS

arn:aws:s3:::my-app-frontend-prod/assets/main.js
─── ─── ── ─ ─ ──────────────────────────────────
 │   │   │  │ │  └─ tên tài nguyên
 │   │   │  │ └─ account id (S3 để trống vì tên bucket đã global unique)
 │   │   │  └─ region (S3 để trống vì tên bucket là global)
 │   │   └─ service
 │   └─ partition (aws, aws-cn, aws-us-gov)
 └─ luôn là "arn"

arn:aws:cloudfront::123456789012:distribution/E1ABCDEFGHIJKL
arn:aws:elasticloadbalancing:ap-southeast-1:123456789012:loadbalancer/app/my-alb/abc123

Bạn sẽ gặp ARN ở ba chỗ: trong policy (như trên), trong thông báo lỗi AccessDenied, và khi cần trỏ dịch vụ này tới dịch vụ kia (ví dụ bucket policy chỉ cho đúng một distribution đọc bucket, phần 4).

Ba điều tuyệt đối không làm

  1. Không bao giờ nhúng AWS access key vào code frontend. Code frontend ai cũng xem được, mở DevTools là thấy. Bot quét GitHub và bundle công khai lấy key trong vài phút. Frontend cần thao tác AWS thì đi qua backend hoặc presigned URL (phần 5).
  2. Không commit file .env chứa key lên Git. Dùng .gitignore và kiểm tra lại lịch sử commit. Key đã từng lên Git thì coi như đã lộ, phải thu hồi và tạo mới chứ không chỉ xoá khỏi code.
  3. Không dùng tài khoản root cho việc hằng ngày. Bật MFA cho root, cất đi, tạo IAM user riêng để dùng.

Ba cách tương tác với AWS

  • Console (giao diện web): dùng khi học, khi khám phá, khi debug nhanh. Bắt đầu từ đây. Nhìn thấy được mọi ô cấu hình giúp hiểu khái niệm nhanh hơn nhiều so với đọc docs.
  • CLI (dòng lệnh): dùng để deploy, viết script, chạy trong CI/CD. Bắt buộc phải biết vài lệnh: aws s3 sync, aws cloudfront create-invalidation. Cài rồi chạy aws configure.
  • IaC (Terraform, CDK, CloudFormation): dùng khi hạ tầng đã ổn định, cần tái lập được. Giai đoạn sau. Đừng học ngay từ đầu, bạn sẽ không hiểu mình đang khai báo cái gì.

CLI: cài và cấu hình

Cài AWS CLI v2 theo hướng dẫn chính thức cho hệ điều hành của bạn (trên macOS có thể dùng brew install awscli). Sau đó:

aws --version          # aws-cli/2.x.x ...
aws configure
# AWS Access Key ID [None]:     AKIA...
# AWS Secret Access Key [None]: ****
# Default region name [None]:   ap-southeast-1
# Default output format [None]: json

aws configure ghi vào hai file trong thư mục home:

# ~/.aws/credentials — KHÔNG bao giờ commit, không copy vào repo
[default]
aws_access_key_id = AKIA...
aws_secret_access_key = ...

# ~/.aws/config
[default]
region = ap-southeast-1
output = json

Khi có nhiều tài khoản (cá nhân và công ty), thêm một section [profile congty] trong ~/.aws/config và một section [congty] trong credentials, rồi chọn bằng --profile congty hoặc biến môi trường AWS_PROFILE=congty. Đây là cách tránh vô tình chạy aws s3 sync --delete vào bucket production của công ty khi đang học.

Lệnh đầu tiên nên chạy sau khi cấu hình là hỏi “tôi đang là ai”:

aws sts get-caller-identity
{
  "UserId": "AIDAEXAMPLEID",
  "Account": "123456789012",
  "Arn": "arn:aws:iam::123456789012:user/dev-vince"
}

Ba dòng này trả lời ba câu hỏi bạn hay lẫn nhất khi debug quyền: đang dùng key của ai, ở account nào, và ARN đó có khớp với thứ ghi trong policy không.


Lab 1.1 — Thiết lập ban đầu (30 phút)

  1. Tạo tài khoản AWS. Bật MFA cho tài khoản root ngay lập tức (Google Authenticator hoặc app tương tự).
  2. Vào Billing → Budgets → Create budget. Loại “Cost budget”, ngưỡng 5 USD/tháng, cảnh báo ở 80% và 100% qua email.
  3. Vào IAM → Users → Create user. Tạo user tên dev-yourname, gắn policy PowerUserAccess (đủ để học, không đụng được IAM cấp cao), bật MFA cho user này.
  4. Từ user vừa tạo, vào Security credentials → Create access key, chọn mục đích “Command Line Interface”.
  5. Cài AWS CLI, chạy aws configure, nhập key, chọn region ap-southeast-1, output format json.
  6. Kiểm tra: aws sts get-caller-identity phải trả về ARN của user bạn vừa tạo.

Kết quả mong đợi: Chạy aws sts get-caller-identity thấy đúng tên user của mình trong trường Arn, và trong hộp thư có email xác nhận budget đã được tạo.

Nếu bước 6 lỗi: Unable to locate credentials nghĩa là chưa chạy aws configure hoặc đang ở profile khác (kiểm tra echo $AWS_PROFILE); InvalidClientTokenId là access key gõ sai hoặc đã bị vô hiệu, tạo key mới; SignatureDoesNotMatch là secret key thiếu ký tự khi copy hoặc đồng hồ máy lệch; lệnh chạy được nhưng trường Account lạ nghĩa là bạn đang dùng credential của tài khoản công ty, xem lại ~/.aws/credentials.


Sai lầm hay gặp ở tuần đầu

  • Tạo tài nguyên nhầm region. Console có ô chọn region ở góc trên bên phải và nhớ lựa chọn gần nhất. Bạn tạo bucket ở Singapore, hôm sau mở Console thấy trống trơn vì đang ở Virginia. Trước khi hoảng, nhìn góc phải.
  • Tưởng tắt tab là tắt tài nguyên. ALB, NAT Gateway, RDS chạy 24/7 kể cả khi bạn ngủ. Sau mỗi lab, vào Billing → Cost Explorer, nhóm theo Service, kiểm tra không còn gì lạ.
  • Cấp AdministratorAccess cho pipeline để hết lỗi AccessDenied. Hết lỗi thật, nhưng key của pipeline giờ đủ quyền xoá cả tài khoản. Sửa đúng dòng policy còn thiếu thay vì mở toang.

Tóm tắt

  • Lên AWS, một dòng npm run dev bị tách thành nhiều dịch vụ rời (Route 53, CloudFront, S3, ALB, ECS, Security Group, ACM, CloudWatch); mỗi chặng đều có thể làm hỏng request và phải khai báo tường minh.
  • Sơ đồ vòng đời request 10 bước là xương sống của series: DNS → TLS → CloudFront xét behavior và cache → S3 hoặc ALB → backend → CloudFront đọc Cache-Control → trình duyệt parse HTML rồi lặp lại cho từng asset và API.
  • Cache nằm ở edge, trước origin; deploy lên S3 không làm edge biết. S3 không hiểu routing SPA. Backend nằm sâu trong VPC, không ai gọi thẳng được.
  • Region quyết định độ trễ khi MISS, edge location quyết định tốc độ khi HIT. Chứng chỉ ACM cho CloudFront bắt buộc ở us-east-1, cho ALB thì cùng region với ALB.
  • IAM: user cho người, role cho máy, policy là JSON “ai được làm gì lên cái gì”. Với S3 phải có cả ARN bucket lẫn ARN bucket/*.
  • Không nhúng key vào frontend, không commit .env, không dùng root hằng ngày.
  • Bắt đầu bằng Console để hiểu, dùng CLI để deploy, để IaC cho giai đoạn sau. Luôn có budget 5 USD làm phanh.

Phần 2 lấp ba lỗ hổng nền tảng mà phần lớn “lỗi AWS” thực ra bắt nguồn từ đó: DNS và Route 53, HTTPS với ACM, và cách đọc HTTP header trong tab Network.

Đọc thêm