WELIFE Docs Swagger Admin Web

Deploy WELIFE API trên Ubuntu

Snapshot máy chủ hiện tại (2026-07-31)

Mục Giá trị
Host / IP 180.93.146.58 (Megahost)
OS Ubuntu 22.04.5 LTS · kernel 5.15.0-156-generic x86_64
SSH ssh root@180.93.146.58 (nên chuyển sang user welifeadmin + tắt root — § harden)
Domain API https://api.minhtien.cloud · WS cùng host
Admin https://admin.minhtien.cloud
Docs https://docs.minhtien.cloud
Apex https://minhtien.cloud

Phân vai deploy (quan trọng):

Thành phần Chạy ở đâu Ghi chú
Nest API + Postgres/Redis/MinIO VPS (Docker / PM2) Đây là phần deploy máy chủ
Dashboard admin VPS (static Nginx) deploy/deploy-dashboard.sh
Consumer / Driver / Partner (Expo) Máy build / EAS / store App không host trên VPS; chỉ gọi EXPO_PUBLIC_API_URL

FE mới (2026-07) — cần native build

Trên mobile/ đã có camera · mic · media · voice search (expo-speech-recognition).

EXPO_PUBLIC_API_URL=https://api.minhtien.cloud/api/v1
EXPO_PUBLIC_WS_URL=https://api.minhtien.cloud
EXPO_PUBLIC_ENV=production

Kiểm tra nhanh trên VPS (sau SSH)

# API sống (public)
curl -sS https://api.minhtien.cloud/api/v1/health

# /health/deps public → 403 trên production (đúng thiết kế).
# Detail deps: JWT ADMIN + HEALTH_DETAIL_ENABLED=true
#   POST /api/v1/auth/... lấy accessToken role ADMIN, rồi:
#   curl -sS -H "Authorization: Bearer $TOKEN" \
#     https://api.minhtien.cloud/api/v1/health/admin/deps

# Container kỳ vọng: api · postgres · redis · minio · mailpit
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' | head -40

bash /root/health-check.sh

Deploy / cập nhật API từ Windows

/opt/welife không phải git clone (repo private). Cập nhật bằng sync từ máy dev (giữ nguyên api/.env + .env trên VPS).

# Option A — sync api + rebuild compose (khuyến nghị)
# Git Bash / WSL từ root repo:
bash deploy/sync-api-vps.sh

# Dashboard admin (static Vite → admin.minhtien.cloud)
bash deploy/sync-dashboard-vps.sh

# Marketing site (Next static → minhtien.cloud + www)
bash deploy/sync-web-vps.sh

# Tài liệu markdown → static HTML (docs.minhtien.cloud)
bash deploy/sync-docs-vps.sh

# Option B — one-shot bootstrap cũ (cần `.vps-pass` gitignored)
node --use-system-ca deploy/push-and-run.mjs

# Option C — SSH tay (sau khi đã sync code)
ssh root@180.93.146.58
cd /opt/welife
docker compose -f docker-compose.yml -f deploy/docker-compose.resources.yml --profile full up -d --build api minio
docker compose -f docker-compose.yml -f deploy/docker-compose.resources.yml --profile full run --rm minio-init
docker compose -f docker-compose.yml -f deploy/docker-compose.resources.yml --profile full exec -T api npx prisma migrate deploy
# OSRM (nếu đã bootstrap data)
docker compose -f docker-compose.yml -f deploy/docker-compose.resources.yml --profile osrm up -d --force-recreate osrm
bash /root/health-check.sh

Luôn kèm -f deploy/docker-compose.resources.yml trên VPS (giới hạn RAM/CPU). deploy/sync-api-vps.sh đã gắn overlay này.

VPS api/.env bắt buộc (sync tự set):

Key Giá trị prod
POSTGIS_SCHEMA public (PostGIS extension trên Ubuntu/aaPanel)
SWAGGER_ENABLED true (OWNER 2026-08-14 — /docs public; set WELIFE_SWAGGER_ENABLED=false khi sync để tắt)
HEALTH_DETAIL_ENABLED false (detail chỉ JWT ADMIN khi bật)

sync-api-vps.sh cũng: strip BOM migration · wait /health · migrate deploy · seed transit_stops nếu trống · smoke transit nearby · Swagger theo WELIFE_SWAGGER_ENABLED (default true từ 2026-08-14) · health-detail/wallet-credit off.

Không git pull trên VPS trừ khi đã cấu hình deploy key riêng. Không commit .env / secret JWT / SMS / payment lên git.

Trạng thái vận hành (đã xử lý 2026-07-31)

Lưu ý cũ Cách xử lý
JWT rotate (≥32 ký tự) Bắt buộc secure-boot prod; user login lại một lần. Backup: api/.env.bak-pre-jwt-rotate
Không git pull Dùng deploy/sync-api-vps.sh
MinIO tắt welife-minio up · bucket welife · API S3_ENDPOINT=http://minio:9000
/health/deps 403 Public cấm; dùng /health/admin/deps + JWT ADMIN (HEALTH_DETAIL_ENABLED=true)
SMTP trong container SMTP_HOST=mailpit (alias mạng welife_default)
Redis host port REDIS_PORT=6380 (tránh conflict host redis :6379)
Nearby PostGIS schema welife VPS: POSTGIS_SCHEMA=public (sync-api tự set) · local Docker có thể welife

Yêu cầu

Tài nguyên máy chủ (Docker)

Mức vCPU RAM Disk Ghi chú
Tối thiểu MVP 2 4 GiB 40 GiB SSD api + Postgres + Redis + MinIO
Prod khuyến nghị 4 8 GiB 60 GiB SSD + swap 4G · log rotate
Prod + OSRM VN 4–8 12–16 GiB 80+ GiB OSRM Vietnam ~2.5 GiB RSS · data ~4 GiB

Máy mẫu 180.93.146.58: 9 vCPU · 15 GiB · 94 GiB — đủ prod + OSRM.

# Cài Docker (nếu thiếu) + swap 4G + daemon log-rotate + sysctl
# Copy script lên VPS rồi:
bash /opt/welife/deploy/vps-docker-resources.sh

# Áp giới hạn RAM/CPU từng service
cd /opt/welife
docker compose -f docker-compose.yml -f deploy/docker-compose.resources.yml --profile full up -d
docker stats --no-stream

Không mở 5432 / 6379 / 9000 ra public. Swap chỉ dự phòng OOM — vm.swappiness=10.

VPS mới — harden + panel (WP-DEPLOY-01)

Máy mẫu: Ubuntu 24.04 · root console (noVNC Megahost). Script repo: deploy/vps-harden-ubuntu24.sh

A. Trên console VPS (root) — bước an toàn tối thiểu

# 1) Cập nhật + công cụ
apt update && apt upgrade -y
apt install -y curl git ufw fail2ban unattended-upgrades ca-certificates

# 2) User admin (đổi tên nếu muốn)
adduser welifeadmin
usermod -aG sudo welifeadmin
mkdir -p /home/welifeadmin/.ssh && chmod 700 /home/welifeadmin/.ssh

# 3) DÁN public key máy bạn vào (bắt buộc trước khi tắt login root/password)
nano /home/welifeadmin/.ssh/authorized_keys
chmod 600 /home/welifeadmin/.ssh/authorized_keys
chown -R welifeadmin:welifeadmin /home/welifeadmin/.ssh

# 4) Firewall
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
ufw status

# 5) fail2ban
systemctl enable --now fail2ban

Từ máy Windows (PowerShell), thử SSH:

ssh welifeadmin@180.93.146.58

Khi login bằng key OK:

# Trên VPS — siết SSH
cat >/etc/ssh/sshd_config.d/99-welife.conf <<'EOF'
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers welifeadmin
MaxAuthTries 3
EOF
systemctl reload ssh

B. Chạy script đầy đủ (Docker + harden)

Copy deploy/vps-harden-ubuntu24.sh lên VPS rồi:

