Gonvex

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.

!
Beta software

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.

ServiceAddressContainer port
Runtimehttp://localhost:80808080
Dashboardhttp://localhost:300080
Postgreslocalhost:54325432
Valkeylocalhost:63806379
MinIO APIhttp://localhost:90009000
MinIO consolehttp://localhost:90019001

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.

  1. Create or select the Google Cloud project that represents the Gonvex service.
  2. 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.
  3. Create a Web application OAuth client.
  4. Add exactly one authorized redirect URI: https://your-gonvex-runtime.example.com/auth/google/callback.
  5. 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/gonvex for 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_URL to the externally reachable runtime URL.
  • Set GONVEX_AUTH_URL and the one Google client ID/secret when native Google login is offered.
  • Set GONVEX_TRUSTED_PROXY_CIDRS when honoring a proxy's forwarded client addresses.
  • Run gonvex auth doctor and 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.
i
MinIO is optional

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.

On this page