bash - staycrafting.dev
LAST MODIFIED: 02 Oct 20:00

~$ cat dung-blog-bang-vibe-coding-va-do-free-nhin-lai-ca-hanh-trinh.md

Dựng blog bằng vibe coding và đồ free: nhìn lại cả hành trình

Bài tổng kết loạt bài: từ ý tưởng, vibe coding Rails cùng Claude, đến kiến trúc infra Cloud Run + TiDB, backup tự chế, email domain xịn xò. Tất cả gần như free.

Loạt bài về cái blog này đến đây là bài cuối. Hai bài trước toàn nói chuyện tiền, hôm nay nói chuyện làm: ý tưởng từ đâu ra, code thế nào, infra dựng ra sao, và mấy trò chế cháo để ăn free cho trọn.

Bài này chỉ kể toàn cảnh. Các bài hướng dẫn step by step chi tiết từng phần sẽ nằm ở một series riêng, và để đọc được thì anh em phải... nạp VIP. Đúng rồi, vận hành blog thì gần như free, nhưng để mình viết bài thì cũng cần trà đá chứ, phải không anh em.

1. Ý tưởng: brainstorm với Claude từ cái tên

Phần lớn mọi người dựng blog thì bắt đầu từ việc chọn theme. Mình bắt đầu từ việc ngồi chém gió với Claude.

Gần như mọi thứ "mềm" của blog đều ra đời từ mấy buổi brainstorm đó:

  • Tên và domain staycrafting.dev: hỏi qua hỏi lại vài chục cái tên, cái thì bị đăng ký rồi, cái thì đọc lên nghe như tên quán nhậu, cuối cùng chốt cái này.
  • UI dạng terminal: dân dev mà, nhìn cái màn hình đen chữ xanh là thấy thân thuộc. Ý tưởng này cũng là Claude gợi ý khi mình kể mình muốn một cái gì đó "nhìn là biết của dev".
  • Các action trên terminal: gõ lệnh gì thì làm gì, phản hồi ra sao, cũng là brainstorm cùng nhau mà ra.
  • Text content trên trang: lúc đầu cũng là bản nháp từ brainstorm. Nhưng càng về sau, khi web dần hoàn thiện, mình sửa lại gần hết cho đúng giọng của mình hơn. AI viết thì mượt, nhưng mượt quá nó lại không phải mình.

Bài học nhỏ: Claude rất giỏi đưa ra nhiều phương án để chọn. Còn việc chọn cái nào và chỉnh cho ra chất riêng thì vẫn là việc của mình.

2. Code: 100% vibe coding, review code là gì?

Blog viết bằng Ruby on Rails, chạy local bằng Docker. Và toàn bộ code là Claude viết.

Nói cho rõ: trang này là vibe coding 100%. Mình không thèm review code. Thứ mình review là:

  • Plan: Claude định làm gì, theo hướng nào.
  • Design: giao diện ra sao, có đúng ý không.
  • Hướng coding: kiến trúc tổng thể có hợp lý không.

Còn từng dòng code bên trong thì... tin tưởng tuyệt đối. Nghe hơi liều, nhưng có lý do:

  • Web chức năng đơn giản: hiển thị bài, quản lý bài, upload ảnh. Không có thanh toán, không có dữ liệu nhạy cảm.
  • Không có gì cần bảo mật ghê gớm (như bài trước có nói, hacker vào DB thì đọc được bài miễn phí, coi như thêm độc giả).

Nên cứ thoải mái mà vibe. Dự án công ty mà làm vậy thì mình không khuyến khích, sếp đọc được bài này chắc gọi lên nói chuyện.

3. Kiến trúc infra: toàn cảnh

Đây là phần mình mày mò nhiều nhất, và cũng vui nhất. Nhìn tổng thể nó như này:

                     Namecheap (domain)
                            │
                            ▼
   Người đọc ──────►  Cloud Run: web (service)  ◄──── Uptime check
                            │       │
                            │       └──► Cloud Storage (bucket ảnh, Active Storage)
                            ▼
                     TiDB Cloud (DB, free tier)
                            ▲
                            │
   Cloud Run: migrate (job) ┘   ← chạy mỗi lần deploy
   Cloud Run: backup  (job) ──► Cloud Storage (bucket backup, tự xóa sau 30 ngày)
          ▲
          └── Cloud Scheduler (mỗi đêm)

   GitHub (tạo tag) ──► Cloud Build ──► Artifact Registry (giữ 3 image gần nhất)
                             └──► chạy migrate job ──► deploy web
   Secret Manager: chứa toàn bộ thông tin nhạy cảm
   Logging + Alert: job lỗi thì bắn email

