All posts
Homepage Blog: kiến trúc, chức năng, và pipeline publish trên AWS
awsserverlessarchitectureblog

Homepage Blog: kiến trúc, chức năng, và pipeline publish trên AWS

Quang Tran D.'s avatarQuang Tran D.
Table of Contents24 sections

Vì sao chúng tôi quyết định tự xây?

Đầu năm 2026, team CMDN (Classmethod Đà Nẵng) cần một nơi để chia sẻ kiến thức, kinh nghiệm và các bài viết kỹ thuật trong nội bộ. Yêu cầu ban đầu nghe có vẻ đơn giản — nhưng khi nhìn vào các lựa chọn có sẵn, chúng tôi nhận ra không có cái nào thực sự phù hợp.

Dùng static site generator như Jekyll hay Hugo? Tác giả phải biết Git để đăng bài. Muốn thêm người viết là phải cấp quyền repo, review PR — bottleneck ngay từ đầu.

Dùng WordPress hay Ghost? Chi phí hosting cố định $9–25+/tháng dù không có ai đọc. Và quan trọng hơn: chúng tôi là một team kỹ thuật — tự xây và kiểm soát hoàn toàn stack là điều tự nhiên.

Chúng tôi quyết định tự xây. Blog chạy được trên AWS với chi phí ước tính $0.50–14/tháng tùy theo lưu lượng — gần như $0 khi không có traffic, tăng tuyến tính theo usage thực tế.

Tóm tắt nhanh

  • Blog CMDN kết hợp trang đọc tĩnh (nhanh, rẻ) với trang quản trị đầy đủ chức năng (viết bài, upload ảnh, xuất bản). Chức năng chia rõ phía người đọc và phía tác giả.

  • Bài mới sau khi đăng xuất hiện trên mạng trong khoảng 3 phút, do pipeline cập nhật chạy ngầm.

  • Chi phí ước tính $0.50–14 mỗi tháng tùy lượt xem. Tham chiếu thực tế: một blog tĩnh 18 tháng production trên AWS tốn khoảng $0.93/tháng (Bezdelev, Medium).

1. Chức năng chính

Blog CMDN không phải là static site generator thuần túy như Jekyll hay Hugo. Hệ thống có backend riêng với dashboard quản trị, full-text search, hệ thống tag, upload media, và Tiptap editor. Chức năng được phân tách rõ ràng thành hai nhóm:

Phía người đọc (public, không yêu cầu xác thực)

  • Xem danh sách bài đã xuất bản với phân trang

  • Đọc nội dung từng bài

  • Lọc bài theo tag

  • Tìm kiếm nội dung

  • Theo dõi RSS feed

Phía tác giả (yêu cầu xác thực)

  • Soạn thảo và chỉnh sửa bài qua WYSIWYG editor

  • Lưu bản nháp hoặc xuất bản

  • Upload và đính kèm ảnh (file tạm tự động xóa sau 24 giờ)

  • Quản lý tag

  • Xuất bản hoặc gỡ bài — hành động này kích hoạt pipeline cập nhật tự động

2. Kiến trúc tổng quan

Stack công nghệ

Layer

Công nghệ

Frontend

Next.js 15 (output: "export")

Hosting & CDN

S3 + CloudFront

Backend

Lambda + API Gateway HTTP API

Database

DynamoDB (2 bảng)

Authentication

Auth0

Publish pipeline

SQS + GitHub Actions

Toàn bộ hệ thống là serverless — không có EC2, không có ECS, không có server cần maintain 24/7.

Diagram kiến trúc tổng quan

Luồng dữ liệu

Reader path hoàn toàn tĩnh: CloudFront serve HTML trực tiếp từ S3, không phát sinh Lambda invocation nào. Đây là yếu tố then chốt giúp chi phí gần như bằng $0 khi traffic thấp.

