Self-Hosting Overview
Venelx is a split system: the dashboard always runs on Vercel, while you choose where the API (control plane) and the build workers run. This page helps you pick a layout; the sub-pages cover each piece in depth.
The tiers
| Tier | Host | Package | Runs |
|---|---|---|---|
| Frontend | Vercel | venelx-frontend | Next.js dashboard — calls the API only |
| Control plane | Cloud Run / EC2 / GCE VM, or a Mac behind a tunnel | venelx-backend | Express, Prisma, queue enqueue, auth, B2 presign, log SSE |
| Build workers | One or more Mac / Linux / Windows machines | venelx-worker | BullMQ consumer, pipeline, Xcode / EAS / Android builds |
| Mobile app | App stores | venelx-app | Expo companion app — calls the API only |
| Queue | Upstash (or any managed Redis) | — | BullMQ; API enqueues, workers consume |
| Database | MongoDB Atlas | — | Projects, jobs, users, billing |
| Artifacts | Backblaze B2 | — | Metadata + presign on the API; workers upload bytes |
Users ──► Vercel (dashboard)
│ HTTPS
▼
API (control plane) ──► MongoDB Atlas · B2
│ enqueue
▼
Redis (Upstash)
│ consume (outbound only)
┌───────┴────────┐
▼ ▼
Worker: mac-ios Worker: linux-android
Two supported layouts
| A — Mac mini monorepo | B — Cloud control plane + workers | |
|---|---|---|
| API | Mac (:4000, behind Cloudflare Tunnel) | Cloud Run / GCE / EC2 |
| Worker | Same Mac, second process | One or more Mac / Linux machines |
| Redis | Upstash or local redis://127.0.0.1 | Upstash (reachable from API + workers) |
| Frontend | Vercel | Vercel |
| Good for | Single-machine setups, home lab | Production fleets, scaling workers |
Use Upstash in both layouts so migrating A → B is only a matter of moving the API
and changing API_URL on workers — not re-topologizing Redis.
Production rules
These are enforced at startup via VENELX_DEPLOY_ROLE (api or worker) in both
packages:
| Rule | Meaning |
|---|---|
| Enqueue only on API | RUN_QUEUE_WORKER=false on the backend in production |
| Consume on workers | RUN_QUEUE_WORKER=true and WORKER_AGENT_ONLY=true on every build host |
| Separate processes | API and worker may share one Mac only as two processes — never one server |
| B2 keys on API only | Workers upload through presigned URLs (B2_UPLOAD_VIA_API=true) |
Invalid in production: RUN_QUEUE_WORKER=true on the API, WORKER_AGENT_ONLY=true
on the main backend, or builds running inside the Express process. The API health
endpoint reports queueConsumerOnApi — it must be false.
Deployment checklist (summary)
- Upstash
REDIS_URLon the API and every worker (identical string). - Deploy the API with
RUN_QUEUE_WORKER=false; verifyqueueConsumerOnApi: falseat/api/health. - Deploy the frontend on Vercel with
NEXT_PUBLIC_API_URL/NEXT_PUBLIC_WS_URL. - Install worker(s) on each build machine and confirm they show online in the dashboard.
- End-to-end: enqueue a build → watch SSE logs → download a
b2:artifact.
In this section
Why Mac workers for iOS
EAS local iOS builds (eas build --local) require macOS + Xcode — cloud Linux VMs
cannot produce an .ipa. Android builds run fine on Linux/WSL2 workers, so a common
fleet is one Mac for ios plus one Linux box for android-preview,android-production.