Đi lần lượt từng mảnh nhé.

3.1. CI/CD: tạo tag là tự deploy

Deploy bằng tay kiểu gõ lệnh trên máy thì vui được vài lần đầu, sau đó thì vừa mệt vừa dễ quên bước. Nên mình dựng luôn CD cho nó xịn xò: mỗi khi tạo tag release version trên GitHub là tự động deploy.

Luồng đơn giản lắm:

GitHub UI: Releases ──► Draft a new release ──► tạo tag v1.2.0 ──► Publish
        │
        ▼
Cloud Build trigger (bắt tag)
        │
        ├─► build Docker image
        ├─► push lên Artifact Registry
        ├─► chạy migrate job
        └─► deploy bản mới lên web service

Tag thì mình tạo luôn trên giao diện GitHub lúc tạo release, khỏi mở terminal gõ lệnh: vào mục Releases, gõ tên version mới, viết vài dòng release note, bấm Publish là xong. Ngồi đâu cũng release được, cầm điện thoại cũng release được.

Cloud Build có sẵn trigger kết nối với GitHub, chỉ cần cấu hình cho nó bắt sự kiện push tag (ví dụ tag dạng v*). Push code bình thường lên nhánh thì không có gì xảy ra, chỉ khi mình chủ động tạo tag thì mới lên production. Mỗi bản deploy đều gắn với một version rõ ràng, muốn biết production đang chạy bản nào thì nhìn tag là biết. Cảm giác như đang release phần mềm thật, dù thực ra chỉ là sửa một lỗi chính tả.

3.2. Lưu image

  • Cloud Build build xong thì đẩy image vào Artifact Registry.
  • Mình bật cleanup policy chỉ giữ 3 bản gần nhất. Không dọn là nó cứ đẻ mãi, phồng storage, tốn tiền. Bài 2 có kể ngày đầu nó ăn của mình 11k chỉ vì đống image rác.

3.3. Domain

Domain mua ở Namecheap, trỏ về Cloud Run. Sau khi gắn domain xong thì mình tắt luôn cái URL mặc định *.run.app của Cloud Run. Để làm gì? Để người ta chỉ vào được qua đúng một cửa chính, không có cửa sau nào lơ ngơ treo trên internet.

3.4. Cloud Run: chạy 3 con, mỗi con một việc

Đây là chỗ mình thấy thiết kế khá hay.

Con 1: web (dạng service). Đây là server phục vụ người đọc, có thể scale lên nhiều instance khi đông.

Con 2: migrate (dạng job). Tách riêng ra chứ không chạy migration lúc web khởi động. Lý do: nếu web bị scale ra nhiều instance cùng lúc, mỗi instance đều chạy db:migrate thì chúng nó tranh nhau sửa schema, dễ toang. Tách ra thành job thì migration chỉ chạy đúng một lần, trên một con, xong là tắt.

Con 3: backup (dạng job). Cái này nói kỹ ở phần dưới.

3.5. Database

DB vẫn dùng TiDB Cloud bản free như đã kể ở bài 2. Nhanh, ổn định, đủ dùng dư dả.

3.6. Ảnh và bí mật

  • Ảnh upload qua Active Storage của Rails được lưu trên Cloud Storage, một bucket riêng cho ảnh.
  • Mọi thứ nhạy cảm (DB password, key, thông tin SMTP...) để trong Secret Manager, Cloud Run đọc ra lúc chạy. Không có cái password nào nằm trong code hay trong image.

3.7. Giám sát

  • Uptime check: cứ mỗi phút gọi vào blog một lần, chết là biết ngay. Kiêm luôn việc giữ cho server và DB không ngủ.
  • Logging: log của cả web lẫn job đều đổ về Logs Explorer, có chuyện gì thì vào đây mà soi.

4. Backup DB: đồ free thì tự chế

Như bài trước đã nói, TiDB free chỉ giữ backup 1 ngày, không có backup thủ công. Nên phải chế cháo.

