v0.6.0 Apache-2.0 amd64 & arm64

Compute environments on Kubernetes,
from a browser.

Helve turns a single Kubernetes namespace into a self-service platform. Your team launches JupyterLab, RStudio, or an LLM inference engine from a form — and gets a working URL, already logged in. No kubectl, no YAML, no cluster credentials handed out.

Self-hosted. Runs entirely inside your cluster. Nothing calls home.

Ships with templates for
  • JupyterLab
  • RStudio
  • Ollama
  • vLLM
  • SGLang

The gap it fills

A shared GPU cluster is only useful if people can actually get onto it. The usual answers are a shared SSH box that drifts, a pile of hand-edited manifests, or handing out kubeconfigs and hoping. Helve is the small piece in between: a login, a form, and a URL — with the cluster's own primitives doing the work underneath.

It is deliberately single-namespace and asks for a Role, never a ClusterRole. It manages what you point it at and nothing else.

What you get

Launch from a template

An admin curates templates and an image catalog; everyone else picks one, sets CPU/memory/GPU, and launches. Credentials like a Jupyter token are generated per deployment and shown only to the owner.

Open, already signed in

Helve reverse-proxies into the pod and injects the generated credential, so Open lands you in a live session with no token to copy. WebSocket upgrades are tunnelled, so Jupyter kernels work.

Local, LDAP/AD, or SSO

Local accounts always work — the bootstrap admin has no other way in — and LDAP/Active Directory or an OIDC provider (Okta, Azure AD, Keycloak, Authentik, ...) can be turned on alongside it, independently, with group-to-admin-role mapping re-checked on every login.

Per-user quotas

CPU, memory and GPU limits with a global default and per-user overrides. Usage is summed from Deployment specs — desired state, correct the instant it's written — rather than from observed pods, which lag and double-count mid-rollout.

Vendor-agnostic accelerators

GPUs are detected from the device-plugin resource name, so NVIDIA, AMD, Intel, Habana, AWS Neuron and TPU all count toward quota without a per-vendor code path.

Lifecycle management

Scale, edit resources and env, restart, roll back to the previous ReplicaSet, or delete — all scoped by ownership. Regenerate a leaked credential without redeploying.

Placement and identity

Pin a user's launches to a node label, assign a per-user UID/GID so different people own their own files on shared storage instead of colliding on one identity, and grant supplemental-group membership for the POSIX/NFS pattern of belonging to several shares at once.

Per-user home directories

A template can mount <base>/<username> for every user who launches it — a shared filesystem already mounted on every node, a PersistentVolumeClaim per user that Helve provisions itself, or one shared PVC split by subpath. Off by default, opt in per template.

Network-layer tenant isolation

Opt-in Istio mTLS: every launched deployment gets its own ServiceAccount and AuthorizationPolicy, so one tenant's pod can no longer reach another's ClusterIP directly — closing the gap underneath Helve's own ownership checks, not just patching around it.

Audit trail

Every login and launch is recorded — who ran what, with which resources. Generated secrets are redacted in the log rather than stored twice.

API tokens

Mint a long-lived bearer token to script against the API without a browser session. Only a SHA-256 hash is ever stored.

The part most get wrong

If you proxy someone's notebook at https://helve.example.com/proxy/their-app/, that notebook is same-origin with your dashboard. Any JavaScript running in it — a pasted cell, a malicious dependency — can call /api/* as whoever is browsing it. HttpOnly doesn't help: the browser attaches the cookie to same-origin fetch automatically.

Helve serves every deployment from its own origin, <name>.proxy.example.com. The browser then treats it as a different site, and Helve's host-only session cookie never travels there. Access is granted by an OAuth-shaped handshake that mints a single-use token on the app origin and exchanges it for a per-deployment cookie.

That's all the HTTP layer. Underneath it, every launched pod still shares one namespace — by default, any of them can reach any other's ClusterIP directly, skipping Helve's checks entirely. v0.6.0 closes that with opt-in Istio mTLS: a per-deployment AuthorizationPolicy that denies pod-to-pod traffic between different owners at the network layer, not just at the routes Helve itself serves.

  • Namespace-scoped Role, never a ClusterRole
  • Ownership enforced on every read and write, not just in the UI
  • Argon2 password hashing with per-address login throttling
  • Cookies marked Secure, HttpOnly, SameSite=Lax
  • Helve's own cookies stripped before forwarding to a pod
  • Set-Cookie from a pod can't overwrite your session
  • Optional Istio mTLS: a tenant's pod can't reach another tenant's pod

How it fits together

Traefik terminates TLS and routes on Host. Helve talks to the Kubernetes API with a namespace-scoped Role, keeps its catalog in Postgres, and reverse-proxies each launched workload from its own origin.

Architecture diagram: users reach Traefik over HTTPS, which routes on Host to Helve; Helve reverse-proxies the launched workloads, stores its catalog in PostgreSQL, and creates them through the Kubernetes API with a namespace-scoped Role. cert-manager issues the TLS certificate Traefik serves.
Open the interactive diagram →

Install

A published Helm chart and a public multi-arch image. No registry credentials needed.

Try it

Bundled single-replica Postgres, TLS off. For evaluation only — no backups.

helm install helve \
  oci://ghcr.io/techboredom/charts/helve \
  --version 0.6.0 \
  --namespace helve --create-namespace \
  --set host=helve.example.com \
  --set database.deploy.enabled=true \
  --set ingress.tls.enabled=false \
  --set adminBootstrap.password=change-me

Run it properly

Your own Postgres, and cert-manager issuing the certificate.

helm install helve \
  oci://ghcr.io/techboredom/charts/helve \
  --version 0.6.0 \
  --namespace helve --create-namespace \
  --set host=helve.example.com \
  --set ingress.className=traefik \
  --set database.existingSecret=helve-db-app \
  --set ingress.tls.issuerRef.name=letsencrypt

The release name and namespace above are yours to choose; only the oci:// reference is fixed. Bringing your own LDAP/AD or SSO directory, or a persistent home directory per user? See the full install guide for the decision trees.

Requirements

  • Kubernetes with an ingress controller
  • PostgreSQL — bring your own, or use the bundled one to evaluate
  • Wildcard DNS for *.proxy.<your host>, plus a matching certificate, to give each deployment its own origin
  • cert-manager only if you want the chart to request the certificate. A wildcard needs a DNS-01 solver; HTTP-01 cannot issue one

The chart refuses to render a broken or quietly-insecure install rather than producing something that half-works — an unset host, a missing issuer, or same-origin proxying without an explicit acknowledgement all fail fast with the reason.

Built with

A Rust workspace: Axum and kube-rs on the server, Leptos compiled to WebAssembly in the browser, and sqlx against Postgres. One static binary on a distroless base, running as non-root with a read-only root filesystem and all capabilities dropped.