Deployment
Vercel, Docker, EAS Build, and CI/CD pipelines
Vezta has three deployment targets, each with its own CI/CD pipeline triggered by pushing to main.
Frontend (Vercel)
The frontend auto-deploys to Vercel on every push to main. No manual steps required.
| Setting | Value |
|---|---|
| Platform | Vercel |
| Trigger | Push to main |
| Build command | pnpm build (Turbopack) |
| Production URL | https://vezta.io |
Never deploy the frontend using the Vercel CLI manually. All deployments go through the Git-based auto-deploy flow. Production environment variables are managed through the Vercel dashboard.
Production environment overrides (.env.production):
NEXT_PUBLIC_API_URL=https://backend.vezta.io/api/v1
NEXT_PUBLIC_WS_URL=wss://backend.vezta.ioBackend (Docker on Digital Ocean)
The backend runs in a Docker container on a Digital Ocean VM with a self-hosted GitHub Actions runner.
| Setting | Value |
|---|---|
| VM | Digital Ocean droplet (206.189.151.6) -- Ubuntu 24.04, 8 GB RAM, 4 vCPU |
| App path | /root/apps/vezta-be |
| Domain | https://backend.vezta.io |
| Reverse proxy | Nginx on host, SSL via Certbot/Let's Encrypt |
| Port mapping | Host 4001 to container 3001 |
| Database | Postgres 17 container (vezta-postgres) on the same VM |
| Redis | Separate vezta-redis container on internal Docker network |
CI/CD Flow
Push to main triggers .github/workflows/deploy.yml on the self-hosted runner:
- Checks out code and rsyncs to
/root/apps/vezta-be(preserves.env) - Runs
docker compose down && docker compose up -d --build - Runs
prisma migrate deployinside the container - Cleans up old Docker images (
docker image prune -f)
The self-hosted runner is installed at /root/actions-runner-vezta-be/ on the VM. No GitHub Secrets are needed for deployment since the runner runs directly on the VM.
Docker Setup
Multi-stage Dockerfile using node:20-alpine with pnpm. Runs prisma generate at build time. Production entrypoint: node dist/src/main.
Container networking: vezta-api and vezta-redis are defined in docker-compose.yml on a custom vezta-network bridge. vezta-postgres runs as a separate container on the same network. The API binds to 127.0.0.1:4001 on host (localhost only -- Nginx proxies external traffic).
Manual Deploy
For hotfixes that cannot wait for CI:
# Copy updated files to server
scp src/some-file.ts root@206.189.151.6:/root/apps/vezta-be/src/some-file.ts
# Rebuild and restart
ssh root@206.189.151.6 'cd /root/apps/vezta-be && docker compose down && docker compose build --no-cache api && docker compose up -d'Always verify the VM's .env file after any changes that depend on environment variables. The .env is at /root/apps/vezta-be/.env on the VM. Key differences from local: DATABASE_URL points to vezta-postgres container, REDIS_URL points to vezta-redis container, NODE_ENV=production, FRONTEND_URL=https://vezta.io.
Useful Server Commands
# SSH into the VM
ssh root@206.189.151.6
# View logs
docker logs vezta-api --tail 50
docker logs vezta-api -f # Follow
# Check container status
docker ps --filter name=vezta
# Rebuild without cache
docker compose build --no-cache api && docker compose up -d
# Renew SSL certificate
certbot renewMobile (EAS Build)
The mobile app is built with EAS Build (Expo Application Services) via GitHub Actions on push to main.
| Setting | Value |
|---|---|
| CI Workflow | .github/workflows/build.yml |
| Build tool | expo/expo-github-action@v8 |
| Required secret | EXPO_TOKEN |
Build Profiles
EAS build profiles are defined in eas.json:
| Profile | API Target | Distribution |
|---|---|---|
development | localhost:3001 | Dev client (simulator/emulator) |
preview | backend.vezta.io | Internal distribution (TestFlight / APK) |
production | backend.vezta.io | App Store / Play Store |
CI Flow
Push to main triggers builds for both iOS (simulator) and Android (APK). Production App Store and Play Store submissions are handled separately through EAS Submit.
CI/CD Summary
| Workflow | Trigger | What It Does |
|---|---|---|
test.yml | PR to main | Runs tests for all subprojects |
deploy.yml (backend) | Push to main | Docker build + deploy on VM |
| Vercel (frontend) | Push to main | Auto-deploy to Vercel |
build.yml (mobile) | Push to main | EAS Build for iOS + Android |
The shared VM (8 GB RAM) also hosts other applications. The backend is memory-optimized: price-sync only writes snapshots when prices change, and the heavy updatePriceChanges() query runs every 5 minutes rather than every price-sync cycle.