Cách làm của mình:

  1. Cloud Run job thứ 3: backup. Cũng dạng job giống migrate. Khi được gọi dậy, nó chạy một rake task của Rails.
  2. Rake task bản chất chỉ là gọi mysqldump thôi, không có gì cao siêu. Các thông số DB host, username, password, port... thì lấy luôn từ cấu hình của app Rails, khỏi khai báo lại lần nữa. Dump xong thì nén và đẩy lên Cloud Storage.
  3. Cloud Scheduler hẹn giờ mỗi đêm gọi job backup dậy.
  4. Alert khi job lỗi: trong Logs Explorer, mình tạo một alert bắt log job failed. Job mà chết thì bắn email về cho mình ngay. Backup mà chạy lỗi âm thầm cả tháng thì cũng như không có backup.
  5. Bucket backup riêng, tự xóa sau 30 ngày: bật lifecycle rule xóa file cũ quá 30 ngày.

Tại sao bucket backup phải tách riêng khỏi bucket ảnh? Vì bucket backup có rule tự động xóa file. Để chung thì có ngày mở blog ra thấy ảnh bài viết cũ bay màu hết, do bị rule dọn luôn. Cái đó thì không vui chút nào.

5. Email domain xịn xò, cũng free nốt

Có domain rồi thì phải có email theo domain cho nó chuyên nghiệp: hello@staycrafting.dev. Nghe như có cả một đội ngũ chăm sóc khách hàng đằng sau, thực ra chỉ có mình.

Nhận mail: iCloud

Mình dùng iCloud+. Mình vốn đã trả phí iCloud vì lưu trữ ảnh nhiều, cần dung lượng. Mà iCloud+ thì gói thấp nhất thôi cũng cho phép gắn custom domain để làm email. Thế là bấm vài cái, trỏ vài bản ghi DNS bên Namecheap, xong.

Vậy nên cái email hello@ nghe xịn xò kia, thực chất là hộp thư iCloud của mình. Không tốn thêm đồng nào.

Gửi mail: Brevo

Có email domain rồi thì tạo luôn tài khoản SMTP ở Brevo để app gửi mail (thông báo, liên hệ...). Bản free cho gửi 300 mail mỗi ngày. Với một blog mà độc giả thân thiết gồm bố mình, mình và con bot Google, thì 300 mail/ngày là quá xịn.

Túm cái váy lại

Mảnh Dùng gì Tiền
Ý tưởng, UI, content nháp Brainstorm với Claude Gói Claude đang dùng
Code Rails + Docker, vibe coding 100% 0đ thêm
CI/CD Tạo tag GitHub → Cloud Build tự deploy vài nghìn
Lưu image Artifact Registry (giữ 3 bản) vài nghìn
Chạy app Cloud Run: web + migrate job + backup job vài nghìn
DB TiDB Cloud free 0đ
Ảnh + backup Cloud Storage (2 bucket riêng) ~0đ
Hẹn giờ, giám sát Scheduler, Uptime check, Logging, Alert ~0đ
Domain Namecheap tiền domain/năm
Email iCloud+ (vốn đã trả) + Brevo free 0đ thêm

Thế đó. Dựng một website bằng toàn đồ gần như free hóa ra khá thú vị. Chỉ với vài buổi tối trong tuần ngồi cùng Claude, đã có một cái blog sương sương để viết linh tinh.

Nhưng cái được nhiều nhất không phải cái blog, mà là quá trình tự mày mò xây dựng. Mỗi chỗ muốn ăn free là một chỗ phải tìm hiểu: dựng CD bằng tag ra sao, job khác service chỗ nào, sao migration phải tách riêng, lifecycle rule hoạt động ra sao, alert dựng thế nào, DNS cho email trỏ kiểu gì... Học được kha khá thứ, và vui.

Tiếp theo: series VIP

Bài này chỉ là bản đồ. Còn hướng dẫn step by step từng phần, từ dựng CD bằng tag, config Cloud Run, viết rake task backup, dựng alert, đến gắn email domain, sẽ nằm trong một series chi tiết riêng.

Và như đã hứa: anh em phải nạp VIP mới đọc được. Giá bao nhiêu thì chưa biết, nhưng chắc chắn không đắt hơn một tuần trà đá.

Cùng đón chờ nhé!

~$ cd ..