{"id":51941065,"url":"https://github.com/FootprintAI/Containarium","last_synced_at":"2026-07-29T18:00:52.631Z","repository":{"id":331613968,"uuid":"1124390254","full_name":"FootprintAI/Containarium","owner":"FootprintAI","description":"Open-source agent runtime — SSH-native isolation, eBPF egress policy, Kubernetes + LXC backends, GPU passthrough, MCP-native CLI","archived":false,"fork":false,"pushed_at":"2026-07-22T06:33:21.000Z","size":14028,"stargazers_count":263,"open_issues_count":31,"forks_count":18,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-07-22T08:25:18.325Z","etag":null,"topics":["agent-native","agent-runtime","agent-sandbox","agentic-ai","ai-agents","claude","code-sandbox","cursor","ebpf","gpu","kubernetes","llm","lxc","mcp","model-context-protocol","multi-tenant","sandbox","self-hosted","ssh"],"latest_commit_sha":null,"homepage":"https://containarium.dev","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FootprintAI.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-28T23:58:47.000Z","updated_at":"2026-07-22T07:07:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"aa22542b-3d3c-447c-a43a-7737714619c9","html_url":"https://github.com/FootprintAI/Containarium","commit_stats":null,"previous_names":["footprintai/containarium"],"tags_count":133,"template":false,"template_full_name":null,"purl":"pkg:github/FootprintAI/Containarium","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FootprintAI%2FContainarium","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FootprintAI%2FContainarium/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FootprintAI%2FContainarium/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FootprintAI%2FContainarium/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FootprintAI","download_url":"https://codeload.github.com/FootprintAI/Containarium/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FootprintAI%2FContainarium/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36043168,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-29T02:00:04.910Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-native","agent-runtime","agent-sandbox","agentic-ai","ai-agents","claude","code-sandbox","cursor","ebpf","gpu","kubernetes","llm","lxc","mcp","model-context-protocol","multi-tenant","sandbox","self-hosted","ssh"],"created_at":"2026-07-28T19:00:29.477Z","updated_at":"2026-07-29T18:00:52.624Z","avatar_url":"https://github.com/FootprintAI.png","language":"Go","funding_links":[],"categories":["Go","Tools and Development Workflows"],"sub_categories":[],"readme":"# Containarium — Agent Runtime\n\n\u003e **Open-source agent runtime** · SSH-native isolation · eBPF egress policy · Kubernetes + LXC · MCP-native CLI · GPU passthrough\n\n**The open-source, self-hostable agent runtime for AI agents.**\nEach agent gets a persistent, SSH-reachable box with per-tenant network isolation — no kube-apiserver token, no host access, no cross-tenant leakage.\n\nBring your own agent — Cursor, Claude Code, OpenCode, your own MCP client.\nWe run the box.\n\n```\nagent: \"create me a sandbox called 'blog'\"           → containarium create\nagent: \"wire up SSH so I can reach it\"               → containarium ssh-config sync\nagent: \"install Caddy on :8080 inside the box\"       → shell_exec (via agent-box MCP)\nagent: \"expose that on blog.example.com\"             → containarium expose-port\n\ncurl https://blog.example.com → hello world\n```\n\n[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)\n[![Go](https://img.shields.io/badge/go-1.25-00ADD8.svg)](go.mod)\n[![Containarium MCP server](https://glama.ai/mcp/servers/FootprintAI/Containarium/badges/score.svg)](https://glama.ai/mcp/servers/FootprintAI/Containarium)\n\n[![Containarium MCP server](https://glama.ai/mcp/servers/FootprintAI/Containarium/badges/card.svg)](https://glama.ai/mcp/servers/FootprintAI/Containarium)\n\n[![Containarium demo: one command to install, then an AI agent turns a fresh box into a live HTTPS app](docs/images/demo-preview.gif)](https://youtu.be/IBDDD_tb8FY)\n\n🌐 **Project site:** [containarium.dev](https://containarium.dev) · 🎬 **55s demo:** [youtu.be/IBDDD_tb8FY](https://youtu.be/IBDDD_tb8FY) · 🚀 **Live app:** [helloworld.demo.containarium.dev](https://helloworld.demo.containarium.dev)\n\n---\n\n## Why an agent runtime?\n\nAI agents are increasingly the primary user of dev infrastructure. They\nwant to build, install, deploy, and verify — not on the human's laptop\n(too noisy, too risky, too local) but on a persistent, isolated runtime that's:\n\n- **Persistent**: state survives between agent runs.\n- **Isolated**: a misbehaving install doesn't touch your machine or your cluster.\n- **Real**: a full Linux environment with `systemd`, real networking,\n  and the ability to host things on the open internet.\n- **Driven by structured tools**: not by an agent typing commands into a\n  TTY hoping nothing scrolls off-screen, but by MCP — typed,\n  bounded, safe.\n- **Blast-radius-bounded**: the agent holds an SSH key, not a\n  kube-apiserver token. It can't reach the cluster control plane, the\n  host OS, or other tenants' boxes.\n\nThat's the runtime Containarium gives you. It runs as a self-hosted\nplatform on LXC or Kubernetes, exposes its admin surface over MCP, and\nships a second MCP server that lives *inside* the box so the agent can\n`shell_exec` and edit files directly.\n\nYou bring the agent. We run the box.\n\n---\n\n## Quick start\n\n### 1. Self-host on a fresh Ubuntu VM (5 minutes)\n\n```bash\ncurl -fsSL https://containarium.dev/install.sh | sudo bash\n```\n\nThat installs Containarium + Incus + dependencies, starts the daemon,\nand gives you a working API at `http://localhost:8080`.\n\n### 2. Create your first box\n\n```bash\nsudo containarium create alice --ssh-key ~/.ssh/id_ed25519.pub\nsudo containarium list\n```\n\n### 3. Wire up SSH so `ssh alice` just works\n\n```bash\ncontainarium ssh-config sync\n# Adds entries to ~/.containarium/ssh_config.\n# Then add ONE line to ~/.ssh/config:\n#     Include ~/.containarium/ssh_config\nssh alice  # connects through the sentinel\n```\n\n### 4. Point your agent at the box\n\nIn `~/.cursor/mcp.json` or `~/.claude.json`:\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"containarium-box\": {\n      \"command\": \"ssh\",\n      \"args\": [\"alice\", \"agent-box\"]\n    }\n  }\n}\n```\n\nNow Claude Code, Cursor, or any MCP-speaking agent can call\n`shell_exec`, `read_file`, `write_file`, `list_directory`,\n`move_file`, `delete_file` directly inside Alice's container.\n\n### 5. Make it reachable on a public hostname\n\n```bash\ncontainarium expose-port alice \\\n  --container-port 8080 \\\n  --domain blog.example.com\n```\n\nCaddy on the sentinel terminates TLS for `blog.example.com` and\nforwards to `alice-container:8080`. `curl https://blog.example.com`\nhits whatever Alice has serving on port 8080.\n\n---\n\n## The four primitives\n\nEvery action in Containarium has a CLI verb (canonical) AND an MCP tool\n(thin wrapper that delegates to the same Go function). See\n[CLAUDE.md](CLAUDE.md) for the convention.\n\n### `agent-box` — in-the-box MCP server\n\nRuns inside every container. Reached over stdio (typically wrapped by\nSSH on the client side). Exposes Linux-native operations:\n\n| Tool | What it does |\n|---|---|\n| `shell_exec` | Run a shell command, capture stdout/stderr/exit, bounded by timeout (default 30s, max 10min) and 256 KiB output cap |\n| `read_file` | Byte range OR `head=N` lines OR `tail=N` lines |\n| `write_file` | Atomic write with `mkdirp` (temp + rename) |\n| `list_directory` | Type/size/mtime, hidden filtering |\n| `move_file` | Atomic rename with `mkdirp` on destination |\n| `delete_file` | Single-file remove (refuses directories so recursive deletes go via `shell_exec` where blast radius is explicit) |\n\nResources (read-only data the agent fetches via MCP `resources/read`):\n\n| URI | What it returns |\n|---|---|\n| `containarium://ci-context` | JSON metadata about the current CI run (PR number, commit SHA, failing test, etc.) when the box was kept alive by the FootprintAI/containarium-run GitHub Action after a failed CI run. Returns `{\"available\": false}` on non-CI boxes so callers never have to special-case errors. |\n| `containarium://ci-prompt` | Static markdown playbook telling agents how to debug a failing CI run inside this box (what to read first, how to iterate, what not to do). Same body on every box; pair with `ci-context` for the per-run data. |\n\nOptional sandbox: when `AGENTBOX_ROOT` is set, every file-ops path is\nresolved against that root with a boundary-aware prefix check. Default\nunset = no constraint. See\n[`internal/agentbox/`](internal/agentbox/) for the Go implementation.\n\n### `mcp-server` — platform MCP server\n\nRuns on the host. Exposes outside-the-box admin operations:\n`create_container`, `list_containers`, `delete_container`,\n`start_container`, `stop_container`, `expose_port`, `get_metrics`,\n`get_system_info`. See [`cmd/mcp-server/`](cmd/mcp-server/).\n\n### `containarium` CLI\n\nSame surface as the platform MCP, plus deeper administration. Top-level\nverbs:\n\n```\ncontainarium create        Create a new container\ncontainarium list          List all containers\ncontainarium delete        Delete a container\ncontainarium expose-port   Expose container:port on a public hostname\ncontainarium ssh-config    Generate self-contained ssh_config\ncontainarium route         Manage proxy routes (low-level)\ncontainarium passthrough   Manage TCP/UDP passthrough rules\ncontainarium token         Issue JWT tokens for the API\ncontainarium info          System info\ncontainarium version       Print version\n```\n\nRun `containarium \u003cverb\u003e --help` for full options.\n\n### Sentinel — sshpiper + Caddy + PROXY-protocol\n\nThe sentinel is a tiny always-on VM (e2-micro on GCP free tier works)\nthat:\n\n- Receives SSH on port 22 (sshpiper routes to the right backend by\n  username).\n- Receives HTTPS on 443 (Caddy with TLS-passthrough or\n  PROXY-protocol-aware forwarding to backend Caddy).\n- Survives spot-VM termination on the backend with a maintenance page.\n- Holds the static IP / DNS A-record so backends can be ephemeral.\n\nSee [docs/SENTINEL-DESIGN.md](docs/SENTINEL-DESIGN.md) for the full\ndesign.\n\n---\n\n## Architecture\n\n```\n        Agent (Cursor / Claude Code / OpenCode)\n            │\n            │ JWT (access; tt=access, jti, scopes)\n            │ MCP over stdio  ──┐\n            │                   │ ┌── refresh ──\u003e POST /v1/tokens/refresh\n            v                   ▼ │                  (single-use; old jti revoked)\n        ssh user@box  → sshpiper → agent-box (in container)\n            │\n            │ HTTPS  (mTLS upstream; PROXY-protocol v2)\n            v\n        Sentinel (e2-micro, always-on)\n        ├── sshpiper (port 22)            : routes by username; fail2ban per-user\n        ├── Caddy + PROXY-protocol (443)  : routes by hostname / SNI suffix\n        └── /wake/ source-IP allowlist    : trusted-proxy only\n            │\n            v\n        +-------------------------------------------------+\n        | Backend VM (spot or bare-metal GPU node)        |\n        |                                                 |\n        |  Incus (LXC) ── containers                      |\n        |    ├── alice-container    : SSH + agent-box     |\n        |    │   └── /run/secrets/* : tmpfs, 0440 alice   |\n        |    └── bob-container      : ZFS-backed storage  |\n        |                                                 |\n        |  Containarium daemon                            |\n        |    ├── JWT auth (iss/aud/jti/scopes)            |\n        |    ├── Admin RBAC + container-owner authz       |\n        |    ├── Image-digest gate (REQUIRE + VERIFY)     |\n        |    ├── Secrets ── Postgres (envelope-encrypted) |\n        |    │              │                             |\n        |    │              v                             |\n        |    │           KMS ── Vault Transit / GCP KMS   |\n        |    │           (master key retirable post-cutover)\n        |    └── Audit log ── Postgres + SHA-256 hash     |\n        |                     chain (verify CLI)          |\n        +-------------------------------------------------+\n```\n\nA single sentinel can front multiple backend VMs — a \"pool\" — and a\nsingle deployment can run multiple pools (each isolated). See\n[docs/MULTI-POOL.md](docs/MULTI-POOL.md).\n\n**Security control surface** (all opt-in via env, default-off for\nupgrade safety; see [`docs/security/OPERATOR-SECURITY-RUNBOOK.md`](docs/security/OPERATOR-SECURITY-RUNBOOK.md)):\n\n| Env var | Layer | Effect |\n| --- | --- | --- |\n| `CONTAINARIUM_REQUIRE_IMAGE_DIGEST=true` | API | refuse images without `@sha256:\u003c64hex\u003e` |\n| `CONTAINARIUM_VERIFY_IMAGE_DIGEST=true` | API | verify digest against the registry index (pre- + post-pull) |\n| `CONTAINARIUM_ALLOWED_IMAGE_REGISTRIES` | API | restrict which simplestreams remotes the daemon will pull from |\n| `CONTAINARIUM_KMS_BACKEND={none,inproc,vault,gcp}` | Secrets | envelope-encrypt DEKs through an external KMS |\n| `CONTAINARIUM_REQUIRE_ENVELOPE=true` | Secrets | refuse legacy master-key-only rows (Phase E retirement gate) |\n| `CONTAINARIUM_POSTGRES_URL_FILE` / `_PASSWORD_FILE` | Secrets | DB creds from disk rather than env |\n| `CONTAINARIUM_WAKE_TRUSTED_PROXIES` | Sentinel | source-IP allowlist for `/wake/` |\n| `OTEL_BEARER_REQUIRED=true` | Telemetry | collector rejects un-bearered OTLP submissions |\n\n---\n\n## How it's different\n\n### vs. SaaS-only sandboxes (e2b, Modal, Replit)\n\nThese give you sandboxes for AI agents, but only as hosted SaaS:\n\n- **Self-hostability**: Containarium runs on your own infrastructure\n  (a $5 VM, your homelab, your enterprise data center). e2b, Modal,\n  and Replit are SaaS-only — your code, your data, and your customers\n  go through their compute.\n- **License**: Apache 2.0, no CLA. Fork it, sell it, run it.\n- **Surface**: full Linux containers with `systemd`, real network\n  namespaces, GPU passthrough. Not a process-per-call sandbox.\n- **Transport**: MCP-native from day one, not a custom SDK with MCP\n  bolted on.\n\n### vs. Docker AI Sandboxes (`sbx`)\n\nDocker's `sbx run claude` and Containarium both call themselves\n\"AI sandboxes,\" but they sit on opposite ends of the same spectrum:\n\n- **Locality**: `sbx` runs the sandbox on the developer's laptop\n  (microVM, host-isolation). Containarium runs the sandbox on a VM\n  you host (LXC, multi-tenant, public-internet reachable via the\n  sentinel).\n- **Persistence**: `sbx` is session-shaped (workspace mount, no\n  documented \"give me a box that survives reboot and has a\n  hostname\"). Containarium containers persist indefinitely, with\n  ZFS snapshots and 30-day retention.\n- **Public reach**: `containarium expose-port alice --domain\n  blog.example.com` is one verb. `sbx` is laptop-local; no\n  public-hostname story.\n- **Agent surface**: `sbx` is CLI-first (`sbx run \u003cagent\u003e`).\n  Containarium is MCP-native — two MCP servers (in-the-box\n  `agent-box` + platform `mcp-server`) plus the same surface via\n  CLI, SSH, REST/gRPC, and a web UI.\n- **License**: `sbx` CLI is free; team policy (Docker Admin Console)\n  is a paid subscription. Containarium is Apache 2.0 — including\n  the audit log, RBAC, KMS integrations, and everything else on\n  this page.\n\nIf you're stopping an agent from `rm -rf`-ing the laptop it's\nrunning on, `sbx` is the lighter tool. If you're giving your agent\n(or your customer's agent) a persistent Linux box on the public\ninternet, Containarium is the shape.\n\n### vs. OSS Kubernetes agent runtimes (agent-sandbox, OpenShell)\n\n[`kubernetes-sigs/agent-sandbox`](https://github.com/kubernetes-sigs/agent-sandbox)\nand [`NVIDIA/OpenShell`](https://github.com/NVIDIA/OpenShell) are the\nclosest open-source peers on Kubernetes:\n\n- **SSH-native vs. exec-based**: both agent-sandbox and OpenShell reach\n  the sandbox via `kubectl exec` or a proprietary client, which requires\n  the agent to hold a kube-apiserver token or cluster credentials.\n  Containarium reaches the pod over SSH through sshpiper — the agent has\n  no path to the cluster control plane at all.\n- **MCP-native**: agent-sandbox and OpenShell expose REST APIs or custom\n  SDKs. Containarium's `agent-box` MCP server runs *inside* the box,\n  reachable over SSH stdio — any MCP-speaking agent (Claude Code, Cursor,\n  OpenCode) works with zero client library.\n- **LXC + K8s, one CLI**: Containarium runs on either Incus/LXC or\n  Kubernetes behind the same `containarium` CLI and `--runtime` flag. You\n  switch backends without changing anything for the agent.\n- **eBPF egress policy**: Containarium enforces per-tenant egress\n  allowlists at the kernel level via TC_INGRESS eBPF programs.\n  agent-sandbox has NetworkPolicy; OpenShell has eBPF but is\n  NVIDIA-stack-specific. Neither offers a portable, per-tenant eBPF\n  allowlist across LXC and K8s backends.\n\n### vs. dev environment platforms (Codespaces, Gitpod, Coder)\n\nThose are persistent IDEs. Containarium is a persistent **box** —\nagent-driven, not developer-driven, no IDE assumption, SSH-as-the-API:\n\n- Containarium environments are reached by SSH and MCP. Any IDE works\n  (Vim, JetBrains Remote, VS Code Remote, Cursor's remote dev — your\n  call).\n- Cost: no per-hour billing in the OSS path. Self-host costs are just\n  your underlying VM.\n- Persistence: containers survive indefinitely; Codespaces auto-delete\n  after inactivity.\n\n### vs. application container platforms (Docker, Kubernetes)\n\nLXC is a **system** container, not an application container. Each\ncontainer has `systemd`, a real init, real users, real package managers,\nreal `sudo`. You can run Docker *inside* a Containarium container; the\nreverse isn't really a thing.\n\nIf your agent is going to `apt install` half a Linux distro, edit\nconfig files in `/etc`, run a database, and reboot — LXC is the right\nshape. If your agent runs a single Python process, Docker or Modal is\nfine.\n\nIt isn't either/or: Containarium can run a box *as a pod* in a\nKubernetes cluster you already operate — same SSH-native agent contract,\nno kube-apiserver token in the agent's hands. Switch with\n`--runtime=k8s`. See the **Kubernetes backend** section below.\n\n---\n\n## What's in the box\n\nBeyond the agent-native primitives, Containarium ships:\n\n### Multi-OS\n\n- **Ubuntu 24.04 LTS** (default)\n- **Rocky Linux 9** (dev/test)\n- **RHEL 9** (production)\n- **Windows Server VMs** via QEMU/KVM with RDP — see\n  [docs/WINDOWS-VM-SETUP.md](docs/WINDOWS-VM-SETUP.md)\n\n### GPU passthrough\n\nFor ML/AI agent workflows. Works with NVIDIA RTX 3090, RTX 4090, and\nsimilar. PCI-level passthrough so the container sees the GPU directly.\nTested on bare-metal GPU nodes connected to the sentinel via tunnel.\n\n### Multi-backend\n\nA single sentinel can front:\n\n- **GCP spot VMs**: cost-effective cloud backends with auto-recovery\n  on preemption.\n- **Bare-metal GPU nodes**: any Linux box you can SSH to; reaches the\n  sentinel via outbound tunnel.\n- **Windows VMs**: live alongside Linux backends.\n\nAll containers from all backends appear in a single unified API.\n\n### Kubernetes backend (experimental)\n\nBeyond the LXC/Incus backend, Containarium can run a box as a **pod in a\nKubernetes cluster you already operate** — reached over SSH exactly like\nan LXC box, so an agent can't tell which substrate it landed on. The\ndaemon reconciles a per-tenant namespace + StatefulSet + headless Service\n+ default-deny NetworkPolicy, and programs the sshpiper gateway (the\n`Pipe` CRD) so `ssh \u003ctenant\u003e@\u003cgateway\u003e` routes to the right pod.\n\nThe pitch isn't \"another way to run pods\" — it's giving an agent a\nhardened, SSH-native foothold in your cluster **without handing it a\nkube-apiserver token**: the box runs with `automountServiceAccountToken:\nfalse` and satisfies the `restricted` Pod Security profile. Compare this\nto `kubectl exec`-based runtimes where the agent necessarily holds cluster\ncredentials.\n\n**Runtime selection** (no recompile needed):\n\n```bash\n# LXC/Incus (default)\ncontainarium daemon\n\n# Kubernetes — uses in-cluster config or KUBECONFIG\nCONTAINARIUM_RUNTIME=k8s containarium daemon\n# or\ncontainarium daemon --runtime=k8s\n```\n\nBoth backends share the same CLI, MCP tools, JWT auth, and REST/gRPC API.\nGPU passthrough is supported on K8s via `nvidia.com/gpu` resource limits.\nLocal bring-up takes under 5 minutes with `kind` — see\n[docs/KIND-QUICKSTART.md](docs/KIND-QUICKSTART.md).\n\nDesign, topology, and BYO-cluster integration:\n[docs/K8S-AGENT-BOX-RUNTIME-DESIGN.md](docs/K8S-AGENT-BOX-RUNTIME-DESIGN.md).\n\n### Web UI\n\nA basic dashboard at `/webui/` for users who'd rather not type CLI:\ncontainer list, lifecycle controls, metrics, browser-based terminal.\nPolished UI is intentionally a cloud-product concern — the OSS web UI\nis functional, not opinionated.\n\n### Persistent storage (ZFS)\n\nContainers survive VM restarts and spot termination. ZFS handles\ncompression, snapshots (daily by default, 30-day retention), and\nchecksums.\n\n### Sentinel HA\n\nThe sentinel itself is e2-micro (free tier). It:\n\n- Detects spot preemption in ~10s, serves a maintenance page.\n- Restarts spot VMs automatically (~85s total recovery).\n- Holds the static IP, so DNS doesn't change as backends rotate.\n\n### Monitoring \u0026 observability\n\nVictoriaMetrics + Grafana auto-provisioned. Per-container CPU,\nmemory, disk, network. Alerting via webhooks. SSH audit logs per\nuser.\n\n### Security primitives\n\n- **Unprivileged LXC containers**: container root ≠ host root.\n- **Per-user proxy accounts**: `/usr/sbin/nologin` on the sentinel,\n  users can only proxy through to their container.\n- **fail2ban per-user**: an attack on Alice's account doesn't ban\n  Bob.\n- **ClamAV + Trivy** scanning across all backends.\n- **AppArmor profiles** per container.\n- **AGENTBOX_ROOT sandbox** to constrain agent-box file ops at runtime.\n\n**Zero-trust controls** (rolled out across the v0.17 → unreleased line; see [`docs/security/OPERATOR-SECURITY-RUNBOOK.md`](docs/security/OPERATOR-SECURITY-RUNBOOK.md)):\n\n- **JWT with `iss` / `aud` / `jti` / `tt` / `scopes`**: 32-byte minimum\n  secret enforced at startup; refresh tokens are single-use; jti-based\n  revocation; per-tool MCP scopes propagate to server-side gates.\n- **Admin RBAC + per-container ownership** on the API surface; cluster\n  ops admin-only, container ops owner-only.\n- **KMS envelope encryption for tenant secrets** (Vault Transit or GCP\n  Cloud KMS), with a migration tool and master-key retirement gate.\n- **tmpfs `--delivery=file`** for secrets that shouldn't be visible in\n  `/proc/\u003cpid\u003e/environ`.\n- **Audit log with SHA-256 hash chain** + `containarium audit verify`\n  to detect tampering.\n- **Image-registry allowlist + pre-pull simplestreams digest\n  verification + post-pull `volatile.base_image` defense-in-depth**\n  for supply-chain hardening.\n- **`SECURITY.md`** with a 90-day coordinated-disclosure window;\n  `gosec` / `govulncheck` / `trivy` running in CI.\n\n---\n\n## CLI reference (essentials)\n\n### Container lifecycle\n\n```bash\n# Create (Ubuntu 24.04, default)\ncontainarium create alice --ssh-key ~/.ssh/id_ed25519.pub\n\n# Create with options\ncontainarium create ml-dev \\\n  --ssh-key ~/.ssh/id_ed25519.pub \\\n  --gpu 0 \\\n  --stack gpu \\\n  --memory 16GB \\\n  --cpu 4\n\n# Lifecycle\ncontainarium list\ncontainarium info\ncontainarium start alice\ncontainarium stop alice\ncontainarium delete alice\n```\n\n### Networking\n\n```bash\n# Expose a container port on a public hostname\ncontainarium expose-port alice \\\n  --container-port 8080 \\\n  --domain blog.example.com\n\n# Lower-level route management\ncontainarium route add api.example.com --target 10.0.3.42:3000\ncontainarium route list\ncontainarium route delete api.example.com\n\n# Raw TCP/UDP passthrough (no TLS termination)\ncontainarium passthrough add --port 50051 \\\n  --target-ip 10.0.3.150 --target-port 50051\n```\n\n### SSH config\n\n```bash\n# Print to stdout (preview)\ncontainarium ssh-config show\n\n# Write to ~/.containarium/ssh_config (one-line `Include` to wire in)\ncontainarium ssh-config sync\ncontainarium ssh-config sync --sentinel sentinel.example.com  # via sentinel\ncontainarium ssh-config sync --identity ~/.ssh/containarium_ed25519\n```\n\n### Authentication\n\n```bash\n# Issue an access + refresh pair (CLI-only; never exposed via API).\n# Access tokens are short-lived (default 15 min) and authenticate the\n# API. Refresh tokens are long-lived and single-use — exchange via\n# POST /v1/tokens/refresh for a new pair.\ncontainarium token generate \\\n  --username admin \\\n  --roles admin \\\n  --secret-file /etc/containarium/jwt.secret\n\n# Use the access token\ncurl -H \"Authorization: Bearer \u003caccess-token\u003e\" http://localhost:8080/v1/containers\n\n# Inspect a token's claims (jti, scopes, expiry, validation)\ncontainarium token inspect \u003ctoken\u003e --secret-file /etc/containarium/jwt.secret\n\n# Revoke a leaked token by jti (idempotent; reads from `audit query`\n# or `token inspect`)\ncontainarium token revoke \u003cjti\u003e --reason \"leak_2026_05_22\"\ncontainarium token list-revoked\n\n# Mint a least-privilege token for an agent with only the scopes it\n# needs — server-side gates enforce this even if the agent ignores\n# the filter.\ncontainarium token generate \\\n  --username alice-agent \\\n  --scopes containers:read,containers:write \\\n  --secret-file /etc/containarium/jwt.secret\n```\n\nSee [`docs/security/OPERATOR-SECURITY-RUNBOOK.md`](docs/security/OPERATOR-SECURITY-RUNBOOK.md)\nfor the full token lifecycle, leak-response playbook, and the agent\nleast-privilege scope catalog.\n\n---\n\n## Deployment\n\n### Manual install (recommended for getting started)\n\n```bash\ncurl -fsSL https://containarium.dev/install.sh | sudo bash\n```\n\nSee [`hacks/README.md`](hacks/README.md) for what the script does.\n\n### Terraform (recommended for production)\n\n```bash\ncd terraform/gce\ncp examples/single-server-spot.tfvars terraform.tfvars\nvim terraform.tfvars   # set project_id, admin_ssh_keys, allowed_ssh_sources\nterraform init\nterraform apply\n```\n\nSee [`terraform/gce/README.md`](terraform/gce/README.md) for variables.\n\n### System requirements\n\n- **Host OS**: Ubuntu 24.04 LTS or later (containers can be any\n  supported OS).\n- **Incus 6.19+** required for Docker-in-LXC support. Ubuntu 24.04's\n  default repos ship 6.0.0 which has an AppArmor bug\n  ([CVE-2025-52881](https://ubuntu.com/security/CVE-2025-52881));\n  use the [Zabbly Incus repository](https://pkgs.zabbly.com/) for\n  current builds.\n- **ZFS kernel module** (for disk quotas).\n- Kernel modules: `overlay`, `br_netfilter`, `nf_nat` (Docker in\n  containers needs these).\n\n```bash\n# Quick Incus install via Zabbly\ncurl -fsSL https://pkgs.zabbly.com/key.asc | \\\n  sudo gpg --dearmor -o /usr/share/keyrings/zabbly-incus.gpg\necho 'deb [signed-by=/usr/share/keyrings/zabbly-incus.gpg] \\\n  https://pkgs.zabbly.com/incus/stable noble main' | \\\n  sudo tee /etc/apt/sources.list.d/zabbly-incus-stable.list\nsudo apt update\nsudo apt install incus incus-tools incus-client\nincus --version  # 6.19 or later\n```\n\n---\n\n## API\n\nContainarium exposes:\n\n- **REST API** at `http://localhost:8080` (gRPC-gateway over the gRPC\n  service, JWT auth)\n- **gRPC** at `:50051` (mTLS, primarily used by the CLI)\n- **Two MCP servers**: `mcp-server` (platform) and `agent-box`\n  (in-the-box)\n\nOpenAPI / Swagger UI at\n`http://localhost:8080/swagger-ui/`.\n\nToken-issuance is **CLI-only** by design; the daemon does not have an\n\"issue token via API\" endpoint, because if it did, anyone with API\naccess could mint admin tokens.\n\n---\n\n## Hardening notes\n\n### SSH key hygiene\n\n- Each user gets their own keypair. **Never** share keys between users\n  — sharing breaks revocation, audit, and per-user fail2ban.\n- The same key can authenticate to both the sentinel proxy account and\n  the container. That's the supported flow: simpler for users, no\n  security loss because the proxy account is `nologin` and only routes\n  through.\n- To rotate: user generates a new key, admin replaces the\n  `authorized_keys` content in the container.\n\n### Agent-box sandbox\n\nIf you're running an untrusted agent, set `AGENTBOX_ROOT` to a project\ndirectory:\n\n```bash\n# In the container\nexport AGENTBOX_ROOT=/srv/project\nagent-box   # all file ops now constrained to /srv/project\n```\n\n`shell_exec` is intentionally not constrained beyond the LXC container\nboundary itself — by design, that's the tool's contract. If you need\ntighter isolation, run agent-box in a more restrictive container (e.g.\nnested LXC, or chroot the user account further).\n\n### Network\n\n- Backend VMs have **no public IP** by default; they reach out via\n  Cloud NAT and accept inbound only via sshpiper.\n- Sentinel allowlist: configure `allowed_ssh_sources` in Terraform\n  (or firewall rules manually) to lock down who can hit port 22.\n\n---\n\n## Comparison FAQ\n\n**Why not Docker / Podman?**\nDocker is for application containers. Containarium uses LXC system\ncontainers — full Linux OS per container, real `systemd`, native SSH,\nDocker-in-LXC works, persistent filesystem. If your agent will\n`apt install` and reboot, you want LXC.\n\n**Why not Kubernetes?**\nK8s orchestrates application containers across nodes — that's the\ninfrastructure layer. Containarium is the agent runtime that runs *on\ntop of* Kubernetes (or LXC), giving each agent a persistent, SSH-native\nbox without handing it cluster credentials. If you're already on K8s,\nrun `containarium daemon --runtime=k8s` and use your existing cluster as\nthe backend. See the [Kubernetes backend](#kubernetes-backend-experimental)\nsection and [docs/KIND-QUICKSTART.md](docs/KIND-QUICKSTART.md).\n\n**Why not Vagrant?**\nVagrant orchestrates VMs on a developer's local machine. Containarium\nhosts environments on shared remote infrastructure for many agents.\n\n**Why not Dev Containers / VS Code Remote Containers?**\nDev Containers are project-scoped, IDE-coupled, single-developer.\nContainarium gives many users (or many of one user's agents) their own\npersistent boxes on shared infrastructure, IDE-agnostic.\n\n**Why not Codespaces / Gitpod?**\nBrowser-IDE-as-a-Service, per-hour billed, vendor-locked. Containarium\nis self-hosted, persistent, SSH/MCP-based, no per-hour billing in OSS.\n\n**Why not e2b / Modal / Daytona?**\nClosest peers — sandboxes for AI agents. They're SaaS-only and\ntypically optimize for short-lived, process-per-call execution.\nContainarium is self-hostable, MCP-native, and gives you full\npersistent Linux boxes. Pick e2b if you want hosted-only and\nephemeral; pick Containarium if you want self-hosted, persistent,\nand your data on your infra.\n\n**Why LXC at all?**\n- Each container runs a full Linux OS with `systemd`.\n- SSH access is first-class.\n- Docker-in-LXC works (vs. fragile Docker-in-Docker).\n- Real persistent filesystem, real users, real `sudo`.\n- \"Feels like a VM\" for the agent — same surface area as a managed\n  cloud VM, fraction of the resource cost.\n\n---\n\n## Use cases\n\n- **AI-agent sandboxes** (the lead): Cursor, Claude Code, Cline,\n  OpenCode, custom agents — all reach the same MCP surface.\n- **Shared developer environments**: many developers, one host, SSH\n  jump server with per-user isolation.\n- **ML / GPU experimentation**: GPU passthrough into LXC.\n- **Education, bootcamps, workshops**: per-student isolated Linux\n  with no per-student VM.\n- **CI / build infrastructure**: long-lived build hosts that keep\n  caches warm across runs.\n- **Demo / testing infrastructure**: spin up a real Linux env, test,\n  tear down.\n\n---\n\n## In the wild\n\nWhere Containarium has been demonstrated live:\n\n- **2026-06-04 — AI Agent Night, Taipei.** When the grand-prize\n  giveaway (a custom vibe-keyboard) hit a snag — the event had no way\n  to run the lucky draw — we fired up Containarium and vibe-coded a\n  lucky-draw picker on the spot to save the giveaway. Still live:\n  [lucky-draw.demo.containarium.dev](https://lucky-draw.demo.containarium.dev/).\n\nDemoed Containarium somewhere? Open a PR and add it here.\n\n---\n\n## Status\n\n- **Production-deployed** on GCP (multi-region) and bare-metal GPU\n  nodes.\n- **APIs are stable** (protobuf-defined with gRPC-gateway).\n- **Apache 2.0**, no CLA, accepting community PRs.\n- Active maintenance: see commit history on `main` and recent\n  releases.\n\n---\n\n## Roadmap\n\n- **Shipped (2026-06)**: **[Kubernetes backend](#kubernetes-backend-experimental)**\n  — run a box as a pod in a cluster you operate, reached over SSH like an LXC\n  box, with the sshpiper gateway, default-deny NetworkPolicy, CSI storage, and\n  `nvidia.com/gpu` passthrough. Selected at runtime via `--runtime=k8s` (no\n  recompile). End-to-end validated on `kind`; 5-minute local bring-up in\n  [docs/KIND-QUICKSTART.md](docs/KIND-QUICKSTART.md). See also\n  [docs/K8S-AGENT-BOX-RUNTIME-DESIGN.md](docs/K8S-AGENT-BOX-RUNTIME-DESIGN.md).\n- **Q2 2026 (in flight)**: `agent-box` MCP, `ssh-config` CLI,\n  `expose-port` CLI, demo recording.\n- **Q3 2026**: `agent-box` tier-2 (MCP Roots, background process\n  management), demo-driven docs and examples.\n- **Q4 2026**: OSS v1.0 cut — stable API surface, contribution\n  guide.\n\nIf you want to drive an item, open an issue or PR — community work is\nwelcome and we triage weekly.\n\n---\n\n## Contributing\n\n- Read [CLAUDE.md](CLAUDE.md) for the CLI-first principle (every new\n  platform action lands as `containarium \u003cverb\u003e` first; MCP wraps it).\n- Check [existing issues and PRs](https://github.com/footprintai/Containarium/issues).\n- Add tests for new features.\n- Update docs if user-visible behavior changes.\n\nNo CLA. Apache 2.0 means you can use, modify, and redistribute. We\nwelcome PRs that align with the project's positioning and reject\nthose that don't (e.g. \"let me add multi-tenancy to the OSS daemon\"\ngoes into the cloud repo discussion, not here).\n\n---\n\n## License\n\nApache License 2.0 — see [LICENSE](LICENSE).\n\n---\n\n## Acknowledgments\n\n- [Incus](https://linuxcontainers.org/incus/) — modern LXC manager.\n- [sshpiper](https://github.com/tg123/sshpiper) — SSH reverse proxy.\n- [mcp-go](https://github.com/mark3labs/mcp-go) — Go MCP server library.\n- [Caddy](https://caddyserver.com/) — TLS / reverse proxy with\n  PROXY-protocol support.\n- [Cobra](https://cobra.dev/) — CLI framework.\n- [Terraform](https://terraform.io/) — infrastructure as code.\n\n---\n\n## Support\n\n- **Project site**: [containarium.dev](https://containarium.dev) — overview, hosted cloud, GitHub Action for CI, PR previews.\n- **Documentation**: [docs/](docs/) directory.\n- **Issues**: [GitHub Issues](https://github.com/footprintai/Containarium/issues).\n- **Demo video**: [55s walkthrough on YouTube](https://youtu.be/IBDDD_tb8FY).\n- **Live demo app**: [helloworld.demo.containarium.dev](https://helloworld.demo.containarium.dev).\n- **Organization**: [FootprintAI](https://github.com/footprintai).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFootprintAI%2FContainarium","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFootprintAI%2FContainarium","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFootprintAI%2FContainarium/lists"}