Self-hosting and Deployment
Run the current Gonvex stack locally and understand what production self-hosting requires.
Self-hosting and Deployment
Gonvex is open source and currently self-hosted first. A generally available hosted Gonvex Cloud service is not open to the public, so new projects should run the runtime locally or deploy it on infrastructure they control.
The Docker stack is the current reference deployment, not a hardened production platform. Production auth, migration controls, tenant operations, upgrades, and deployment automation are still evolving.
Run the reference stack
Requirements: Git, Docker with the Compose plugin, and make.
git clone https://github.com/Whagons-International/gonvex.git
cd gonvex
make stack
The command runs docker compose up --build --wait for Postgres, Valkey, MinIO, the
runtime, and dashboard, then creates the local object-storage bucket.
| Service | Address | Container port |
|---|---|---|
| Runtime | http://localhost:8080 | 8080 |
| Dashboard | http://localhost:3000 | 80 |
| Postgres | localhost:5432 | 5432 |
| Valkey | localhost:6380 | 6379 |
| MinIO API | http://localhost:9000 | 9000 |
| MinIO console | http://localhost:9001 | 9001 |
Check the runtime:
curl http://localhost:8080/healthz
Inspect or stop the stack with standard Compose commands:
docker compose ps
docker compose logs -f runtime
docker compose down
Do not add -v to docker compose down unless you intentionally want to delete the
local Postgres, Valkey, MinIO, and runtime volumes.
Upgrade the runtime
The npm CLI and the Go runtime are separate artifacts. Installing a newer
@gonvex/cli changes the client on your workstation, but it does not replace an
already running runtime binary or container. The reference runtime image is compiled
from the source in the Docker build context.
After updating the checkout, rebuild and recreate only the runtime service:
git pull --ff-only
docker compose build --no-cache runtime
docker compose up -d --force-recreate runtime
docker compose logs --tail=100 runtime
curl http://localhost:8080/healthz
This preserves the existing Postgres and runtime volumes. No manual database
migration is required for project environment variables; the runtime creates or
updates its control-plane tables during startup. Do not use docker compose down -v
as part of this upgrade.
Whagons Coolify deployments
The Runtime regression GitHub workflow validates pull requests and pushes to
main, but it does not call the Coolify deployment API. The Whagons development
runtime and dashboard track main at HEAD; the repository's Coolify push webhook
is their single deployment lane. Coolify starts each replacement, waits for its
/healthz check, moves traffic, and then stops the previous container. Pull requests
run the regression suite but never deploy.
Coolify supplies the resolved SOURCE_COMMIT to each running container. The runtime
prefers a valid full SHA from that value over the legacy manually maintained
GONVEX_RUNTIME_VERSION, so /healthz.version identifies the actual webhook
checkout and the production promotion gate cannot pass on stale version metadata.
Postgres and Valkey stay in the separate docker-compose.coolify.yml data-plane
service. Runtime releases therefore do not restart either durable dependency.
Source manifests live in Postgres and data files can rehydrate from object storage.
An installation may persist /var/lib/gonvex for data files, plugins, and telemetry;
the Go module cache, build cache, and compiler temporary directory live outside that
tree so a volume mounted there cannot hide compiler-owned directories from the image.
The runtime does not report healthy until every persisted project manifest has hydrated. Scheduled jobs and deterministic cron occurrences live in Postgres and use renewable row leases for crash recovery. During upgrades from the earlier Valkey-only scheduler, Valkey claim keys remain as a compatibility fence and the new runtime drains old queued jobs into Postgres. HTTP and WebSocket traffic can therefore use both rolling containers while either version safely schedules or executes work without duplicating a cron fire.
Production is a separate, manually approved promotion lane. Run Promote Gonvex
production with the full SHA that is already healthy in development and a
verified backup or restore-point reference. Select the production runtime's current
GONVEX_REQUIRE_AUTH value explicitly; the workflow verifies that choice and never
silently changes the authentication policy during an upgrade. The workflow requires successful CI,
proves that both main and production can reach the candidate by fast-forward,
and verifies the exact SHA reported by the development runtime. The protected
gonvex-production environment pauses before any production secret or deploy step
is released.
After approval, the workflow rolls the independent production runtime first and
the dashboard second. Postgres and Valkey remain in the production data-plane
service and are not restarted. Before deployment it preserves configured trusted
proxy networks, adds 127.0.0.1/32 for the supervisor-to-worker hop, and disables
push auto-deploy on both production Applications. This prevents the final
production branch update from causing a duplicate Coolify rollout. Public health
checks must report the exact runtime SHA before the workflow fast-forwards
production without force and creates the immutable gonvex-prod-<sha> release
tag. A failed rollout leaves the production branch and release tag at the last
verified deployment. A push to main never updates production directly.
The workflow reads COOLIFY_API_URL, COOLIFY_RUNTIME_APPLICATION_UUID, and
COOLIFY_DASHBOARD_APPLICATION_UUID as protected environment variables and
COOLIFY_API_TOKEN as a protected secret in the gonvex-runtime GitHub
environment. Production uses the same variable names in the protected
gonvex-production environment, pointed at the production Applications. Keep the
token in a GitHub secret rather than in a workflow file. The exact SHA pin makes
the running source auditable and avoids a moving-branch race during a rebuild.
Project-key authentication for project environment variables first shipped in
runtime v0.1.9 (source commit c49ef6a). The exact response
{"error":"dashboard sign-in is required"} from
/dev/projects/{project}/env identifies the v0.1.8-or-earlier handler, even when a
newer CLI successfully authenticates to /dev/sync. Deploy the current checkout to
also enforce the stricter rule that a runtime-wide development sync key is not a
project environment credential.
Verify the rollout from an application directory without printing its key:
npx gonvex dev --once
npx gonvex env list
For a proxied deployment, preserve Authorization, x-gonvex-key, and
x-gonvex-project-id, and forward /dev/projects/* and /dev/sync to the same
runtime. A proxy-generated dashboard-auth 401 means the request did not reach the
route-specific project environment authorization.
Connect an application
Use the runtime's browser-reachable address—not its internal Compose service name—in
your app's .env.local:
GONVEX_PROJECT_ID=my-product
GONVEX_RUNTIME_URL=http://localhost:8080
GONVEX_PROJECT_KEY=
VITE_GONVEX_PROJECT_ID=my-product
VITE_GONVEX_URL=http://localhost:8080
VITE_GONVEX_WS_URL=ws://localhost:8080/ws
Run npx gonvex dev. In an interactive terminal, the CLI can create a project on the
runtime and write the returned project ID and key to .env.local. For an existing
project, obtain its key from the dashboard when prompted.
Keep GONVEX_PROJECT_KEY server-side. Only variables prefixed with VITE_ are meant
for the browser bundle.
One-time Google auth broker setup
Individual Gonvex apps do not need Firebase or their own Google Cloud project. The operator of a Gonvex installation creates one Google OAuth client for the runtime. This is a one-time infrastructure setup, not a per-app step.
That OAuth client presents the Gonvex installation's shared verified brand and consent screen. The operator is responsible for ensuring every app using the broker belongs under that service and complies with Google's OAuth policies; do not use one brand to impersonate unrelated third-party applications.
- Create or select the Google Cloud project that represents the Gonvex service.
- Configure the Google Auth Platform branding and audience. A public hosted service should use a production External app, publish a real homepage and privacy policy, verify its domains, and complete any brand review Google requires.
- Create a Web application OAuth client.
- Add exactly one authorized redirect URI:
https://your-gonvex-runtime.example.com/auth/google/callback. - Configure the runtime:
GONVEX_AUTH_URL=https://your-gonvex-runtime.example.com
GONVEX_GOOGLE_CLIENT_ID=1234567890-example.apps.googleusercontent.com
GONVEX_GOOGLE_CLIENT_SECRET=...
GONVEX_AUTH_URL is browser-facing and must match the origin/path registered with
Google. Inject the client secret from your infrastructure secret manager; never put
it in an app's .env.local, browser bundle, image, or source repository. Restrict
access to the credential, rotate it on suspected exposure, and keep separate
credentials for non-production infrastructure. Gonvex requests openid email profile, exchanges Google's code server-side, and validates the returned ID token
against Google's JWKS. See Google's official web-server OAuth
guide and
OpenID Connect validation guide.
After the runtime is configured, every app owner only runs:
npx gonvex auth add google --origin https://app.example.com
npx gonvex auth doctor
For local apps, http://localhost origins are accepted. Non-local callback origins
must use HTTPS. The runtime keeps an exact per-project callback allowlist and never
accepts an arbitrary redirect URL from the browser.
The doctor is a configuration/readiness check. Before launch, also complete one real sign-in on every production app origin; that is the only end-to-end test of the Google client ID, secret, consent screen, redirect registration, proxy, and app route together.
The SPA provider keeps its short-lived access token and rotating refresh token in origin-scoped browser storage so it can work across app origins without third-party cookies. Treat XSS prevention as credential protection: deploy a restrictive CSP, avoid untrusted scripts, review dependencies, and never log or copy the stored session. Server-side token values are stored only as hashes.
Native Google login for the Gonvex dashboard
The dashboard itself can use the same native broker instead of a separate identity SDK. Give it a dedicated Gonvex project so sessions from customer applications can never become control-plane credentials:
npx gonvex project create dashboard-auth --database-mode single
npx gonvex project select <dashboard-auth-project-id>
npx gonvex auth add google \
--origin https://dashboard.example.com \
--callback-path /login
npx gonvex auth doctor
Configure the runtime and dashboard build with the same project ID:
# Runtime
GONVEX_DASHBOARD_AUTH_PROJECT_ID=<dashboard-auth-project-id>
DASHBOARD_AUTH_USER=admin@example.com
# apps/dashboard build-time values
VITE_GONVEX_DASHBOARD_AUTH_PROJECT_ID=<dashboard-auth-project-id>
VITE_GONVEX_GOOGLE_LOGIN_ENABLED=true
VITE_GONVEX_AUTH_ENABLED=true
The runtime accepts a dashboard Google session only when it was minted for that
exact project, contains a verified email, and the email is already a dashboard user
or matches DASHBOARD_AUTH_USER. App sessions from every other project are rejected.
What each component does
Runtime
Executes uploaded Go functions and serves HTTP and WebSocket traffic.
Postgres
Stores runtime control data and application data in the reference stack.
Valkey
Provides cache and realtime coordination.
Dashboard
Inspects and manages the development runtime.
S3-compatible storage
Optional for file APIs. The reference stack uses MinIO.
The Compose stack uses one Postgres instance and development credentials for
convenience. Gonvex also supports project-specific database routing through
GONVEX_PROJECT_DATABASE_URLS, but operating those databases remains your
responsibility.
Production Compose profile
docker-compose.production.yml is the hardened Git-backed profile used by the
Moneymaker installation. Unlike the reference development stack, it publishes no
database, cache, or object-storage ports; pins third-party images by digest; enables
durable Valkey persistence; requires dashboard/runtime authentication; persists the
plugin, database, and object-storage state; and writes daily retained PostgreSQL
dumps to a separate volume. Coolify attaches domains only to the
gonvex-maker-runtime and gonvex-maker-dashboard services and generates the
SERVICE_* credentials referenced by the file. Runtime and dashboard image builds also bound Go/Rayon/libuv parallelism so
an upgrade cannot consume every CPU on a shared host. The backup sidecar waits for
the runtime health gate before its first dump, ensuring the initial retained backup
contains the initialized control-plane schema rather than an empty new database.
Its own healthcheck requires a valid custom-format dump of at least 20 KB. All
service names are stack-specific because Coolify also joins applications to a
shared network; generic aliases such as postgres or runtime could otherwise
resolve to an unrelated application's container. The two public services also
declare high-priority HTTPS routers that use the Gabriel server's lehttp
HTTP-challenge resolver; Coolify's generated Compose routers otherwise select
the server's unrelated default resolver.
The local dump volume protects against an application or database regression, not loss of the host. A production operator must additionally copy encrypted database and object-storage backups off-host and prove a restore. Keep the bootstrap email and password in a secret manager, replace bootstrap access with named dashboard users, and configure the optional Google variables only after the OAuth redirect has been registered.
Moving beyond localhost
For a remote runtime, the application-facing values change to HTTPS and secure WebSockets:
GONVEX_RUNTIME_URL=https://gonvex.example.com
VITE_GONVEX_URL=https://gonvex.example.com
VITE_GONVEX_WS_URL=wss://gonvex.example.com/ws
The runtime listens on port 8080 in the reference image. Put it behind a reverse
proxy or load balancer that terminates TLS and supports WebSocket upgrades.
Auth rate limits use the direct peer address by default. When a trusted reverse
proxy supplies X-Forwarded-For, configure only its IPs or networks so clients
cannot spoof rate-limit identities:
GONVEX_TRUSTED_PROXY_CIDRS=10.0.0.0/8,192.0.2.10
The built-in limiter is per runtime process. Multi-replica deployments should add a distributed edge/WAF limit as well.
Minimum operations checklist
- Replace the Compose database, MinIO, and dashboard development credentials.
- Use durable Postgres storage and test database restoration.
- Persist
/var/lib/gonvexfor runtime plugin and telemetry data. - Run Valkey/Redis with an appropriate durability and eviction policy for your load.
- Back up every application database and object-storage bucket.
- Restrict access to the dashboard and
/dev/*management endpoints. - Preserve project authentication headers on proxied
/dev/*requests. - Configure TLS and preserve WebSocket upgrades on
/ws. - Set
GONVEX_PUBLIC_URLto the externally reachable runtime URL. - Set
GONVEX_AUTH_URLand the one Google client ID/secret when native Google login is offered. - Set
GONVEX_TRUSTED_PROXY_CIDRSwhen honoring a proxy's forwarded client addresses. - Run
gonvex auth doctorand a real Google sign-in for every production origin. - Monitor
/healthz, container restarts, database capacity, and runtime logs. - Pin and test image versions before upgrading.
If the app does not use Gonvex file APIs, production object storage is not required. When it is required, any compatible S3 provider can replace the local MinIO example.
Current deployment limits
There is no implemented gonvex deploy command in the current npm CLI. The commands
available today include dev, init, create, project, env, auth, account
login, and personal-token management; gonvex dev performs the development manifest
upload and schema sync.
Before treating the broader platform as production-ready, account for these unfinished areas:
- migration previews, destructive-change approval, and rollback tooling;
- automated tenant-database backup, restore, and fleet rollout operations;
- automated releases, rollbacks, and zero-downtime runtime upgrades;
- a supported public hosted control plane;
- organization-specific dashboard roles, audit export, and SSO policy.
For the complete status, see Current Limits.