Author path đi qua API Gateway → Lambda → DynamoDB. Auth0 JWT được verify tại tầng API Gateway native authorizer, không cần Lambda authorizer riêng per request — giảm latency và chi phí invocation.

Thiết kế database

DynamoDB được chia thành hai bảng với vai trò tách biệt:

  • Table A (Author workspace): Chứa toàn bộ draft và bài đã xuất bản. Mọi thao tác viết và chỉnh sửa đều ghi vào bảng này.

  • Table B (Reader store): Chỉ chứa bài đã xuất bản, phục vụ reader path.

Khi tác giả xuất bản, dữ liệu được ghi đồng thời vào cả hai bảng trong một transaction. Khi gỡ bài, bài bị xóa khỏi Table B nhưng vẫn tồn tại trong Table A. Thiết kế này đảm bảo reader query không phải scan qua bản nháp, tiết kiệm read capacity và giảm chi phí DynamoDB.

Lý do chọn HTTP API thay vì REST API

API Gateway HTTP API có giá $1.00/triệu request, so với $3.50/triệu của REST API — tiết kiệm khoảng 71% ở mức 100K page view/tháng. Blog backend không yêu cầu WAF tích hợp hay request validation phức tạp, nên HTTP API là lựa chọn đủ dùng và tối ưu chi phí.

Lý do chọn ARM64 (Graviton2) cho Lambda

AWS ghi nhận ARM64 Graviton2 giảm khoảng 20% duration cost so với x86 cho cùng workload. ARM64 hiện đã stable và là default được khuyến nghị cho Lambda function mới.

3. Pipeline publish

Vấn đề với Next.js static export

output: "export" của Next.js không hỗ trợ Incremental Static Regeneration (ISR). Bài mới xuất bản chỉ xuất hiện trên static route sau lần build và deploy kế tiếp — đây là hạn chế được xác nhận trong Next.js official docs.

Giải pháp: Lambda → SQS → GitHub Actions

CMDN giải quyết bằng pipeline bất đồng bộ:

Tác giả bấm Publish
  → Lambda ghi vào DynamoDB (Table A + Table B)
  → Lambda gi message vào SQS queue
  → GitHub Actions lắng nghe SQS trigger
  → Next.js static export rebuild
  → S3 sync
  → CloudFront cache invalidation
  → Bài live trên CDN

Thời gian end-to-end từ lúc bấm Publish đến khi bài xuất hiện: khoảng 3 phút.

Diagram publish pipeline

Lý do chọn pipeline này

  • Tận dụng GitHub Actions free tier. GitHub cung cấp 2.000 phút free/tháng cho private repo và không giới hạn cho public repo. Mỗi rebuild tốn 1–3 phút. Với tần suất 30 bài/tháng, tổng usage khoảng 90 phút — nằm hoàn toàn trong free tier. Sử dụng AWS CodeBuild hoặc self-hosted runner sẽ phát sinh thêm $5–10/tháng mà không có lợi thế rõ ràng.

  • Tách biệt write path khỏi read path. SQS là queue bất đồng bộ. Lambda trả về response cho tác giả ngay khi DynamoDB write hoàn tất, không chờ rebuild. Reader path (CloudFront → S3) hoàn toàn độc lập, không bị ảnh hưởng bởi publish spike.

  • ISR-like behavior không cần Next.js server thường trực. Bài cũ là static HTML, không cần Lambda SSR mỗi request. Trade-off duy nhất là publish latency ~60 giây — không phù hợp với news site, nhưng hoàn toàn chấp nhận được cho blog kỹ thuật hoặc blog nội bộ.

So sánh với alternative phổ biến: Hầu hết tutorial Next.js trên AWS chọn OpenNext hoặc AWS Amplify để giả lập ISR. Approach của CMDN đánh đổi một chút UX (publish latency) để đổi lấy kiến trúc đơn giản hơn và chi phí biến đổi theo usage thực tế.

4. Chi phí ước tính theo từng service

