v0.3.0 Apache-2.0 amd64 & arm64

Compute environments on Kubernetes,
from a browser.

Aether 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. Aether 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

Aether 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.

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, and assign a per-user UID/GID so different people own their own files on shared NFS instead of colliding on one identity.

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 dashboards get wrong

If you proxy someone's notebook at https://aether.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.

Aether serves every deployment from its own origin, <name>.proxy.example.com. The browser then treats it as a different site, and Aether'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.

  • 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
  • Aether's own cookies stripped before forwarding to a pod
  • Set-Cookie from a pod can't overwrite your session
  • CI holds no cluster credentials — Argo CD is the only writer

How it fits together

Traefik terminates TLS and routes on Host. Aether 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, which routes to Aether; Aether talks to the Kubernetes API, PostgreSQL and the launched workloads. Git and GHCR feed Argo CD, which deploys into the cluster.
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 aether \
  oci://ghcr.io/techboredom/charts/aether \
  --version 0.3.0 \
  --namespace aether --create-namespace \
  --set host=aether.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 aether \
  oci://ghcr.io/techboredom/charts/aether \
  --version 0.3.0 \
  --namespace aether --create-namespace \
  --set host=aether.example.com \
  --set ingress.className=traefik \
  --set database.existingSecret=aether-db-app \
  --set ingress.tls.issuerRef.name=letsencrypt

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.