# Install on your own server (/docs/environments/byo-install)

Enrol any Linux machine you control as a free environment with the codaid daemon — install, enrol, run as a service.

A **bring-your-own** (BYO) environment is a machine you already have — a VPS, a home server, a spare workstation. You install `codaid`, enrol it with a one-time token, and it connects outbound to the relay. BYO environments are free and available to every key.

## Supported platforms [#supported-platforms]

| Platform | Binary | Installer | Service |
| --- | --- | --- | --- |
| Linux x86_64 / aarch64 | `codaid-linux-x86_64`, `codaid-linux-aarch64` (static musl) | `install.sh` | systemd (`codaid.service`) |
| Windows x86_64 | `codaid.exe` (zip in the release) | `install.ps1` — see [codaid CLI](./codaid.mdx) | None — run `codaid run` yourself |
| macOS | Not published yet | The installer accepts `darwin`, but no binary is released — coming soon | None |

Per-member Linux accounts and container isolation need Linux with root; see [team environments](./team.mdx).

<Steps>
<Step>

### Create the environment and get a token [#create-the-environment-and-get-a-token]

**Hub:** open [hub.codai.ro/projects](https://hub.codai.ro/projects), create a project, then **New environment → Bring your own machine**. On the environment page choose **Generate enrol token**; the token is single-use and valid for 30 minutes, and the page shows the exact install command.

**CLI:** with `CODAI_API_KEY` set (or a key in `~/.codai/codaid.json`):

```bash
codaid env create --project my-app --name dev-box
# prints the environment and:
#   curl -fsSL https://codai.ro/install-codaid.sh | CODAI_ENROLL_TOKEN=codai_env_… sh
```

**API:** `POST /v1/environments` with `"provider": "byo"`, then `POST /v1/environments/{id}/enroll-token` — see the [API page](./api.mdx).

</Step>
<Step>

### Install and enrol (Linux) [#install-and-enrol-linux]

Run on the machine, as a user with `sudo`:

```bash
curl -fsSL https://github.com/codai-ro/codaid/releases/latest/download/install.sh \
  | CODAI_ENROLL_TOKEN=codai_env_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX sh
```

The installer downloads the binary for your architecture to `/usr/local/bin/codaid` (verifying it against the release's `SHA256SUMS` and refusing to install when the checksum is missing or differs), runs `codaid enroll`, and — when systemd is running — installs and starts `codaid.service` for the invoking user. It needs `curl` or `wget`.

Because a BYO environment carries no API key of its own, `codaid enroll` then starts a **device-code sign-in**: it prints a URL and a code, you approve it in the browser on any device, and the daemon stores the resulting key. Pass `CODAI_API_KEY=codai_…` to skip that step (useful for fleets).

| Installer variable | Effect |
| --- | --- |
| `CODAI_ENROLL_TOKEN` | Enrol after installing (omit to install only). |
| `CODAI_SERVICE_SCOPE=system` | Root-owned unit running with home `/var/lib/codai`; enables per-member Linux accounts. |
| `CODAI_IDENTITY=shared` | With `system` scope: one service account `codai` for everybody instead of one Linux user per member. |
| `CODAI_API_KEY` | Use this key instead of the device-code sign-in. |
| `VERSION` | Pin a release, e.g. `VERSION=0.3.3`; default `latest`. |
| `INSTALL_DIR` | Binary location; default `/usr/local/bin`. |
| `CODAI_GATEWAY_URL`, `CODAI_AUTH_URL`, `CODAI_RELAY_URL`, `CODAID_WORKSPACE` | Passed through to `codaid enroll`. |

The same script is mirrored at `https://codai.ro/install-codaid.sh`; the GitHub release URL is always the newest.

</Step>
<Step>

### Or enrol by hand [#or-enrol-by-hand]

```bash
codaid enroll --token codai_env_… [--api-key codai_…] [--workspace /srv/app]
codaid run            # foreground; Ctrl-C stops it
codaid status         # JSON: config (key redacted), workspace, git, listening ports, identity, locks
```

`enroll` writes `~/.codai/codaid.json` (directory `0700`, file `0600`) with the device id, API key, environment id and relay URL. Re-enrolling keeps the same device id. The key is never printed — `status` shows only its prefix and length.

On **Windows**, install with `irm https://codai.ro/install-codaid.ps1 | iex` ([codaid CLI](./codaid.mdx)), then run `codaid enroll --token …` and `codaid run` in a terminal. Shell commands execute in PowerShell. There is no Windows service yet.

</Step>
<Step>

### Run as a service [#run-as-a-service]

```bash
# unit for your own user (what the installer does)
codaid install-service --user "$USER" | sudo tee /etc/systemd/system/codaid.service
sudo systemctl daemon-reload && sudo systemctl enable --now codaid

# system unit (root): per-member Linux accounts, shared repos, per-repo build lock
sudo codaid install-service --system [--identity per-user|shared] [--user codai] [--home /var/lib/codai]
```

`--system` must run as root on Linux with systemd; it creates the service user and, in `per-user` mode, the `codai-dev` group plus `/srv/codai/repos` and `/var/lib/codai/locks`. If the machine is not enrolled yet it prints the `sudo CODAI_HOME=/var/lib/codai/.codai codaid enroll …` command to run next. The unit restarts on failure every 5 s.

</Step>
<Step>

### Check it is online [#check-it-is-online]

```bash
codaid env status dev-box      # online=true, daemon version, ports, git branch
```

The hub shows **Daemon connected**, and the desktop Environments view shows a green dot. The daemon sends a heartbeat every 15 s and reconnects with back-off (1 s → 30 s) whenever the socket drops; the relay closes every WebSocket after one hour and the daemon reconnects immediately.

</Step>
</Steps>

## What the daemon can do [#what-the-daemon-can-do]

Everything goes through the relay; the daemon never listens on a port.

| Capability | Notes |
| --- | --- |
| `shell` | `bash -lc` (PowerShell on Windows). Default timeout 60 s, maximum 10 min; up to 64 KB per output stream; the whole process tree is killed on timeout. |
| `fs_read`, `fs_write`, `fs_list`, `fs_roots` | Confined to the workspace root (or the member's worktree); symlink escapes are refused. |
| Terminals (`pty`) | Interactive shell in the workspace, resizable. |
| Port streams (`tcp`, `http`) | Connect to `127.0.0.1:<port>` inside the machine — used by previews and `codaid env forward`. |
| Reports | Listening ports every 15 s, git state (branch, dirty, ahead/behind, worktrees) every 30 s, activity (`idle`, `human`, `agent`) and held locks with each heartbeat. |

<Callout type="warn">
`shell` is not confined to the workspace — it runs with the privileges of the Linux account it executes as. In `shared` identity mode every member runs as the same account, so treat the machine as untrusted for secrets. Use `CODAI_SERVICE_SCOPE=system` with the default `per-user` identity when several people share a machine.
</Callout>

## Files and variables [#files-and-variables]

| Item | Location |
| --- | --- |
| Config | `~/.codai/codaid.json` (`$CODAI_HOME` overrides `~/.codai`); system scope `/var/lib/codai/.codai/codaid.json` |
| Workspace root | `workspace` in the config → `$CODAID_WORKSPACE` → `/workspace` if it exists → the home directory |
| Build locks | `$CODAI_HOME/locks` (shared) or `/var/lib/codai/locks` (per-user) |
| Log level | `CODAID_LOG` (default `info`) |