Toàn bộ hệ thống serverless — chi phí tỉ lệ thuận với usage thực tế. Dưới đây là breakdown theo từng service ở ba mức traffic khác nhau.

Giả định tính toán

Mức

Page view/tháng

API request/tháng

Ghi chú

Thấp

~5.000

~10.000

Blog nội bộ mới ra mắt

Trung bình

~50.000

~100.000

Blog có traction

Cao

~500.000

~1.000.000

Bài được chia sẻ rộng

Reader path (CloudFront → S3) không phát sinh Lambda invocation — chỉ tính CloudFront transfer và S3 GET request. Author path (API Gateway → Lambda → DynamoDB) tính riêng.

Breakdown chi phí theo service

Service

Mức thấp

Mức trung bình

Mức cao

Ghi chú

S3 (hosting static)

~$0.02

~$0.05

~$0.23

GET request + storage ~50MB

CloudFront

~$0.10

~$0.85

~$8.50

$0.0085/GB transfer, edge Asia

API Gateway HTTP API

~$0.01

~$0.10

~$1.00

$1.00/triệu request

Lambda

~$0.00

~$0.02

~$0.20

Free tier 1M req; ARM64 Graviton2

DynamoDB

~$0.10

~$0.50

~$2.50

On-demand; 2 bảng tách biệt

S3 (media upload)

~$0.02

~$0.10

~$0.50

Presigned URL, file tạm xóa sau 24h

SQS

~$0.00

~$0.00

~$0.01

Free tier 1M request/tháng

Auth0

~$0.00

~$0.00

~$0.00

Free tier 7.500 MAU

GitHub Actions

~$0.00

~$0.00

~$0.00

Free tier ~2.000 phút/tháng

Tổng ước tính

~$0.25–0.50

~$1.62–2.00

~$12.94–14.00

Lưu ý: Số liệu dựa trên AWS pricing công bố tại thời điểm triển khai (2026-Q1). Giá CloudFront tính theo edge region Asia Pacific. Lambda nằm trong free tier ở mức thấp và trung bình. DynamoDB on-demand — không phát sinh chi phí khi không có traffic.

Chi phí thực tế tham chiếu

Một blog tĩnh trên AWS sau 18 tháng production ghi nhận chi phí trung bình khoảng $0.93/tháng (Bezdelev, Medium, 2026) — phù hợp với ước tính mức thấp của chúng tôi. Blog CMDN có thêm Lambda và DynamoDB cho author path, nên thực tế sẽ cao hơn một chút tùy mức độ tác giả sử dụng dashboard.

So sánh với alternative

Setup CMDN

Ghost Pro

Wordpress

Traffic thấp

~$0.50/tháng

$9/tháng

$25/tháng

Traffic trung bình

~$2/tháng

$9/tháng

$25/tháng

Traffic cao

~$14/tháng

$25/tháng

$25/tháng

Chi phí khi zero traffic

~$0

$9/tháng (fixed)

$25/tháng (fixed)

Setup serverless có lợi thế rõ ràng ở giai đoạn đầu khi traffic thấp. Ở mức traffic cao (~500K page view/tháng), khoảng cách thu hẹp lại — nhưng chúng tôi vẫn kiểm soát hoàn toàn infrastructure và không bị vendor lock-in.

5. Kết luận — khi nào nên chọn setup này

Khi nào nên chọn setup này

Setup phù hợp với:

  • Blog công ty, blog kỹ thuật, hoặc blog sản phẩm

  • Team có kỹ năng AWS và muốn kiểm soát infrastructure

Khi nào không nên chọn

  • News site hoặc nội dung realtime: Publish latency 60 giây không chấp nhận được.

  • Team không có dev rành AWS: Chi phí setup và vận hành về kiến thức cao hơn dùng Ghost hay WordPress.

  • Cần CMS thân thiện với marketer: WYSIWYG editor tự xây không thể cạnh tranh với CMS chuyên dụng về UX.


Tham khảo