Self-Host
What one install gives you
This is the connected / online installer: the target cluster must be able to reach the public internet. Images are pulled directly from public registries (ghcr.io / docker.io / registry.k8s.io) and prerequisite charts/manifests are fetched from their public sources. There is no offline image bundle, no in-cluster registry, and no host image-loading step. For fully air-gapped sites, a separate offline installer ships an image tarball, an in-cluster registry, and a host-prep step.
Core platform (always installed)
- Control plane — agent management, scheduling, user and workspace management
- Channel gateway — the entry point for external events (webhooks, Slack, etc.) to reach agents
- Data layer — PostgreSQL (CloudNativePG) + shared NFS
- Agent workspace runtime — one pod per workspace runs the agent; agents can
@each other, share files, and share a memory store
Optional modules (off by default)
- Code Sandbox — lets agents run code and serve temporary web previews. Powered by the third-party OpenSandbox, which you install yourself; the platform points at it via
OPENSANDBOX_URL - Remote Browser — lets agents drive a real browser while users watch live over WebRTC. Ships a bundled TURN relay (coturn) and a published headful Chromium image
- LDAP — let users sign in with their LDAP account
Prerequisites
Infrastructure
| Resource | Requirement | Notes |
|---|---|---|
| Kubernetes | v1.28+ (multi-node), or a single k3s node (single-node profile) | 3+ workers recommended |
| Worker nodes | 4 vCPU / 8GB RAM minimum | Agent pods are created per workspace dynamically |
| Public registry access | Nodes can pull from ghcr.io, docker.io, registry.k8s.io | Override REGISTRY only to use a mirror |
| RWX shared storage | A CSI that supports ReadWriteMany (NFS is the most common) | Backs the AFS shared directory, 500Gi by default |
| RWO volume storage | Any CSI that can run PostgreSQL (Ceph RBD, vSAN, etc.; the same NFS also works) | PostgreSQL data volumes + agent workspace container disks |
Network
| Item | Requirement |
|---|---|
| Node IP | At least one worker IP reachable by users (NodePort uses it) |
| NodePort | 3 free ports in 30000–32767: TOS_NODE_PORT / BROWSER_NODE_PORT / SANDBOX_NODE_PORT |
| TURN ports | When the Remote Browser's TURN relay is enabled: open 3478/tcp+udp and 49152-49252/udp on the coturn node |
| Storage reachability | All nodes can mount the two storage classes above (NFS / block-storage CSI, etc.) |
| Registry reachability | All nodes can pull images from the public registries |
LLM API
The platform does not bundle any model. Depending on the agent types you enable, you must provide protocol-compatible API endpoints:
| Agent type | API protocol required |
|---|---|
| Codex | OpenAI Responses API (note: not Chat Completions) |
| Claude Code | Anthropic API |
If your existing model service only supports the OpenAI Chat Completions API, one option is to put a translating proxy in front of it that converts the OpenAI Chat protocol to the Anthropic protocol, then point Claude Code-style agents at the proxy.
kubeconfig permissions
Installation requires cluster-admin — install.sh touches resources that a namespace-scoped admin cannot (CRDs, webhooks, ClusterRoles, StorageClasses, etc.). You can revoke it immediately after install; at steady state the control plane authenticates via its own in-cluster ServiceAccount with tightly scoped permissions (normal read/write within the namespace + cluster-scoped get/list on nodes only).
The operator's kubeconfig is never mounted into any platform pod. If a temporary cluster-admin is not acceptable, here is an equivalent minimal ClusterRole.
Equivalent minimal ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nap-installer
rules:
- apiGroups: [apiextensions.k8s.io]
resources: [customresourcedefinitions]
verbs: [get, list, watch, create, update, patch, delete]
- apiGroups: [admissionregistration.k8s.io]
resources: [validatingwebhookconfigurations, mutatingwebhookconfigurations]
verbs: [get, list, watch, create, update, patch, delete]
- apiGroups: [""]
resources: [namespaces]
verbs: [get, list, create, update, patch]
- apiGroups: [rbac.authorization.k8s.io]
resources: [clusterroles, clusterrolebindings, roles, rolebindings]
verbs: [get, list, watch, create, update, patch, delete]
- apiGroups: [storage.k8s.io]
resources: [storageclasses]
verbs: [get, list, create, update, patch]
- apiGroups: [postgresql.cnpg.io]
resources: ["*"]
verbs: ["*"]
- apiGroups: [opensandbox.alibaba.com]
resources: ["*"]
verbs: ["*"]
- apiGroups: ["", apps, batch, networking.k8s.io, policy]
resources: ["*"]
verbs: ["*"]
- apiGroups: [""]
resources: [nodes]
verbs: [get, list, watch]This is still close to cluster-admin in practice (*/* on the core/apps/batch groups), but spelling out the resources makes a security review easier.
Once the prerequisites are in place: