name: quantlab-deployment description: Gunakan skill ini untuk semua operasi deployment QuantLab — backend ke AWS EC2 (systemd), frontend ke Cloudflare Pages, setup SSL/HTTPS, Supabase database, GitHub Actions CI/CD, dan monitoring. Mencakup troubleshooting deployment failures.
QuantLab Deployment Skill
Skill ini memandu agent dalam semua aspek deployment QuantLab ke production dan pengelolaan infrastruktur.
🎯 Kapan Skill Ini Diaktifkan
Aktifkan OTOMATIS jika:
- User minta deploy backend atau frontend
- Ada masalah dengan CI/CD (GitHub Actions)
- Setup SSL/HTTPS untuk backend API
- Configure Supabase database
- Setup atau troubleshoot systemd service
- Konfigurasi environment variables di production
- Monitoring atau health check production server
- Troubleshoot "connection refused" atau "port not accessible"
🏗️ Production Infrastructure
┌─────────────────────────────────────────────────────────────┐
│ FRONTEND: Cloudflare Pages │
│ URL: https://quantlab.bamsbung.com │
│ Deploy: git push → GitHub Actions → wrangler pages deploy │
│ Build: npm run build → dist/ → CF Pages │
└─────────────────┬───────────────────────────────────────────┘
│ HTTPS API calls
┌─────────────────▼───────────────────────────────────────────┐
│ BACKEND: AWS EC2 │
│ IP: 54.251.201.70 │
│ Port: 8080 (HTTP) → TODO: 443 (HTTPS via nginx) │
│ Server: Ubuntu 24.04, 2 vCPU, 914MB RAM │
│ Binary: /opt/quantlab/quantlab-api (4.8MB) │
│ Service: systemd quantlab-api.service │
│ Runtime: 9.5 MB RSS (sangat efisien) │
└─────────────────────────────────────────────────────────────┘
🚀 Deploy Backend ke EC2
Cara 1: GitHub Actions (DIREKOMENDASIKAN untuk production)
Prerequisites:
- GitHub Secret sudah dikonfigurasi (lihat bagian GitHub Secrets)
- Push ke
mainbranch
# .github/workflows/backend.yml akan otomatis:
# 1. cargo test → cargo clippy → cargo audit
# 2. cargo build --release → strip binary
# 3. SCP binary ke EC2
# 4. systemctl restart quantlab-api
# 5. curl /v1/health → verify
Cara 2: Manual Deploy via SSH (untuk hotfix)
# 1. Build lokal (jika environment Linux/WSL)
cd .Production/backend/rust-api
cargo build --release
strip target/release/quantlab-api
# 2. SCP ke server
scp -i ~/.ssh/ec2.pem target/release/quantlab-api ubuntu@54.251.201.70:/tmp/
# 3. SSH ke server
ssh -i ~/.ssh/ec2.pem ubuntu@54.251.201.70
# 4. Di server:
sudo systemctl stop quantlab-api
sudo cp /tmp/quantlab-api /opt/quantlab/quantlab-api
sudo chmod +x /opt/quantlab/quantlab-api
sudo systemctl start quantlab-api
sudo systemctl status quantlab-api
# 5. Verify
curl http://localhost:8080/v1/health
Cara 3: Build On-Server (untuk binary size compatibility)
# SSH ke server
ssh -i ~/.ssh/ec2.pem ubuntu@54.251.201.70
# Setup swap jika belum ada (diperlukan untuk cargo build --release)
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# Clone/pull kode terbaru
cd /opt/quantlab/src
git pull origin main
# Build (⚠️ akan butuh ~5-10 menit dengan 2GB swap)
cargo build --release
# Deploy
sudo systemctl stop quantlab-api
sudo cp target/release/quantlab-api /opt/quantlab/quantlab-api
sudo systemctl start quantlab-api
🌐 Deploy Frontend ke Cloudflare Pages
Cara 1: GitHub Actions (DIREKOMENDASIKAN)
# Push ke main → CI otomatis deploy
git push origin main
Cara 2: Manual via Wrangler CLI
cd .Production/frontend
# Build
npm run build
# Deploy
npx wrangler pages deploy dist \
--project-name=quantlab \
--commit-message="Manual deploy $(date +%Y-%m-%d)"
Setup Cloudflare Pages Environment Variables
Dashboard: https://dash.cloudflare.com
→ Pages → quantlab → Settings → Environment Variables
→ Add untuk Production DAN Preview:
PUBLIC_SUPABASE_URL = https://supabase.bamsbung.com
PUBLIC_SUPABASE_ANON_KEY = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.[200+ chars]
PUBLIC_API_BASE = https://[ec2-ip]/v1
⚠️ PENTING: Set untuk Production DAN Preview environment! ⚠️ Setelah set env vars, klik Save lalu trigger redeploy!
🔐 GitHub Actions Secrets Setup
Backend Repository (quantbackend)
Settings → Secrets and variables → Actions → New repository secret
EC2_HOST = 54.251.201.70
EC2_USER = ubuntu
EC2_SSH_KEY = [isi konten file .pem LENGKAP termasuk header]
BINANCE_API_KEY = [Binance API key]
BINANCE_API_SECRET = [Binance API secret]
Frontend Repository (quantfrontend)
Settings → Secrets and variables → Actions → New repository secret
CLOUDFLARE_API_TOKEN = [Token CF dengan Pages:Edit permission]
CLOUDFLARE_ACCOUNT_ID = [Account ID dari CF dashboard]
Cara Buat CF API Token yang Benar
Cloudflare Dashboard → My Profile → API Tokens → Create Token
→ Use template: "Edit Cloudflare Pages"
→ Permissions: Zone: Pages: Edit
→ Account: [your account]
→ Save → Copy token
# Test token:
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer [TOKEN]" \
-H "Content-Type: application/json"
# Expected: {"result":{"status":"active"}}
🔒 Setup SSL/HTTPS (P0 — Belum Done!)
Backend saat ini hanya HTTP (port 8080). Frontend (HTTPS) tidak bisa call HTTP backend di production.
Option A: nginx + Let's Encrypt (DIREKOMENDASIKAN)
# SSH ke EC2
ssh -i ~/.ssh/ec2.pem ubuntu@54.251.201.70
# Install nginx
sudo apt-get update
sudo apt-get install -y nginx certbot python3-certbot-nginx
# Buat domain dulu: api.quantlab.bamsbung.com → 54.251.201.70
# (Set A record di DNS: api.quantlab.bamsbung.com → 54.251.201.70)
# Konfigurasi nginx
sudo nano /etc/nginx/sites-available/quantlab-api
# Isi:
server {
listen 80;
server_name api.quantlab.bamsbung.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# Aktifkan site
sudo ln -s /etc/nginx/sites-available/quantlab-api /etc/nginx/sites-enabled/
sudo nginx -t # test config
sudo systemctl restart nginx
# Get SSL cert
sudo certbot --nginx -d api.quantlab.bamsbung.com
# Verify
curl https://api.quantlab.bamsbung.com/v1/health
Option B: Cloudflare Tunnel (Zero Config SSL)
# Install cloudflared
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb
sudo dpkg -i cloudflared.deb
# Login dan create tunnel
cloudflared tunnel login
cloudflared tunnel create quantlab-api
# Config file
nano ~/.cloudflared/config.yml
# isi:
tunnel: [TUNNEL_ID]
credentials-file: /home/ubuntu/.cloudflared/[TUNNEL_ID].json
ingress:
- hostname: api.quantlab.bamsbung.com
service: http://localhost:8080
- service: http_status:404
# Install sebagai service
sudo cloudflared service install
sudo systemctl start cloudflared
🗄️ Setup Supabase Database
- Deploy Supabase via Docker di EC2
- Gunakan port 54322 untuk Postgres Database agar bypass Supavisor
- Setting Caddy reverse proxy untuk API/Auth ke
supabase.bamsbung.com
2. Get Connection String
Project Settings → Database → Connection string → URI
Format: postgresql://postgres:[password]@54.251.201.70:54322/postgres
3. Run Migrations di Server
# SSH ke EC2
ssh -i ~/.ssh/ec2.pem ubuntu@54.251.201.70
# Set DATABASE_URL di .env
echo 'DATABASE_URL=postgresql://postgres:[pass]@localhost:54322/postgres' \
>> /opt/quantlab/.env
# Restart service untuk load env baru
sudo systemctl restart quantlab-api
# Verify DB connection
curl http://localhost:8080/v1/health
# Seharusnya: {"supabase": "ok"}
4. Run SQL Migrations
# Di lokal (dari .Production/backend/rust-api)
DATABASE_URL=postgresql://... sqlx migrate run
# Atau copy migration files ke server dan run di sana
🔧 systemd Service Management
Cek Status
# Status service
sudo systemctl status quantlab-api
# Lihat logs real-time
sudo journalctl -u quantlab-api -f
# Lihat 100 baris log terakhir
sudo journalctl -u quantlab-api -n 100
# Lihat logs sejak tadi
sudo journalctl -u quantlab-api --since "1 hour ago"
Service File (jika perlu recreate)
# /etc/systemd/system/quantlab-api.service
[Unit]
Description=QuantLab API Server
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=5
User=ubuntu
WorkingDirectory=/opt/quantlab
EnvironmentFile=/opt/quantlab/.env
ExecStart=/opt/quantlab/quantlab-api
# Resource limits (914 MB RAM server)
LimitNOFILE=65536
MemoryMax=512M
[Install]
WantedBy=multi-user.target
# Reload jika edit service file
sudo systemctl daemon-reload
sudo systemctl enable quantlab-api
sudo systemctl start quantlab-api
🔥 Troubleshooting Guide
Problem 1: Port 8080 Not Accessible
Symptom: curl -v http://54.251.201.70:8080/v1/health → connection timeout
Fix:
# 1. Check EC2 firewall (AWS Console)
# AWS Console → EC2 → Instance → Networking → Firewall
# Add rule: Custom TCP, port 8080, Anywhere (0.0.0.0/0)
# 2. Check Ubuntu UFW
sudo ufw allow 8080/tcp
sudo ufw reload
sudo ufw status
# 3. Check service running
sudo systemctl status quantlab-api
# 4. Check listening port
sudo ss -tlnp | grep 8080
Problem 2: Service Crash Loop
Symptom: systemctl status shows "activating" → "failed" repeatedly
Debug:
sudo journalctl -u quantlab-api -n 50
# Common causes:
# 1. SECRET_KEY too short (min 32 chars)
echo -n "$SECRET_KEY" | wc -c # harus >= 32
# 2. ALLOWED_ORIGINS format salah (dotenvy issue)
# SALAH: ALLOWED_ORIGINS=["https://example.com"]
# BENAR: ALLOWED_ORIGINS='["https://example.com"]'
# 3. CRLF dari Windows
sed -i 's/\r//' /opt/quantlab/.env
# 4. .env file permission
chmod 600 /opt/quantlab/.env
Problem 3: GitHub Actions CI Gagal
Backend workflow gagal:
# Check: apakah working-directory benar?
# defaults.run.working-directory harus menunjuk ke folder Cargo.toml
# Check: apakah EC2_SSH_KEY format benar?
# Harus include header: -----BEGIN RSA PRIVATE KEY-----
# Harus newline di dalam konten key
# Debug SSH connection:
ssh -i [key.pem] ubuntu@54.251.201.70 "echo Connected"
Frontend workflow gagal (Wrangler):
# Check CLOUDFLARE_API_TOKEN valid:
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
# Check project name:
wrangler pages project list
# Common fix: project name di wrangler.jsonc harus match!
Problem 4: CORS Error di Frontend
Symptom: Browser console: Access-Control-Allow-Origin missing
Check backend ALLOWED_ORIGINS:
# SSH ke server
grep ALLOWED_ORIGINS /opt/quantlab/.env
# Harus ada URL frontend: https://quantlab.bamsbung.com
# Jika tidak ada, tambah dan restart
sudo systemctl restart quantlab-api
Check dev mode:
// main.rs — dev mode harus Any, prod harus strict
if config.app_env == "development" {
CorsLayer::very_permissive() // Any origin
} else {
CorsLayer::new()
.allow_origin(allowed_origins) // strict whitelist
}
Problem 5: Supabase Auth Tidak Berfungsi di Production
Symptom: Login berhasil tapi langsung redirect ke /login
Check:
// supabase.ts — isValidAnonKey harus > 100 chars
// Placeholder "your-anon-key-here" tidak diterima!
// Verify di CF Pages env vars:
// PUBLIC_SUPABASE_ANON_KEY harus 200+ chars real JWT
📊 Health Check & Monitoring
Quick Health Check Script
#!/bin/bash
# Save sebagai: scripts/health_check.sh
API_BASE="http://54.251.201.70:8080"
echo "=== QuantLab Health Check ==="
echo "Timestamp: $(date)"
echo ""
# Check endpoint
check_endpoint() {
local name=$1
local url=$2
local response=$(curl -s -w "\n%{http_code}" "$url" 2>/dev/null)
local http_code=$(echo "$response" | tail -1)
local body=$(echo "$response" | head -1)
if [ "$http_code" = "200" ]; then
echo "✅ $name → $http_code"
else
echo "❌ $name → $http_code"
echo " Body: $body"
fi
}
check_endpoint "Health" "$API_BASE/v1/health"
check_endpoint "Assets" "$API_BASE/v1/assets"
check_endpoint "Regime BTC D1" "$API_BASE/v1/regime/current/BTCUSDT/D1"
check_endpoint "Dashboard Summary" "$API_BASE/v1/dashboard/summary"
echo ""
echo "=== System Resources ==="
echo "Memory: $(free -m | grep Mem | awk '{print $3"/"$2" MB"}')"
echo "Disk: $(df -h / | tail -1 | awk '{print $3"/"$2" ("$5" used)"}')"
echo "Process: $(ps aux | grep quantlab-api | grep -v grep | awk '{print "CPU:"$3"% MEM:"$4"%"}')"
Monitoring via UptimeRobot (Setup Minimal)
1. uptimerobot.com → Create Monitor
2. Type: HTTP(S)
3. URL: http://54.251.201.70:8080/v1/health
4. Interval: 5 minutes
5. Alert via: Email / Telegram
📋 Production Deployment Checklist
PRE-DEPLOY:
[ ] cargo test → semua PASS
[ ] cargo clippy -- -D warnings → 0 warnings
[ ] npm run build → 0 errors
[ ] playwright test → semua PASS
BACKEND DEPLOY:
[ ] GitHub Secrets dikonfigurasi (EC2_HOST, USER, SSH_KEY)
[ ] push ke main → GitHub Actions green
[ ] curl http://54.251.201.70:8080/v1/health → 200 OK
[ ] journalctl tidak ada errors
FRONTEND DEPLOY:
[ ] CF Pages env vars dikonfigurasi (SUPABASE_*, PUBLIC_API_BASE)
[ ] GitHub Secrets dikonfigurasi (CF_API_TOKEN, CF_ACCOUNT_ID)
[ ] push ke main → build + deploy green
[ ] Verify: https://quantlab.bamsbung.com → load OK
[ ] Login flow bekerja
POST-DEPLOY:
[ ] E2E test vs production URL
[ ] Check WebSocket (live indicator hijau di RegimeExplorer)
[ ] Monitor logs 30 menit pertama (journalctl -f)
[ ] Setup UptimeRobot monitoring
🔑 Environment Variables Reference
Backend EC2 (.env)
APP_ENV=production
AUTH_ENABLED=true
PORT=8080
SECRET_KEY=[min 32 chars! gunakan: openssl rand -hex 32]
SUPABASE_URL=https://supabase.bamsbung.com
SUPABASE_KEY=eyJ... # anon key
SUPABASE_SERVICE_KEY=eyJ... # service role key
SUPABASE_JWT_SECRET=[dari Supabase Project Settings → API → JWT Secret]
DATABASE_URL=postgresql://postgres:[pass]@localhost:54322/postgres
# PENTING: JSON arrays HARUS dalam single quotes!
ALLOWED_ORIGINS='["https://quantlab.bamsbung.com","https://quantlab.dedy774741.workers.dev","http://localhost:4321"]'
BINANCE_API_KEY=[key]
BINANCE_API_SECRET=[secret]
# Optional
WS_MAX_CONNECTIONS_FREE=1
WS_MAX_CONNECTIONS_PRO=3
WS_MAX_CONNECTIONS_ENTERPRISE=10
CACHE_TTL_MULTIPLIER=1.0
CACHE_MAX_ENTRIES=1000
Frontend (.env.local)
PUBLIC_SUPABASE_URL=https://supabase.bamsbung.com
PUBLIC_SUPABASE_ANON_KEY=eyJ... # 200+ chars, REAL token!
PUBLIC_API_BASE=http://localhost:8080 # development
# Production: https://api.quantlab.bamsbung.com