| title | Self-hosted environments quickstart |
|---|---|
| source | https://code.claude.com/docs/en/self-hosted-environments-quickstart |
| category | code |
| generated | true |
Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt Use this file to discover all available pages before exploring further.
Self-hosted environments are in public beta on Team and Enterprise plans; [Availability and limitations](/docs/en/self-hosted-environments#availability-and-limitations) covers the enablement path. This page gets your first session running; see [Self-hosted environments](/docs/en/self-hosted-environments) for what they are and [Deploy to production](/docs/en/self-hosted-environments-deploy) for hardening and fleet recipes.Set up your first self-hosted environment: install Claude Code, create the environment, start a runner, and route a session to it.
A self-hosted environment runs Claude Code cloud sessions on infrastructure your organization operates, executed by runner processes you deploy. This quickstart stands up your first one, the smallest that works: one runner on a single host, running one test session. There are two steps: create the environment, start a runner, and route a session to it, then message that session from your terminal. You'll move between two surfaces: claude.ai for creating the environment, checking its status, and routing a session, and a terminal on the host for everything the runner does.
By the end you'll have an environment on the Cloud environments admin page, a runner polling for work, and a session running on your host. Before you connect real repositories or internal systems, work through Deploy to production, which covers the security posture, egress control, git credentials, and orchestration.
The claude.ai side needs:
- Allow self-hosted environments turned on by an Owner on the Cloud environments admin page; the New button doesn't appear until it is. If you don't hold the role, someone who does can create the environment and hand you its secret; the runner and terminal steps on this page need no claude.ai role, and where a step checks status in the admin UI, the runner's own log lines give you the same signal.
- The GitHub connector turned on by an Owner, and each developer's own GitHub connection, so they can pick github.com repositories when they start sessions.
The runner host needs:
- A Linux or macOS host or container with outbound HTTPS to
api.anthropic.com, toclaude.aiand the download hosts it redirects to for the install step below, and to your git host for the clone; the network requirements table has the full list. Windows isn't supported as a runner host; run the runner in a Linux container instead. Developer workstations aren't affected, since sessions start from claude.ai in a browser. - A repository for the test session: a public one, or one this host can already clone by its HTTPS URL without being asked for credentials. An SSH key alone isn't enough, because the runner clones the repository's
https://URL. To clone over SSH instead, see Rewrite git URLs for private networks. - A clock synchronized to real time, for example with NTP. Authentication fails when the clock is more than five minutes off; see Troubleshooting.
Install on the host before you start:
- Claude Code v2.1.224 or later, with any of the standard install methods. The runner is part of the standard
claudebinary, and earlier versions don't recognize theself-hosted-runnersubcommand. The native installer's defaultlatestchannel carries each release as soon as it's published; thestablechannel, the Homebrewclaude-codecask, and the stable apt, dnf, and apk repositories trail by about a week. To pin the exact version your fleet runs, see Install a specific version. For container images, see the Dockerfile in Deploy to production. - Git 2.24 or newer. Some git options on the deploy page need newer versions; Configure git states each floor.
Confirm the host is ready:
claude self-hosted-runner --helpA ready host prints the runner's usage text, listing flags such as --environment-secret-file. On versions older than 2.1.224, the command prints the general claude --help output instead; upgrade with claude update or reinstall from the latest channel.
Use either the guided setup or the manual steps. The guided setup is a single command that starts an interactive Claude Code session and walks you through the rest. Use the manual steps instead on a host where an interactive session isn't possible. Also use them when someone who holds the Owner role created the environment and handed you its secret, since the guided setup needs an Owner sign-in.
The guided setup walks you through creating the environment in the admin UI, starts a local runner with the secret file you save, confirms that the runner registers, and writes a cheat sheet to ./runner-setup/CHEAT-SHEET.md. Before you run it, confirm your sign-in and version:
- Sign-in: run it on a machine where you've signed in with
claude auth loginusing an account that holds an Owner role. With only an API key or a third-party model provider, the session starts but its organization checks fail. - Version: confirm the version check passed. On versions older than 2.1.224, the setup command starts a Claude session with the words as the prompt instead of the guided setup.
To start the guided setup, run the setup subcommand in your shell and follow the prompts:
claude self-hosted-runner setupThe setup doesn't start a test session itself: it tells you to start one at claude.ai/code. The setup's last step stops the runner it started. If you leave the setup before that step, the runner keeps running. To keep going after the last step, start the runner again in your shell with the command in ./runner-setup/CHEAT-SHEET.md, then route a session to the environment.
Create the environment on claude.ai, start the runner from a terminal on the host, then return to claude.ai to confirm the runner appears and route a session to it. If someone who holds the Owner role already created the environment and handed you its secret, start at step 2.
Go to the [**Cloud environments** page](https://claude.ai/admin-settings/cloud-environments) in admin settings. Under **Self-hosted environments**, select **New**, name the environment, and select **Create**. On the wizard's second step, select **Copy environment key** to copy the environment secret, which the admin UI labels an environment key. claude.ai shows the secret once, and you can't retrieve it later; it expires 365 days after creation. The environment's `ccpool_...` ID stays visible in its detail dialog; you'll need it for the `aud` check in [token verification](/docs/en/self-hosted-environments-identity) and for dispatching [test sessions from CI](/docs/en/self-hosted-environments-testing#run-the-test-loop).If you lose the secret or need to rotate it, create a new secret from the environment's **Configuration** tab, roll the new secret out to your runners, then revoke the old one. Runners holding a revoked secret fail their next authenticated poll and exit, logging `poll auth failed`, and your orchestrator restarts them with the new secret.
```bash theme={null}
mkdir -p /etc/claude
```
Write the environment secret to a file. The command below reads from your terminal so the secret stays out of shell history: paste the value you copied, press Enter, then Ctrl-D, and the subshell's `umask` makes the file readable only by its owner.
```bash theme={null}
(umask 077 && cat > /etc/claude/environment-secret)
```
Choose a base directory, replacing `<writable-dir>` in the runner command below with an absolute path that the runner can write to or create. The runner creates the directory at startup, then checks repositories out and creates per-session directories under it. Without `--base-dir` it uses `/workspace`, which only works if that directory already exists and is writable or you start the runner as root.
<Warning>
Use a directory dedicated to the runner, not your home directory or a directory of your own clones. The runner treats whatever it finds at `<writable-dir>/<repo-owner>/<repo>` as its own clone, and can reset it and overwrite or delete files in it.
</Warning>
If the runner can't create or write to the base directory, it exits at startup with an error naming the directory instead of registering. See [Troubleshooting](/docs/en/self-hosted-environments-deploy#troubleshooting).
Then start the runner with `--environment-secret-file` and `--base-dir`:
```bash theme={null}
claude self-hosted-runner --environment-secret-file '/etc/claude/environment-secret' --base-dir '<writable-dir>'
```
The runner logs `Registered: runner_id=<runner-id>` once it has registered with your environment, then begins polling for work. Started with this command, it exits by design after serving one session, not after each turn. To serve more sessions, start the runner again each time it exits. See [If the runner exits](#if-the-runner-exits) for when that happens and what the runner logs.
The next available runner picks up the queued session and logs `Picked up session <session-id>` along with its active count and capacity, so you can confirm from the runner's own output which host took the session. Watch the session work and read Claude's replies at [claude.ai/code](https://claude.ai/code).
<span id="session-doesnt-start" />If the session doesn't start working, match what you see:
* **The session sits queued**: see [Troubleshooting](/docs/en/self-hosted-environments-deploy#troubleshooting).
* **The session fails to start with a git error**: if the error includes git's `could not read Username for` followed by your git host's URL, the runner had no HTTPS credentials for that host.
* **Supply HTTPS credentials**: see [Configure git](/docs/en/self-hosted-environments-deploy#configure-git)
* **Clone over SSH instead**: if the runner host already has an SSH key, see [Rewrite git URLs for private networks](/docs/en/self-hosted-environments-deploy#rewrite-git-urls-for-private-networks)
If the runner exits during this quickstart, start it again. The runner can exit on its own:
- Nothing left running: the log shows
[runner:exit] account workload drained — exiting. The runner exits by design once it's no longer running any session, for example:- You archived or deleted the session: start the runner again
- The session failed to start: fix the cause, then start the runner again
- Lost contact: the log shows a
[runner:fatal]line withrunner record gone server-sideor withpoll auth failed. If the runner loses contact with Anthropic for a while, for example because the host sleeps, it can exit when it next reaches Anthropic.
A finished turn doesn't end your test session. After the first turn the session is still attached and the runner is still up, so you can send the session a follow-up message without restarting the runner first.
For production, deploy the runner under an orchestrator that restarts it on exit and waits longer between restarts when the runner keeps exiting right after it starts. See Deploy to production and When the runner exits.
Once a session is running on your environment, send it a follow-up from the claude CLI on any machine where you're logged in with claude auth login; the command doesn't need to run from the machine that started the session. The command posts one message:
claude -p "your message" --cloud <session-id>For <session-id>, pass the bare session_... or cse_... ID or the session's claude.ai/code URL. A successful send prints Sent to cloud session. with the session ID and a view link. Accepted ID forms, JSON output, and the account and policy requirements are on Send follow-ups from the CLI, since the command works the same against Anthropic-hosted sessions.
- Deploy to production: harden the deployment, control egress, configure git credentials, and run the fleet under Kubernetes or Compose
- Customize sessions: wrapper scripts, lifecycle hooks, on-demand runners, MCP servers, and permissions
- Test end to end: a CI smoke test that dispatches a session and reads Claude's replies