ClaudeMap

·Skills & Commands

A 2026 guide to Claude Code self-hosted environments — the Environment/Runner/Session model, outbound-only security boundary, quickstart commands, Kubernetes and Compose deployment with drain control, and why model traffic can't route through Bedrock or an LLM gateway.

Claude Code Self-Hosted Environments: Run Cloud Sessions on Your Own Compute (2026)

Claude Code self-hosted environments are a deployment mode where cloud-initiated coding sessions are executed by a runner process on your own machines — code checkouts, builds, and secrets stay on your infrastructure while Anthropic hosts only the control plane. The feature entered public beta on August 7, 2026 (v2.1.224) and the official docs are still evolving quickly. Based on the documentation as of September 2026, this guide covers the concept model, the full path from zero to a first session, production deployment, and the security boundary.

TL;DR

  • Three concepts: Environment (a named runner group), Runner (a resident process on your host), Session (one task)
  • The control plane is Anthropic's; every connection is outbound HTTPS from the runner — no inbound ports
  • Four steps: claude self-hosted-runner setup → store the environment key → start the runner → pick the environment in claude.ai/code
  • Code, artifacts, and secrets never leave your machines; model traffic can't be rerouted to Bedrock / Vertex / an LLM gateway either
  • For production, use the official Kubernetes / Compose recipes and control draining with --drain-grace-sec

The concept model: Environment, Runner, Session

Three roles, cleanly separated:

| Concept | What it is | Analogy | |---|---|---| | Environment | A named group of runners, created in the claude.ai admin UI | a CI runner fleet | | Runner | A resident process on your host that claims and runs sessions | a self-hosted CI runner | | Session | One concrete coding task, initiated from web/desktop | one CI job |

The key difference from running Claude Code automation on GitHub Actions: Actions are event-driven, stateless jobs (PR triggers, ephemeral execution), while self-hosted environments carry interactive long-lived sessions — you start one at claude.ai/code, it routes to your runner, and you can continue it from phone or browser at any time. What happens to disk state after a session ends is a deployment decision.

The control plane is Anthropic-hosted, but every connection is initiated outbound by the runner over HTTPS — Anthropic never dials into your network. That asymmetry is the foundation of the whole security model.

Quickstart: zero to first session

Prerequisite: Claude Code ≥ v2.1.224. Confirm the binary has the runner subcommand:

claude self-hosted-runner --help
# if it prints generic claude --help instead, upgrade first:
claude update

Step 1: create an Environment. In the claude.ai Cloud environments admin page, select New under Self-hosted environments, name it, and create. On the wizard's second step, Copy environment key — the secret is shown once and expires after 365 days.

Step 2: store the key on the runner host.

mkdir -p /etc/claude
(umask 077 && cat > /etc/claude/environment-secret)
# paste the key, press Enter, then Ctrl-D

umask 077 makes the file readable only by the current user — this is the documented approach verbatim; don't skip it.

Step 3: start the runner.

claude self-hosted-runner --environment-secret-file '/etc/claude/environment-secret' --base-dir '<writable-dir>'

Back in the admin page, the environment status should flip from "No runners deployed" to Healthy within seconds.

Step 4: route a first session. Start a session at claude.ai/code and pick your environment in the picker; the runner logs Picked up session <session-id> when it claims the work. You can even append messages to a session from your local CLI:

claude -p "your message" --cloud <session-id>

The lazy path: run claude self-hosted-runner setup and the guided setup walks you through all of the above.

Production: from one box to orchestration

A single runner is fine for evaluation; production needs lifecycle and scaling answers. The official deploy page ships native Kubernetes and Docker Compose recipes. Three things matter most:

Images and version pinning. Pin the Claude Code version inside the runner image to avoid environment drift; pre-warming common repo checkouts measurably cuts session start time.

