# Enrolling your first host

The control plane only knows about hosts you've explicitly
enrolled. Two paths exist:

1. **Token-based enrolment** — admin generates a token, pastes it
   into an install command on the host. The host appears immediately,
   already mapped to the desired repo.
2. **Announce-and-approve** — the agent runs without a token,
   "announces" itself to the server, and a human in the UI accepts
   the announcement.

Token-based is the default and what most operators want; the
announce flow exists for the case where you can't easily paste a
secret onto the host (auto-imaged endpoints, scripted bring-ups
from a config repo).

## Token-based enrolment

### From the UI

1. Click **+ Add host** on the dashboard.
2. Fill in the hostname, the restic repo URL, and the repo
   credentials. The credentials are AEAD-encrypted at the server
   immediately; what you paste is what the agent receives.
3. Optionally pick the initial source paths — these become the
   first source group on the host.
4. Submit. The server mints a one-time token and shows you a copy-
   pasteable install snippet.

### On the host (Linux)

```sh
curl -fsSL https://restic.example.com/install/install.sh | \
    sudo RM_SERVER=https://restic.example.com \
         RM_ENROL_TOKEN=<token> \
         bash
```

The script:

1. Detects architecture (`amd64` or `arm64`).
2. Downloads the agent binary from `/agent/binary?os=…&arch=…`.
3. Drops the systemd unit at
   `/etc/systemd/system/restic-manager-agent.service`.
4. Runs the agent in `-enrol` mode, which posts the token and
   stores the persistent bearer it gets back.
5. Enables and starts the unit.

Within seconds the host should appear on the dashboard as
**online**.

### On the host (Windows)

```pwsh
$env:RM_SERVER  = "https://restic.example.com"
$env:RM_ENROL_TOKEN = "<token>"
iwr -useb $env:RM_SERVER/install/install.ps1 | iex
```

Equivalent shape: registers a Windows service via the SCM
(see P2-16 for details), runs `-enrol`, starts the service.

## Recovering a lost token

Tokens are single-use and short-lived (1h). If you closed the tab
before pasting the install command, head to the **Add host** page —
outstanding tokens are listed there with a **Regenerate** button.
Regenerating revokes the old token's hash and mints a fresh raw
token while preserving the original repo credentials and initial
paths. (NS-02 in `tasks.md` if you want the design rationale.)

## Announce-and-approve

If the host can reach the server but you don't want to paste a
secret on it, run the agent in `-announce` mode:

```sh
restic-manager-agent -announce \
                     -server https://restic.example.com \
                     -hostname myhost
```

The host appears in the **Pending hosts** panel on the dashboard
with its hostname, OS, arch, and the source IP that announced it.
Click **Accept**, fill in the repo URL + credentials, and the
server pushes the bearer over the still-open WebSocket. No
back-and-forth round trip.

If you don't accept within an hour the announcement is swept.

## What happens on the agent

After enrolment, the agent:

1. Connects via WebSocket to `/ws/agent` with its bearer token.
2. Sends a `hello` envelope with its OS, arch, agent version,
   restic version, and protocol version.
3. Receives a `config.update` carrying its encrypted repo
   credentials and any source-group paths.
4. Sits idle, sending a heartbeat every 30s. Operator-driven
   "Run now" actions arrive as `command.run` envelopes; scheduled
   jobs are driven by the agent's local cron.

## Auto-init of the repository

The first time a backup runs, the agent invokes `restic init`
against the repo you configured at enrolment. If the repo already
exists (`config file already exists`) the agent treats it as a
success and proceeds. The host's repo status (`unknown` →
`ready` / `init_failed`) is surfaced under the vitals strip on
the host detail page; if init fails, save fresh credentials in
the **Repo** tab to retry.
