Pair hosts when they start instead of in the installer

The installer only writes the controller URL and host name. Running the
host requests to join the cluster if it has not been approved yet, or if
the controller no longer accepts its token, and waits until an admin
approves it. Once approved it saves its id and token and starts as
normal. A rejected host exits with code 8.

clusteriohost run --user-token approves the host right away with the
token of a user allowed to approve hosts. The token is not saved.

This moves the pairing client into the host package, where it uses the
same certificate setup as the host's connection to the controller, and
removes --no-pair and the rerun handling from the installer.
This commit is contained in:
Danielv123 committed 2026-10-30 21:13:14 +01:00
1 parent 37e79d9c41
commit 4a49a198f0
25 files changed
+948 -1131

No files matched your search

+4 -3
View File
@@ -327,7 +327,7 @@ Defaults to "New Host".
### host.id
Immutable numeric id of the host which uniquely identifies this host in the cluster.
The controller picks the id when the host is approved and the installer writes it here, the controller does not accept hosts with an id it has not approved.
The controller picks the id when the host is approved and the host writes it here, the controller does not accept hosts with an id it has not approved.
Hidden in the web interface.
Defaults to a random 31 bit number.
@@ -367,8 +367,9 @@ Defaults to "http://localhost:8080/".
### host.controller_token
Access token used for authenticating with the controller.
The installer writes it together with host.id when the host is approved, see [Setting up remote hosts](/README.md#setting-up-remote-hosts).
The token only works while the host exists on the controller, if the host is revoked run the installer again in the host directory to get it approved again.
The host saves it together with host.id when it is approved, see [Setting up remote hosts](/README.md#setting-up-remote-hosts).
The token only works while the host exists on the controller, if the host is revoked it asks to be approved again the next time it starts.
Set it to `enter token here` to make the host ask to join again, for example after changing host.controller_url to another controller.
The value can only be read and changed from the host itself.
Defaults to "enter token here".
+2 -2
View File
@@ -64,7 +64,7 @@ The `container` property of `WebPluginContext` is now the plugin's ES module nam
## Host pairing
Host tokens are no longer generated by users.
A host joins the cluster by running the installer and having the code it shows approved, see [Host pairing](protocol.md#host-pairing) for the HTTP endpoints it uses.
A host joins the cluster by having the code it shows when it first starts approved, see [Host pairing](protocol.md#host-pairing) for the HTTP endpoints it uses.
- `HostGenerateTokenRequest` and `HostConfigCreateRequest` are removed.
Pending requests are listed with `HostPairingListRequest`, approved with `HostPairingApproveRequest` and rejected with `HostPairingRejectRequest`, and changes to them are sent to subscribers of `HostPairingUpdatesEvent`.
@@ -72,7 +72,7 @@ A host joins the cluster by running the installer and having the code it shows a
It throws `ConflictError` while instances are assigned to the host.
- The permissions `core.host.generate_token`, `core.host.revoke_token` and `core.host.create_config` are removed.
Check `core.host.approve` and `core.host.revoke` instead.
- `clusteriocontroller bootstrap generate-host-token` is removed, scripts that set up hosts should run the installer with `--controller-token` to approve the host with a user token.
- `clusteriocontroller bootstrap generate-host-token` is removed, scripts that set up hosts can start the host with `--user-token` to approve it with a user token.
Host records are no longer created when a host connects, only by approving it, and the controller rejects hosts it has no record of.
Revoking a host deletes its record and note.
+7 -6
View File
@@ -34,9 +34,9 @@ The [send-buffer setting](../configuration.md#controllermax_send_buffer_size) co
## Host pairing
The host id and token sent in `registerHost` come from the installer, which gets them from the controller over HTTP before the host is started.
The host id and token sent in `registerHost` are requested by the host over HTTP the first time it starts, before it connects.
Hosts are only added to the controller by approving a pairing request, and `registerHost` is rejected with close code 3000 (Unauthorized) for a host id the controller has no record of.
Revoking a host deletes its record, so its token stops working and the installer has to pair it again, which gives it a new id.
Revoking a host deletes its record, so its token stops working and the host has to be approved again the next time it starts, which gives it a new id.
See [Setting up remote hosts](/README.md#setting-up-remote-hosts) for how this looks to the user.
The endpoints below take and return JSON bodies and are sent with `Cache-Control: no-store`.
@@ -50,7 +50,7 @@ A user or host token is sent in either an `Authorization: Bearer <token>` header
Creates a request for a host to join the cluster.
- `name: string` - Name of the host, at most 100 characters after trimming whitespace, without control characters.
- `version: string` (optional) - Version of the installer.
- `version: string` (optional) - Version of the host.
Responds with 202 and `{"requestId": string, "code": string}`.
The `code` is shown to the user to approve the request with, formatted as six characters like `ABC-DEF`.
@@ -73,20 +73,20 @@ Rejected requests give 403, and unknown or expired requests give 404.
The result of an approved or rejected request is only returned once, after which the request is gone.
A pending request expires 30 seconds after it was last polled, and after an hour of waiting.
The installer polls every 2 seconds.
The host polls every 2 seconds, and makes a new request when the previous one has expired.
### `POST /api/host-pairing/cancel`
- `requestId: string` - Id returned when the request was created.
Removes a pending request, sent by the installer when it stops waiting.
Removes a pending request, sent by the host when it stops waiting.
Responds with 204 whether or not the request existed.
### `GET /api/host-pairing/check`
Checks a host token.
Responds with 200 and `{"valid": true}` if the token is valid and the host it was issued to still exists, and with 401 otherwise.
The installer uses this to tell whether an existing host config still works when it is run again.
A host with a saved token checks it with this when it starts, and requests to join again if the token is not accepted.
## Connector flow
@@ -178,6 +178,7 @@ Host handshake for establishing a new connection session.
The controller closes the connection with code 3000 (Unauthorized) if the token is invalid, was issued for another id, or if there is no host with this id, see [Host pairing](#host-pairing).
If this happens when the host starts it exits with code 8, and the run scripts created by the installer do not restart it.
A host that has been rejected also exits with code 8.
A host that is revoked while connected is disconnected, is rejected when it tries to connect again, and shuts down.
#### `registerControl`
+6 -6
View File
@@ -23,23 +23,23 @@ Listing, approving and rejecting installers waiting for approval needs the `core
ctl> host pending
Lists installers waiting for approval with the code they show, the name they asked for, the address they connected from and how long they have been waiting.
A request goes away when its installer stops waiting, and after waiting for an hour.
Lists hosts waiting for approval with the code they show, the name they asked for, the address they connected from and how long they have been waiting.
A request goes away when its host stops waiting, and after waiting for an hour, after which the host asks again with a new code.
### Approve host
ctl> host approve <code> [--name <host name>]
Approves the installer showing the code and prints the id of the new host.
Approves the host showing the code and prints the id of the new host.
The code is not case sensitive and the dash can be left out.
`--name` gives the host a different name than the one entered in the installer.
`--name` gives the host a different name than the one it asked for.
Approving gives the host full access to the cluster, check with `host pending` that the name and address match the computer you are setting up.
### Reject host
ctl> host reject <code>
Rejects the installer showing the code, the installer then exits with an error.
Rejects the host showing the code, the host then exits with an error.
### Revoke host
@@ -49,7 +49,7 @@ Specify the host by name or ID.
Removes the host from the cluster, disconnects it and makes its token stop working.
Instances assigned to the host have to be unassigned first.
Requires the `core.host.revoke` permission.
To add the computer back to the cluster, run the installer again in the directory the host is installed in.
To add the computer back to the cluster, start the host again and approve it.
### Update Clusterio