export WELIFE_ADMIN_USER=welifeadmin
export WELIFE_SSH_PUBKEY='ssh-ed25519 AAAA... your-key'
# Panel (chọn 1):
#   none     — chỉ harden (khuyến nghị lần đầu)
#   coolify  — quản lý Docker/app (khớp WELIFE compose)
#   aapanel  — panel kiểu BT (phổ biến VN)
export WELIFE_PANEL=none
bash vps-harden-ubuntu24.sh
Panel Khi nào dùng Port UI
Coolify Deploy Docker compose / WELIFE stack :8000
aaPanel Nginx/PHP quen BT Panel :7800 / :888
none Chỉ Docker CLI + PM2 theo doc dưới —

Khuyến nghị WELIFE: harden xong → WELIFE_PANEL=coolify (hoặc none + Docker tay).

C. Cấm expose DB

Postgres / Redis / MinIO chỉ bind 127.0.0.1 (đã trong compose local). UFW không mở 5432 6379 9000.

D. Secrets production

# trên máy dev
node scripts/gen-secrets.mjs
# dán vào api/.env trên VPS — xem docs/SECURITY.md + 07-ENVIRONMENT.md

Domain mẫu — minhtien.cloud (Megahost)

DNS A → 180.93.146.58 (NS DotVN: ns1.dotvndns.vn):

Host Vai trò Trạng thái
api.minhtien.cloud Nest API + Socket.IO → 127.0.0.1:3000 HTTPS OK
ws.minhtien.cloud WS (cùng API) HTTPS OK
admin.minhtien.cloud Dashboard Vite HTTPS OK
www / docs Placeholder HTTPS OK
@ (minhtien.cloud) Apex HTTPS OK (Let's Encrypt)

Consumer Expo production:

EXPO_PUBLIC_API_URL=https://api.minhtien.cloud/api/v1
EXPO_PUBLIC_WS_URL=https://api.minhtien.cloud
EXPO_PUBLIC_ENV=production

Hoàn thiện env prod (pattern APP_DESIGN_BUILD health/deploy):

bash /root/finalize-prod-env.sh   # CORS · TRUST_PROXY · recreate API · landing
bash /root/issue-apex-ssl.sh      # cert @ sau khi A đúng
bash /root/health-check.sh

Scripts: finalize-prod-env.sh · issue-apex-ssl.sh · health-check.sh

One-shot (đã có aaPanel): deploy/one-shot-minhtien-cloud.sh

Từ máy Windows (sau khi tạo file gitignored .vps-pass = 1 dòng mật khẩu root):

node --use-system-ca deploy/push-and-run.mjs

Hoặc trên VPS (root):

bash one-shot-minhtien-cloud.sh

Dev infra (Postgres PostGIS + Redis + MinIO)

Ports mặc định trên máy Windows có thể lệch (5434/6380) — xem 07-ENVIRONMENT.md.

cd /opt/welife   # hoặc D:\welife
cp .env.example .env
cp api/.env.example api/.env
npm run infra:up
npm run env:check

Chạy API local (ngoài Docker)

cd api
cp .env.example .env
npm install
npm run start:dev
# Swagger: http://localhost:3000/docs

Full stack Docker (API + Nginx)

docker compose --profile full up -d --build

PM2 (không dùng Docker cho Node)

sudo apt update && sudo apt install -y nodejs npm nginx
cd /opt/welife/api
npm ci && npm run build
npx pm2 start dist/main.js --name welife-api -i max
npx pm2 save

Nginx reverse proxy trỏ proxy_pass http://127.0.0.1:3000 theo deploy/nginx.conf.

Checklist production

Mail (WP-AUTH-05)

# Mailpit (OTP inbox nội bộ — đã dùng trên VPS)
docker ps | grep mailpit

# docker-mailserver (optional — /opt/welife-mail; port 25 thường bị aaPanel chiếm)
bash /root/mailserver-up.sh
# DNS: deploy/MAIL-DNS.md

Auth FE: login email OTP (không SĐT) trên CON / PAR / DRV / ADM.