Mục lục
- Mục tiêu bài học
- Railway là gì
- Deploy lên Railway — từng bước
- railway.json — cấu hình build và deploy
- Railway CLI
- Database, Redis và Volume trên Railway
- Railway specifics — sleep, networking, environments
- Fly.io là gì
- Deploy lên Fly.io — từng bước
- fly.toml — cấu hình chi tiết
- Fly Machines — scale và multi-region
- Secrets và Volume trên Fly.io
- Database và GPU trên Fly.io
- So sánh Railway vs Fly.io vs Render
- Common pitfalls
- Tóm tắt
- Bài tiếp theo
Mục tiêu bài học
Sau bài này bạn sẽ:
- ✅ Hiểu Railway hoạt động thế nào và khi nào phù hợp
- ✅ Deploy FastAPI app lên Railway qua Git + CLI
- ✅ Cấu hình
railway.jsonđúng chuẩn - ✅ Hiểu Fly.io dùng Firecracker microVM, không phải Docker container thuần
- ✅ Deploy và scale multi-region với
fly.toml - ✅ Chọn được platform phù hợp dựa trên bảng so sánh 3 PaaS
Railway là gì
Railway là PaaS deploy từ Git repo. Điểm nổi bật là dashboard UX rõ ràng, tích hợp database 1-click, và auto-detect build tool từ Dockerfile hoặc Nixpacks (build Python app mà không cần Dockerfile).
Service types
- Web Service — serve HTTP, có URL public
*.up.railway.app - Cron Job — chạy định kỳ theo schedule
- Database — Postgres, MySQL, MongoDB, Redis (managed, cùng project)
- Volume — persistent storage gắn vào service
Pricing (2024-2025)
- Trial: $5 credit một lần (không cần card), sau đó cần upgrade
- Pro: $5/tháng minimum + usage-based
- RAM: $0.000463/GB-giờ
- vCPU: $0.000231/vCPU-giờ
- Ví dụ: 512 MB RAM, 0.5 vCPU, chạy 24/7 ≈ $5-7/tháng
Khi nào phù hợp
- Prototype đến small production, cần DB và API trong cùng project
- Ưu tiên UX dashboard hơn flexibility cấu hình
- Team nhỏ, không muốn quản lý infra
Deploy lên Railway — từng bước
1. Tạo tài khoản và project
- Truy cập https://railway.app → đăng ký bằng GitHub
- New Project → Deploy from GitHub Repo
- Chọn repo, Railway tự detect:
- Nếu có
Dockerfile→ build Docker image - Nếu không → Nixpacks tự phát hiện Python và build
2. Cấu trúc project mẫu
my-ai-api/
├── Dockerfile
├── railway.json
├── requirements.txt
├── main.py
└── .env.example
3. Cấu hình env vars
Sau khi Railway detect repo, vào tab Variables của service:
- Add từng biến qua UI:
OPENAI_API_KEY,MODEL_PATH, ... - Hoặc import từ file
.env(Railway UI hỗ trợ paste bulk) - Railway tự inject biến
PORT— dùng trong start command
4. Auto-deploy
Mỗi lần git push lên branch được config → Railway tự trigger build và deploy. Không cần CI/CD riêng cho workflow đơn giản.
railway.json — cấu hình build và deploy
File railway.json (hoặc railway.toml) ở root repo cho phép override cấu hình mặc định.
{
"$schema": "https://railway.com/railway.schema.json",
"build": {
"builder": "DOCKERFILE",
"dockerfilePath": "Dockerfile"
},
"deploy": {
"startCommand": "uvicorn main:app --host 0.0.0.0 --port $PORT",
"healthcheckPath": "/health",
"restartPolicyType": "ON_FAILURE",
"restartPolicyMaxRetries": 3
}
}
Giải thích các field quan trọng
builder: "DOCKERFILE"— dùng Dockerfile, không dùng Nixpacksbuilder: "NIXPACKS"— để Railway tự build Python (không cần Dockerfile)startCommand— override CMD trong Dockerfile. Railway inject$PORTtự độnghealthcheckPath— Railway ping path này để xác nhận service healthy trước khi route trafficrestartPolicyType: "ON_FAILURE"— tự restart khi crash, tối đa 3 lần
Ví dụ dùng Nixpacks (không có Dockerfile)
{
"$schema": "https://railway.com/railway.schema.json",
"build": {
"builder": "NIXPACKS"
},
"deploy": {
"startCommand": "uvicorn main:app --host 0.0.0.0 --port $PORT",
"healthcheckPath": "/health",
"restartPolicyType": "ON_FAILURE",
"restartPolicyMaxRetries": 3
}
}
Lưu ý: Nixpacks đọc requirements.txt hoặc pyproject.toml. Nếu cần CUDA hoặc system lib đặc biệt thì vẫn cần Dockerfile.
Railway CLI
# Cài đặt
npm i -g @railway/cli
# Đăng nhập (mở browser)
railway login
# Link thư mục hiện tại với Railway project
railway link
# Deploy thư mục hiện tại lên project đã link
railway up
# Xem log realtime
railway logs
# Chạy script local nhưng dùng env vars của project (useful cho migration)
railway run python migrate.py
# Xem danh sách env vars
railway variables
# Set env var
railway variables --set "MODEL_NAME=gpt-4o-mini"
Workflow thực tế
Với AI app có model weights nặng, thường dùng railway run để chạy script tải model hoặc migration DB từ local nhưng với đúng env vars của production — tránh phải SSH vào container.
# Chạy database migration với production credentials
railway run python -m alembic upgrade head
# Debug: in env vars của project
railway run env | grep DATABASE_URL
Database, Redis và Volume trên Railway
Database 1-click
- Trong project dashboard → New Service → chọn Postgres (hoặc MySQL / MongoDB / Redis)
- Railway tạo service DB trong cùng project
- Connection string (
DATABASE_URL) tự động inject vào các service khác cùng project qua Reference Variable
# Reference Variable trong dashboard — Railway tự resolve
DATABASE_URL = ${{Postgres.DATABASE_URL}}
REDIS_URL = ${{Redis.REDIS_URL}}
Không cần copy-paste URL thủ công. Nếu DB service được recreate (URL đổi), reference variable tự cập nhật.
Persistent Volume
Dùng khi cần lưu model weights hoặc data file giữa các lần deploy:
- Service settings → Volumes → Add Volume
- Chỉ định mount path, ví dụ
/data - Volume gắn với service, không share giữa các service khác nhau
Lưu ý quan trọng: Volume trên Railway gắn với 1 region. Khi migrate region, volume không tự di chuyển theo — cần export/import data thủ công.
Railway specifics — sleep, networking, environments
Service sleep
- Trial / Hobby: service sleep sau thời gian idle (không có request). Cold start khi có request mới (~1-5s tùy image size)
- Pro: không sleep, service chạy liên tục
Với AI inference API, sleep không chấp nhận được trong production vì model load time thêm vào cold start. Dùng Pro tier hoặc ping định kỳ.
Private networking
Các service trong cùng project communicate với nhau qua private DNS (không ra Internet):
# Service "api" gọi service "postgres" trong cùng project
# URL private: postgres.railway.internal:5432
# Tự động inject khi dùng Reference Variable
Multiple environments
Railway hỗ trợ nhiều environment (Production, Staging, PR Preview) trong 1 project. Mỗi environment có bộ env vars riêng và có thể có service riêng. Hữu ích khi cần test model version mới trước khi deploy production.
Fly.io là gì
Fly.io là PaaS với khả năng deploy nhiều region đồng thời. App chạy trên Firecracker microVM — lightweight virtual machine do Amazon phát triển cho AWS Lambda, cho boot time nhanh hơn VM thông thường nhưng isolation tốt hơn container thuần.
Điểm khác biệt so với Railway
- Multi-region native: 1 lệnh scale app ra nhiều region (Singapore, Tokyo, Frankfurt, ...)
- Anycast routing: request tự route đến region gần user nhất
- Firecracker microVM: không phải Docker container — mỗi Machine là 1 VM nhỏ
- CLI-first: workflow chủ yếu qua terminal, dashboard ít tính năng hơn Railway
- GPU support: A10, A100 (đắt nhưng khả dụng)
Pricing (2024-2025)
- Shared vCPU: $0.0000022/vCPU-giây
- RAM: theo block (256MB increments)
- Free allowance: 3 shared-cpu-1x VMs 256MB RAM, 3GB volume
- Sau free tier: usage-based, không có monthly minimum
Khi nào phù hợp
- App cần latency thấp toàn cầu (inference gần user)
- Cần edge compute hoặc multi-region stateless API
- Dùng GPU inference mà không muốn setup Kubernetes
- Quen CLI workflow, không cần dashboard phức tạp
Deploy lên Fly.io — từng bước
1. Cài flyctl (Fly CLI)
# macOS / Linux
curl -L https://fly.io/install.sh | sh
# macOS (Homebrew)
brew install flyctl
# Windows (PowerShell)
pwsh -Command "iwr https://fly.io/install.ps1 -useb | iex"
2. Đăng ký và đăng nhập
# Tạo tài khoản mới
fly auth signup
# Hoặc đăng nhập nếu đã có tài khoản
fly auth login
3. Khởi tạo app
# Trong thư mục project
fly launch
fly launch hỏi interactive:
- App name (hoặc auto-generate)
- Region (primary region)
- Có cần Postgres/Redis không
Kết quả: tạo file fly.toml và register app trên Fly.
4. Deploy
# Build image và deploy
fly deploy
# Theo dõi logs trong lúc deploy
fly logs
# Mở app trên browser
fly open
# Kiểm tra status machines
fly status
5. Xem thông tin app
# Danh sách machines đang chạy
fly machines list
# SSH vào machine đang chạy
fly ssh console
# Xem logs theo thời gian thực
fly logs --tail
fly.toml — cấu hình chi tiết
app = "my-ai-api"
primary_region = "sin" # Singapore
[build]
dockerfile = "Dockerfile"
[http_service]
internal_port = 8000
force_https = true
auto_stop_machines = "stop" # dừng machine khi idle
auto_start_machines = true # khởi động lại khi có request
min_machines_running = 0 # cho staging; đặt 1 cho prod
[env]
LOG_LEVEL = "info"
# Không đặt secret ở đây — dùng fly secrets set
[[vm]]
cpu_kind = "shared"
cpus = 1
memory_mb = 1024
Giải thích các section
primary_region— region mặc định khi deploy. Mã region:sin(Singapore),hkg(Hong Kong),nrt(Tokyo),fra(Frankfurt),iad(Virginia)auto_stop_machines = "stop"— machine dừng khi không có request. Options:"off"(không auto-stop),"stop","suspend"(nhanh hơn stop, chỉ supported trên một số region)auto_start_machines = true— tự khởi động machine khi có request vàomin_machines_running = 0— số machine tối thiểu luôn chạy. Đặt1để tránh cold start trong productioncpu_kind = "shared"— shared CPU (rẻ hơn). Dùng"performance"cho CPU-intensive inference
Health check
[[http_service.checks]]
grace_period = "10s"
interval = "30s"
method = "GET"
path = "/health"
timeout = "5s"
Fly dùng health check để xác định machine healthy trước khi route traffic. Nếu app khởi động lâu (load model weights), tăng grace_period lên 30s-60s.
Fly Machines — scale và multi-region
Trên Fly.io, mỗi instance app là 1 Machine. Machine = Firecracker microVM chạy image của bạn. Fly quản lý lifecycle: start, stop, route request.
Scale số lượng và region
# Scale lên 3 machine, mỗi region 1 machine
fly scale count 3 --region sin,hkg,nrt
# Scale chỉ trong 1 region
fly scale count 2 --region sin
# Xem resource hiện tại
fly scale show
# Thay đổi RAM và CPU
fly scale vm shared-cpu-1x --memory 2048
Anycast routing
Fly dùng anycast IP — cùng 1 IP nhưng request được route đến region gần nhất (về mặt network). Người dùng ở Singapore sẽ hit machine sin, người dùng ở Nhật hit nrt.
Với AI inference, nếu model nhỏ có thể load vào memory tất cả region thì multi-region giúp giảm latency đáng kể. Nếu model lớn (>4GB), cần cân nhắc cost.
Cold start
Khi auto_stop_machines = "stop" và min_machines_running = 0, machine dừng khi idle và khởi động lại khi có request đầu tiên. Cold start bao gồm:
- Firecracker boot: ~300ms
- App startup + model load: phụ thuộc vào code
Tổng cold start thường 1-5s. Cho production với yêu cầu latency thấp, đặt min_machines_running = 1.
Secrets và Volume trên Fly.io
Secrets
Không đặt credentials trong fly.toml hay Dockerfile. Dùng fly secrets:
# Set secret (inject vào app như env var)
fly secrets set OPENAI_API_KEY=sk-proj-...
fly secrets set DATABASE_URL=postgresql://...
# Set nhiều cùng lúc
fly secrets set OPENAI_API_KEY=sk-... MODEL_NAME=gpt-4o-mini
# Xem danh sách secrets (chỉ tên, không thấy value)
fly secrets list
# Xóa secret
fly secrets unset OPENAI_API_KEY
Sau khi set secret, Fly tự restart app để inject giá trị mới. Nếu muốn set mà không restart ngay: fly secrets set --stage rồi deploy sau.
Persistent Volume
Volume là block storage gắn với 1 region. Dùng để lưu model weights hoặc data:
# Tạo volume 10GB ở Singapore
fly volumes create model_data --region sin --size 10
# Liệt kê volumes
fly volumes list
Mount volume vào app qua fly.toml:
[[mounts]]
source = "model_data"
destination = "/data"
App sau khi deploy có thể đọc/ghi vào /data. Thường dùng entrypoint script để download model weights vào volume lần đầu:
#!/bin/sh
# entrypoint.sh — chạy trước khi start uvicorn
if [ ! -f /data/model.bin ]; then
echo "Downloading model..."
python download_model.py --output /data/model.bin
fi
exec uvicorn main:app --host 0.0.0.0 --port 8080
Quan trọng: Volume chỉ accessible trong 1 region. Nếu scale sang region khác (nrt, hkg), mỗi region cần volume riêng — volume không share giữa các region.
Database và GPU trên Fly.io
Fly Postgres
# Tạo Postgres cluster
fly postgres create --name my-ai-db --region sin
# Attach vào app (tự inject DATABASE_URL)
fly postgres attach my-ai-db
# Kết nối trực tiếp để debug
fly postgres connect -a my-ai-db
Fly Postgres là app Postgres chạy trên Fly Machines, không phải managed service như AWS RDS. Bạn chịu trách nhiệm backup và patching. Phù hợp cho prototype và staging. Production nghiêm túc nên dùng managed Postgres (Neon, Supabase, hoặc cloud provider).
Upstash Redis
# Tạo Redis (tích hợp Upstash)
fly redis create
# Upstash Redis là managed service, tự inject REDIS_URL
GPU (A10 / A100)
Fly có GPU support nhưng không phải tất cả region đều có. GPU machines đắt hơn đáng kể:
# Deploy với GPU A10
fly deploy --vm-gpu-kind a10
Hoặc trong fly.toml:
[[vm]]
gpu_kind = "a10"
cpus = 8
memory_mb = 32768
GPU region: chủ yếu ord (Chicago) và iad (Virginia) tính đến 2025. Kiểm tra availability tại docs.fly.io trước khi plan.
So sánh Railway vs Fly.io vs Render
| Tiêu chí | Railway | Fly.io | Render |
|---|---|---|---|
| Pricing model | $5/tháng + usage-based (RAM/CPU) | Usage-based, không monthly minimum | Fixed tier ($7/$25/...) hoặc usage-based |
| UX / Dashboard | Tốt — visual graph service dependencies | Đơn giản hơn — CLI-first | Tốt — quen thuộc, dễ dùng |
| CLI experience | Tốt (railway CLI) |
Rất tốt (flyctl), nhiều subcommand |
Có CLI nhưng ít dùng hơn |
| Multi-region | Không native (1 region / service) | Có — anycast, scale per region | Không native |
| GPU support | Không | Có (A10, A100) — hạn chế region | Có (A100 40GB) — từ 2024 |
| Persistent volume | Có (per service) | Có (per region) | Có (per service) |
| Managed database | Postgres, MySQL, MongoDB, Redis (1-click) | Fly Postgres (self-managed trên Fly), Upstash Redis | Postgres, Redis managed |
| Free tier | $5 credit một lần (trial) | 3 VMs 256MB + 3GB volume | Free tier (sleep sau idle) |
Khi nào chọn cái nào
- Railway: prototype nhanh cần API + DB trong cùng project, team không muốn config nhiều, pricing usage-based ổn định
- Fly.io: cần multi-region hoặc edge inference, dùng GPU, quen CLI workflow, muốn kiểm soát networking chi tiết
- Render: muốn dashboard đơn giản, Postgres managed chắc chắn, hoặc cần GPU A100 ngay
Common pitfalls
Railway
- Free trial credit hết tháng → service tắt đột ngột. Đặt spending limit rõ ràng trong billing settings. Không nên dùng trial cho demo người dùng thực.
- Region change gây downtime nhỏ. Khi thay đổi region của service, Railway migrate service sang region mới — có downtime ngắn. Lên kế hoạch ngoài giờ cao điểm.
- Secret set nhưng service không nhận. Sau khi thêm env var hoặc secret, cần trigger redeploy thủ công nếu auto-deploy không kích hoạt. Railway không tự restart service running.
-
Nixpacks build thành công nhưng startup lỗi.
Nixpacks đoán đúng Python version nhưng có thể bỏ sót system library (ví dụ
libgompcho PyTorch). Khi gặp lỗi runtime, chuyển sang Dockerfile cho kiểm soát tốt hơn.
Fly.io
-
Auto-stop machines → cold start bất ngờ trong production.
Mặc định
min_machines_running = 0. Đặtmin_machines_running = 1cho production để luôn có ít nhất 1 machine warm. - Volume chỉ accessible trong 1 region. Nếu scale sang region mới, machine ở region đó không thể đọc volume của region khác. Cần tạo volume riêng cho mỗi region và cơ chế sync data nếu cần.
-
Health check timeout khi load model nặng.
App load model 2GB mất 30-60s. Nếu
grace_periodquá ngắn, Fly đánh dấu machine unhealthy và kill trước khi app sẵn sàng. Tănggrace_periodhoặc lazy-load model sau startup. -
Secret set mà không deploy lại → app không nhận giá trị mới.
fly secrets setmặc định trigger restart. Nhưng nếu dùng--stage, cầnfly deploysau để apply. - GPU availability không phải lúc nào cũng có. GPU machines có quota giới hạn. Nếu deploy GPU app lần đầu, mở support ticket để request quota trước.
Tóm tắt
✅ Railway: PaaS đơn giản, UX tốt, DB tích hợp 1-click, phù hợp prototype → small production
✅ railway.json cấu hình builder (Dockerfile / Nixpacks), start command, healthcheck
✅ Railway CLI: railway up deploy, railway run chạy script với production env
✅ Fly.io: edge compute, multi-region, Firecracker microVM, CLI-first
✅ fly.toml: auto_stop_machines, min_machines_running, [[vm]] resources
✅ fly secrets set cho credentials, không đặt trong fly.toml
✅ Volume trên Fly gắn region — mỗi region cần volume riêng
✅ Production: đặt min_machines_running = 1 và grace_period đủ cho model load
Bài tiếp theo
Bài 38: Deploy lên AWS / GCP (overview) — EC2, App Engine, Cloud Run, ECS Fargate: so sánh khi nào rời PaaS sang cloud provider thực sự.
Tài liệu tham khảo
- Railway — Config as Code (railway.json)
- Railway — Nixpacks build system
- Railway CLI reference
- Fly.io — Launch your app
- Fly.io — fly.toml configuration reference
- Fly.io — Machines overview (Firecracker microVM)
- Fly.io — Volumes and persistent storage
- Fly.io — GPU support
- Firecracker — GitHub repository (Amazon)
