Deployment
The dev scripts in Getting started are the quickest way to hack on HiveKeeper. To run
it as a deployed stack — the gateway plus an on-prem agent, optionally with Postgres and OIDC — use the
committed Docker Compose files. (Everything here works the same with podman compose.)
This page is the DEVELOPMENT stack.
It is zero-config on purpose, and its defaults say so: a publicly-known encryption key, the database password
app, a Keycloak in dev mode whose users’ passwords are their usernames. Do not run it on the internet.
For a deployment you intend to keep — TLS, generated secrets, per-user login, backups — follow Running in production, which uses a separate, self-contained stack that refuses those defaults rather than inheriting them.
Compose stack
The repo root ships a layered set of compose files:
| File | Adds |
|---|---|
docker-compose.yml | The base: the gateway (in-memory, no DB) and one agent. |
docker-compose.postgres.yml | Postgres + switches the gateway to the postgres profile (durable jobs, org/users/fleet, audit log, RLS). |
docker-compose.keycloak.yml | A dev Keycloak (imports the hivekeeper realm) + the oidc profile for per-user login. |
docker-compose.authentik.yml | A dev Authentik (OAuth2/OIDC provider) + the oidc,oidc-authentik profile for per-user login. |
Bring it up
# Simplest: gateway (in-memory) + agent, built from source on a fresh clone.docker compose up -d --build
# With persistence (Postgres):docker compose -f docker-compose.yml -f docker-compose.postgres.yml up -d --build
# With persistence + OIDC/SSO (sign in at the console with owner/owner):docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.keycloak.yml up -d --build
# OR with Authentik:docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.authentik.yml up -d --buildThe gateway listens on :8090. The agent dials out to it over WebSocket (no inbound ports) and resolves
SSH credentials locally — the cloud never sees them. Configure via env (copy .env.example to .env); the
key ones are HIVEKEEPER_DEFAULT_USER / HIVEKEEPER_DEFAULT_PASSWORD (the agent’s fallback SSH login),
HIVEKEEPER_CREDENTIAL_VAULT + HIVEKEEPER_VAULT_KEY (a per-device vault HiveKeeper can manage from the UI,
encrypted at rest), and, for the Postgres profile, HIVEKEEPER_CRYPTO_KEY (job-secret encryption — set a real
key in production: openssl rand -base64 32).
Optional subsystem env (agent + gateway)
| Variable | On | Enables |
|---|---|---|
HIVEKEEPER_PPSK_STORE | agent | Path to the on-prem PPSK key store — turns on admin-minted PPSK via RADIUS (with HIVEKEEPER_VAULT_KEY for at-rest encryption). Lab/untested; see PPSK runbook. |
HIVEKEEPER_RADIUS_DIR | agent | Directory the agent writes the FreeRADIUS authorize file to (the PPSK RADIUS runtime). |
HIVEKEEPER_ALERT_POLL_INTERVAL_MS | gateway (postgres) | Background alert-poller interval (default 300000 = 5 min); …_INITIAL_DELAY_MS for the first run. |
HIVEKEEPER_SMTP_HOST / …_PORT / …_USER / …_PASSWORD + HIVEKEEPER_ALERT_EMAIL_FROM | gateway (postgres) | SMTP for email alert channels. Unset ⇒ email channels are skipped (webhook channels need no config). |
The poller and email/webhook delivery only run under the postgres profile; channels + thresholds are managed
in the console under Alerts → Alert delivery (admin-gated).
The console (hive-web) is its own container: a static bundle behind nginx, which also proxies the console’s
/gw calls to the gateway (in development that proxy is the Vite dev server’s job). It is not bundled into
the gateway. For hacking on the UI, pnpm --dir hive-web dev is still the fastest loop.
Nothing about your deployment is baked into the bundle — it asks the gateway where to sign in
(GET /api/mode) at runtime, so the published image works against whatever domain and identity provider you
point it at.
Keycloak-in-Docker issuer gotcha: tokens are minted for the browser-facing URL (http://localhost:8081),
so the gateway validates the iss claim against that while fetching JWKs over the container network. If you
reach the console from another host or port, set HIVEKEEPER_OIDC_ISSUER to match where users log in.
Container images
Released images are published to the GitHub Container Registry:
ghcr.io/ggfto/hivekeeper-gatewayghcr.io/ggfto/hivekeeper-agentghcr.io/ggfto/hivekeeper-serverghcr.io/ggfto/hivekeeper-web— the console
Each is tagged with the release version (e.g. 0.2.0) and latest. To run the published images instead of
building from source, set the tag and pull:
HIVEKEEPER_TAG=latest docker compose pull && docker compose up -dVersioning & releases
Versioning is automated with semantic-release driven by
Conventional Commits. On every push to main, the Release
workflow inspects the commits since the last release and, if any warrant one (feat → minor, fix →
patch, feat!/BREAKING CHANGE → major):
- bumps
versioningradle.properties(the single source of truth for all JVM modules and the images), - updates
CHANGELOG.md, commits and tags it (vX.Y.Z), - builds and pushes the gateway/agent/server images to GHCR (tagged with the version and
latest), - creates the GitHub Release.
No release-worthy commits since the last tag → the workflow does nothing.
One-time setup: so the first automated release does not jump to 1.0.0, create a baseline tag on the
current commit: git tag v0.1.0 && git push origin v0.1.0. The release job needs the repository’s
GITHUB_TOKEN to have contents: write and packages: write (already set in the workflow).