Mình đã xây dựng nền tảng giáo dục cho trẻ em với 0 đồng vốn và chi phí vận hành 100k/tháng như thế nào
TL;DR: Mình là một developer đã tự tay xây dựng Cú Thông Minh — nền tảng học mà chơi cho trẻ 3-8 tuổi, với 38+ thể loại game tương tác, 60+ bài blog SEO. Tổng chi phí đầu tư: 0 đồng. Chi phí vận hành: 100.000 VNĐ/tháng cho VPS. Bài viết này chia sẻ toàn bộ hành trình từ tech stack, deploy, đến SEO.

Mục lục
- Giới thiệu — Tại sao mình làm dự án này?
- Phần 1: Tech Stack — Chọn đúng công nghệ, tiết kiệm tối đa
- Phần 2: Deploy — Từ laptop lên production với 100k/tháng
- Phần 3: SEO — Để Google tìm thấy bạn khi không có tiền quảng cáo
- Tổng kết chi phí
1. Giới thiệu — Tại sao mình làm dự án này? {#1-giới-thiệu}
Mình nhận ra một vấn đề: các ứng dụng giáo dục cho trẻ em ở Việt Nam hoặc là đầy quảng cáo, hoặc là quá đắt, hoặc là nội dung không phù hợp văn hóa Việt. Mình muốn tạo một nơi mà trẻ em có thể vừa học vừa chơi, an toàn, không quảng cáo, và phụ huynh không cần lo lắng.
Kết quả sau vài tháng:
- 🎮 38+ thể loại game — từ toán, tiếng Việt, động vật, đến kỹ năng sống
- 📝 60+ bài blog chất lượng cho SEO
- 💰 Chi phí vận hành: ~100.000 VNĐ/tháng
- 🚫 0 đồng cho quảng cáo, hosting frontend, database, auth, storage
Vậy mình đã làm thế nào?
2. Phần 1: Tech Stack — Chọn đúng công nghệ, tiết kiệm tối đa {#2-tech-stack}
Nguyên tắc chọn stack
Mình theo đúng 3 nguyên tắc:
- Free tier đủ dùng — tận dụng tối đa tier miễn phí của các dịch vụ
- Ít dependency — càng ít service, càng ít thứ phải maintain
- Developer experience tốt — một mình làm thì DX phải mượt
Frontend: Next.js 16 + React 19
next: 16.1.4
react: 19.2.3
typescript: ^5
tailwindcss: ^4
Tại sao Next.js?
- SSR/SSG giúp SEO cực mạnh (quan trọng khi không có tiền quảng cáo)
- App Router với Server Components giảm JavaScript gửi đến client
- React Compiler (bật trong
next.config.ts) — tự động memo hóa, không cần louseMemo/useCallback - Image optimization built-in — tự động resize, convert sang AVIF/WebP
- PWA support — user có thể "cài" app lên điện thoại mà không cần App Store
// next.config.ts — Một số config quan trọng
const nextConfig: NextConfig = {
output: "standalone", // Docker-friendly output
reactCompiler: true, // Bật React Compiler
images: {
formats: ["image/avif", "image/webp"], // Ảnh nhẹ hơn 60-80%
minimumCacheTTL: 2592000, // Cache 30 ngày
},
experimental: {
// Tree-shake chỉ import icon cần dùng
optimizePackageImports: ["lucide-react", "framer-motion"],
},
};
Database + Auth + Storage: Supabase (Free tier)
Đây là lựa chọn "thay đổi cuộc chơi". Thay vì phải tự setup PostgreSQL, viết auth system, setup file storage riêng — Supabase cho tất cả miễn phí:
| Service | Supabase Free Tier | Mình dùng |
|---|---|---|
| Database (PostgreSQL) | 500 MB | ✅ Đủ |
| Auth | 50,000 MAU | ✅ Thoải mái |
| Storage | 1 GB | ✅ Ảnh game |
| Edge Functions | 500K invocations/tháng | ✅ Chưa dùng hết |
// Dùng Drizzle ORM thay vì query trực tiếp
// Type-safe, migration dễ quản lý
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/db/schema.ts",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
Tại sao Drizzle ORM mà không phải Prisma?
- Bundle size nhỏ hơn nhiều (quan trọng cho serverless)
- Type-safe mà không cần code generation
- Query builder gần với SQL thuần
UI & Animation
framer-motion: ^12.35.0 # Animation mượt mà
lucide-react: ^0.562.0 # Icon SVG nhẹ
canvas-confetti: ^1.9.4 # Hiệu ứng confetti khi bé hoàn thành bài
Monitoring: Sentry (Free tier)
- Error tracking real-time
- Tunnel route qua server để tránh bị ad-blocker chặn
// Sentry chạy qua tunnel, ad-blocker không chặn được
tunnelRoute: "/monitoring",
Blog: MDX (miễn phí, không cần CMS)
Thay vì trả tiền cho Contentful, Sanity, hay WordPress:
- Viết blog bằng MDX files ngay trong repo
- Parse bằng
next-mdx-remote+gray-matter - 0 đồng, version control bằng Git, deploy cùng app
content/
└── blogs/
├── be-3-tuoi-nen-hoc-gi.mdx
├── day-be-hoc-dem.mdx
├── giao-duc-som-la-gi.mdx
└── ... (60+ bài)
Tổng kết Tech Stack
| Thành phần | Công nghệ | Chi phí |
|---|---|---|
| Frontend | Next.js 16 + React 19 | 0đ |
| Database | Supabase PostgreSQL | 0đ (free tier) |
| Auth | Supabase Auth | 0đ |
| File Storage | Supabase Storage | 0đ |
| Blog/CMS | MDX trong repo | 0đ |
| Icons | Lucide React | 0đ |
| Monitoring | Sentry | 0đ (free tier) |
| Tổng | 0 đồng |
3. Phần 2: Deploy — Từ laptop lên production với 100k/tháng {#3-deploy}
Tại sao không dùng Vercel?
Vercel là lựa chọn tự nhiên cho Next.js, nhưng:
- Free tier giới hạn bandwidth (100 GB/tháng)
- Serverless function timeout ngắn
- Khi scale lên, giá rất đắt
- Muốn toàn quyền kiểm soát server
VPS: 100.000 VNĐ/tháng
Mình thuê một VPS tại Việt Nam:
- RAM: đủ chạy Docker
- CPU: đủ build + serve
- Bandwidth: không giới hạn
- Giá: ~100.000 VNĐ/tháng
Docker Multi-Stage Build
Mình dùng Dockerfile multi-stage để giữ image nhẹ nhất có thể:
# Stage 1: Install dependencies
FROM node:20-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
ENV NODE_OPTIONS="--max-old-space-size=4096"
RUN npm run build
# Stage 3: Production (chỉ copy output cần thiết)
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Chỉ copy standalone output — image cực nhẹ
COPY /app/.next/standalone ./
COPY /app/.next/static ./.next/static
COPY /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
Tip:
output: "standalone"trongnext.config.tslà key. Nó tạo ra một thư mục chỉ chứa đúng những gì cần để chạy production — không cónode_modulesnặng nề.
Deploy Script: Build local, chuyển lên VPS
Đây là phần thú vị: VPS rẻ = RAM ít. Build Next.js cần nhiều RAM. Giải pháp? Build trên máy Mac (RAM 16GB), rồi rsync image lên VPS.
#!/bin/bash
VPS_IP="xxx.xxx.xxx.xxx"
IMAGE_NAME="cuthongminh-web"
# 1. Build Docker image trên máy local
docker build --platform linux/amd64 -t ${IMAGE_NAME}:latest .
# 2. Save thành file tar
docker save ${IMAGE_NAME}:latest -o /tmp/${IMAGE_NAME}.tar
# 3. Chuyển file tar lên VPS bằng rsync
rsync -avz --progress /tmp/${IMAGE_NAME}.tar root@${VPS_IP}:/tmp/
# 4. SSH vào VPS, load image và restart container
ssh root@${VPS_IP} "\
docker load -i /tmp/${IMAGE_NAME}.tar && \
cd /var/www/cuthongminh.com/frontend && \
docker compose -f docker-compose.deploy.yml up -d --force-recreate"
Quy trình deploy: chạy 1 lệnh ./deploy.sh, mất khoảng 3-5 phút, zero downtime (Docker tự restart container mới trước khi tắt cũ).
Docker Compose trên VPS
version: "3.8"
services:
cuthongminh-web:
image: cuthongminh-web:latest
container_name: cuthongminh_web
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=production
env_file:
- .env.production
Đơn giản đến mức bất ngờ. Nginx đứng trước làm reverse proxy + SSL (Let's Encrypt miễn phí).
Tổng kết Deploy
| Thành phần | Giải pháp | Chi phí |
|---|---|---|
| Server | VPS Việt Nam | ~100k/tháng |
| Container | Docker + Docker Compose | 0đ |
| SSL | Let's Encrypt | 0đ |
| Reverse Proxy | Nginx | 0đ |
| CI/CD | Shell script (deploy.sh) |
0đ |
| Domain | cuthongminh.com | ~250k/năm (~20k/tháng) |
4. Phần 3: SEO — Để Google tìm thấy bạn khi không có tiền quảng cáo {#4-seo}
Khi ngân sách quảng cáo bằng 0, SEO là kênh marketing duy nhất. Mình đã tối ưu rất kỹ.
4.1. Technical SEO
Sitemap động tự động
Thay vì viết sitemap bằng tay, mình tự generate từ code:
// src/app/sitemap.ts
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = "https://cuthongminh.com";
// Trang tĩnh
const staticRoutes = [
{ url: baseUrl, priority: 1 },
{ url: `${baseUrl}/games`, priority: 0.9 },
];
// Tự động scan tất cả thư mục game
const gameFolders = fs.readdirSync(gamesDir)
.filter(file => !file.startsWith("[") && !file.startsWith("."));
const gameRoutes = gameFolders.map(game => ({
url: `${baseUrl}/games/${game}`,
priority: 0.8,
}));
// Tự động scan tất cả file blog .mdx
const blogFiles = fs.readdirSync(blogsDir)
.filter(file => file.endsWith(".mdx"));
const blogRoutes = blogFiles.map(file => ({
url: `${baseUrl}/blogs/${file.replace(/\.mdx$/, "")}`,
priority: 0.7,
}));
return [...staticRoutes, ...gameRoutes, ...blogRoutes];
}
Kết quả: Mỗi khi thêm game hoặc blog mới → sitemap tự cập nhật → Google crawl nhanh hơn.
Robots.txt thông minh
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: "*",
allow: "/",
disallow: ["/auth/", "/settings/", "/learn-progress/", "/api/"],
},
sitemap: "https://cuthongminh.com/sitemap.xml",
};
}
Chỉ cho Google index nội dung public, chặn trang auth và API.
4.2. Schema.org Structured Data
Đây là thứ giúp Google hiểu website bạn là gì:
// Schema cho Educational Organization
const orgJsonLd = {
"@context": "https://schema.org",
"@type": "EducationalOrganization",
name: "Cú Thông Minh",
url: "https://cuthongminh.com",
description: "Nền tảng giáo dục tương tác cho trẻ em từ 3-8 tuổi...",
foundingDate: "2024",
areaServed: { "@type": "Country", name: "Vietnam" },
knowsAbout: [
"Early childhood education",
"Educational games for kids",
"Vietnamese language learning",
],
};
// Schema cho Web Application
const appJsonLd = {
"@type": "WebApplication",
applicationCategory: "EducationalApplication",
offers: { price: "0", priceCurrency: "VND" },
aggregateRating: { ratingValue: "4.9", reviewCount: "1280" },
};
4.3. Content SEO: 60+ bài blog MDX
Chiến lược đơn giản: viết bài blog trả lời đúng câu hỏi phụ huynh đang tìm kiếm.
Ví dụ các bài đã viết:
be-3-tuoi-nen-hoc-gi.mdx→ keyword: "bé 3 tuổi nên học gì"day-be-hoc-dem.mdx→ keyword: "dạy bé học đếm"giao-duc-som-la-gi.mdx→ keyword: "giáo dục sớm là gì"hoc-mau-sac.mdx→ keyword: "dạy bé học màu sắc"
Mỗi bài blog đều:
- Có metadata SEO riêng (title, description, OG image)
- Link nội bộ về trang game liên quan
- Được thêm vào sitemap tự động
4.4. Performance = SEO
Google đánh giá Core Web Vitals. Những gì mình làm:
// Cache headers cho static assets — 1 năm, immutable
{
source: "/_next/static/(.*)",
headers: [{
key: "Cache-Control",
value: "public, max-age=31536000, immutable",
}],
},
// Cache headers cho optimized images — 30 ngày
{
source: "/_next/image",
headers: [{
key: "Cache-Control",
value: "public, max-age=2592000, stale-while-revalidate=86400",
}],
},
Thêm các kỹ thuật khác:
- Dynamic import cho các component không cần thiết ngay (FAQ, Testimonials, Floating CTA)
- Preconnect đến CDN assets
loading="lazy"cho ảnh below-the-fold- Font từ Google Fonts với
display: "swap"— text hiển thị ngay, không chờ font load
4.5. FAQ Schema cho AI/Voice Search
const HOME_FAQ_ITEMS = [
{
question: "Cú Thông Minh là gì?",
answer: "Ứng dụng giáo dục tương tác dành cho trẻ em từ 3-8 tuổi...",
},
{
question: "Ứng dụng có miễn phí không?",
answer: "Cung cấp nhiều trò chơi miễn phí. Nâng cấp premium với 20+ thể loại...",
},
];
FAQ Schema giúp xuất hiện trên Google Featured Snippets và AI chatbot responses.
5. Tổng kết chi phí {#5-tổng-kết}
Chi phí ban đầu: 0 đồng
| Hạng mục | Giải pháp | Chi phí |
|---|---|---|
| Framework | Next.js (open source) | 0đ |
| Database | Supabase Free tier | 0đ |
| Auth | Supabase Auth | 0đ |
| Storage | Supabase Storage | 0đ |
| Monitoring | Sentry Free tier | 0đ |
| CMS | MDX files trong repo | 0đ |
| SSL | Let's Encrypt | 0đ |
Chi phí vận hành hàng tháng: ~100.000 VNĐ
| Hạng mục | Chi phí/tháng |
|---|---|
| VPS | ~100.000 VNĐ |
| Domain | ~20.000 VNĐ (250k/năm) |
| Tổng | ~120.000 VNĐ/tháng |
Kết quả đạt được
- 🎮 38+ thể loại game tương tác cho trẻ em
- 📝 60+ bài blog SEO content
- 📱 PWA chạy trên mọi thiết bị
- 🔍 100+ trang được index trên Google
- 🛡️ Không quảng cáo, an toàn cho trẻ
- 📊 Error monitoring real-time với Sentry
Lời kết
Bạn không cần nhiều tiền để bắt đầu. Với hệ sinh thái open source hiện nay và các free tier rộng rãi, một developer hoàn toàn có thể tự xây dựng và vận hành một sản phẩm hoàn chỉnh với chi phí gần như bằng 0.
Điều quan trọng nhất không phải là tiền, mà là:
- Chọn đúng stack — tận dụng free tier
- Tự động hóa — deploy một lệnh, sitemap tự generate
- SEO từ ngày đầu — khi không có tiền quảng cáo, organic traffic là tất cả
Nếu bạn đang có một ý tưởng sản phẩm, đừng chờ có tiền hay có team. Hãy bắt đầu ngay hôm nay.
👉 Trải nghiệm tại: cuthongminh.com
Nếu bạn thấy bài viết hữu ích, hãy upvote và chia sẻ nhé! Có câu hỏi gì, comment bên dưới mình sẽ trả lời. 🦉
All rights reserved