Draining and restarts. Runner lifecycle is controlled with --drain-grace-sec: the default of 0 means drain immediately on the stop signal, so Kubernetes can restart runners with fresh disks — stateless and rebuildable by design. --retire-at <epoch-seconds> retires a runner at a scheduled time, and --defer-shutdown-max-min (v2.1.238+) can postpone shutdown to a session boundary.

Autoscaling. Anthropic supports running an autoscaling orchestrator that starts runners as sessions queue — you don't need to hand-write HPA logic.

The security boundary: what stays on your machines, and what can't be rerouted

  • Outbound only. Runner-to-control-plane traffic is all outbound HTTPS; corporate networks connect via HTTPS_PROXY / NO_PROXY (mTLS and Proxy-Authorization header injection supported, v2.1.248+).
  • Data residency. Checkouts, build artifacts, and secrets stay on your machines; the Anthropic side holds session orchestration only.
  • Minimal inference auth. Runners receive session-scoped OAuth tokens used solely for inference calls.
  • Model traffic can't be rerouted. Model calls from self-hosted environments cannot route through Bedrock, Vertex, Agent Platform, Foundry, or a self-hosted LLM gateway — a hard boundary in the current version; write it into your compliance assessment.
  • Four git credential options (including per-session minted credentials and the Anthropic git proxy) — pick per your git host instead of baking a long-lived PAT into the runner.

Common pitfalls

Pitfall 1: the self-hosted-runner subcommand doesn't exist. Older builds silently print the generic help. Run claude update — the subcommand arrived in v2.1.224.

Pitfall 2: the environment key is gone. It's shown once and expires in 365 days. Regenerate it, and remember every runner host needs the new key.

Pitfall 3: the runner never turns Healthy. A corporate firewall blocking outbound access is the most common cause — check the proxy and domain allowlist against the deploy docs; claude --debug shows the runner-side handshake logs.

Pitfall 4: sessions interrupted by Kubernetes restarts. The default --drain-grace-sec 0 is by design (fresh-disk restarts are cleaner), not a bug; hosts running long sessions want --defer-shutdown-max-min to wait out the session.

Pitfall 5: routing through your own model gateway. You can't (see the security boundary) — don't let procurement assume otherwise.

Related guides

Frequently asked questions

How is a self-hosted environment different from running the claude CLI in a container?

Running claude -p in a container is a one-shot call that you initiate and orchestrate; a self-hosted environment is an interactive session where Anthropic hosts the control plane and you supply the compute — started from claude.ai/code or your phone, routed to your runner, continuable across devices. The former fits CI steps; the latter brings the cloud Claude Code experience onto your own infrastructure.

Does the runner need inbound ports open?

No. Every connection is initiated outbound by the runner over HTTPS; Anthropic never dials into your network. That is the core difference from traditional self-hosted setups that expose webhooks.

What if the environment secret is lost or expires?

Regenerate it in the admin page and update /etc/claude/environment-secret on every runner host. It's shown once at creation and expires after 365 days — put the rotation on a calendar instead of waiting for the fleet to drop offline.

Do session code and secrets pass through Anthropic?

No. Checkouts, build artifacts, and secrets stay on your machines; the control plane handles session orchestration only. Inference requests go outbound from the runner to the model API, authenticated with a session-scoped OAuth token.

Can model traffic go through our Bedrock / Vertex endpoint or LLM gateway?

Not in the current version — model calls from self-hosted environments are restricted to Anthropic-hosted endpoints; the Bedrock / Vertex / Foundry / gateway routes are not supported. For those requirements, evaluate running the CLI in containers instead.

Which teams should actually use self-hosted environments?

Two profiles fit best: teams whose compliance rules require data to stay inside their network (the outbound-only model usually survives security review), and teams that want the cloud session experience on their own compute, including bare-metal or specialized hardware. If you just want Claude in CI, the GitHub Actions route is simpler.

Official references

This article reflects the public documentation as of September 2, 2026 (v2.1.251). The feature is in public beta and evolving quickly — the official docs win.