@@ -12,7 +12,7 @@ HQ portal.
|
||||
|
||||
A signed file. It carries the instance UUID it belongs to, the tier, the server
|
||||
allowance, feature toggles and an expiry. The control plane verifies the
|
||||
signature locally — checking a licence never contacts HQ, and a running instance
|
||||
signature locally checking a licence never contacts HQ, and a running instance
|
||||
does not need HQ to be reachable.
|
||||
|
||||
Signing happens in exactly one place, in HQ. The control plane can only verify.
|
||||
@@ -40,7 +40,7 @@ bound to that UUID and hands it back.
|
||||
:::info One Free per account, per deployment
|
||||
The limit is enforced per account **and** deployment, so a Free cloud instance
|
||||
does not stop you claiming Free on a self-hosted install. Both the friendly
|
||||
pre-check and the issuer apply the same rule — deliberately, because a
|
||||
pre-check and the issuer apply the same rule deliberately, because a
|
||||
pre-check stricter than the issuer would refuse something that would actually
|
||||
have worked.
|
||||
:::
|
||||
@@ -56,7 +56,7 @@ starts reporting the tier, allowance and expiry.
|
||||
:::warning Cloud instances cannot paste a licence
|
||||
On a cloud instance `POST /license` answers `409 cloud_managed`, and the UI
|
||||
hides the form entirely. A cloud licence is written directly by HQ. This is not
|
||||
a restriction the injection path has to work around — it writes to the database,
|
||||
a restriction the injection path has to work around it writes to the database,
|
||||
not through the endpoint.
|
||||
:::
|
||||
|
||||
@@ -65,7 +65,7 @@ not through the endpoint.
|
||||
Free licences are renewable from HQ within a renewal window near expiry;
|
||||
outside that window the renew call refuses. See [Free tier](../hq/free-tier.md).
|
||||
|
||||
Pasting a licence keeps working while the current one is expired — that endpoint
|
||||
Pasting a licence keeps working while the current one is expired that endpoint
|
||||
is exempt from the licence check, because it is the way out of degraded mode.
|
||||
|
||||
## Moving the install to new hardware
|
||||
|
||||
@@ -9,21 +9,21 @@ who operates it and how licensing, users and data lifecycle work.
|
||||
|
||||
## At a glance
|
||||
|
||||
| | Cloud | Self-hosted |
|
||||
| --- | --- | --- |
|
||||
| Who runs it | We do | You do |
|
||||
| Where you sign in | `<your-slug>.vantage.hostxtra.co.uk` | Your own hostname |
|
||||
| Database and backups | Ours | Yours |
|
||||
| Licence | Written for you when you buy or create the instance | Pasted in, or claimed from HQ |
|
||||
| Team members | Granted from HQ; the instance holds a projection | Created in the instance itself |
|
||||
| Free tier | Yes, one per account | Yes, one per account |
|
||||
| Expired Free instance | Eventually deleted, after warning | Never deleted |
|
||||
| | Cloud | Self-hosted |
|
||||
| --------------------- | --------------------------------------------------- | ------------------------------ |
|
||||
| Who runs it | We do | You do |
|
||||
| Where you sign in | `<your-slug>.vantage.hostxtra.co.uk` | Your own hostname |
|
||||
| Database and backups | Ours | Yours |
|
||||
| Licence | Written for you when you buy or create the instance | Pasted in, or claimed from HQ |
|
||||
| Team members | Granted from HQ; the instance holds a projection | Created in the instance itself |
|
||||
| Free tier | Yes, one per account | Yes, one per account |
|
||||
| Expired Free instance | Eventually deleted, after warning | Never deleted |
|
||||
|
||||
## Cloud
|
||||
|
||||
You create an instance from the HQ portal and it exists a few seconds later,
|
||||
already licensed. People you grant access to get a real user inside that
|
||||
instance — see [People and roles](../hq/people-and-roles.md) — but HQ owns their
|
||||
instance see [People and roles](../hq/people-and-roles.md) but HQ owns their
|
||||
password, role and existence.
|
||||
|
||||
:::info The instance does not phone home
|
||||
@@ -38,33 +38,27 @@ warning emails first. See [Free tier](../hq/free-tier.md).
|
||||
## Self-hosted
|
||||
|
||||
You run the Docker Compose stack on your own infrastructure. Nothing about the
|
||||
control plane requires an internet connection to HQ at runtime — a licence is a
|
||||
control plane requires an internet connection to HQ at runtime a licence is a
|
||||
signed file, verified locally.
|
||||
|
||||
Two ways to get one:
|
||||
|
||||
1. **Free** — link the install to an HQ account and claim it
|
||||
1. **Free** link the install to an HQ account and claim it
|
||||
([Claim a Free licence](./claim-free-licence.md)).
|
||||
2. **Paid** — buy from HQ, which creates a placeholder, then paste the install's
|
||||
2. **Paid** buy from HQ, which creates a placeholder, then paste the install's
|
||||
real instance UUID to bind and issue
|
||||
([Self-hosted instances](../hq/self-hosted-instances.md)).
|
||||
|
||||
Self-hosted users are local (or OIDC). There is no projection from HQ, and the
|
||||
three member endpoints in HQ refuse to touch a self-hosted instance at all.
|
||||
|
||||
:::warning Self-hosted instances are never deleted by us
|
||||
The reaper that removes expired Free cloud instances is disabled by default and
|
||||
must stay that way on a self-hosted install. See `FREE_INSTANCE_REAP_AFTER` in
|
||||
[Environment variables](../reference/environment-variables.md).
|
||||
:::
|
||||
|
||||
## Which should you pick
|
||||
|
||||
Pick cloud if you want the thing running now and do not want to own a MongoDB.
|
||||
Pick self-hosted if your policy requires the control plane inside your own
|
||||
network, or the servers you manage cannot reach the public internet.
|
||||
|
||||
Moving between them is a migration, not a switch — instances are bound to a
|
||||
Moving between them is a migration, not a switch instances are bound to a
|
||||
deployment at creation, and a licence binds to an instance UUID.
|
||||
|
||||
## Next
|
||||
|
||||
@@ -13,15 +13,15 @@ Open the control plane in a browser. Because no user exists, you land on
|
||||
|
||||
Fill in:
|
||||
|
||||
| Field | Notes |
|
||||
| --- | --- |
|
||||
| Organisation name | Display name. Shown throughout the UI |
|
||||
| Slug | Lowercase, used in the hostname on cloud. Some names are reserved |
|
||||
| Your name | |
|
||||
| Email | Becomes your sign-in identity |
|
||||
| Password | Stored bcrypt-hashed |
|
||||
| Field | Notes |
|
||||
| ----------------- | ----------------------------------------------------------------- |
|
||||
| Organisation name | Display name. Shown throughout the UI |
|
||||
| Slug | Lowercase, used in the hostname on cloud. Some names are reserved |
|
||||
| Your name | |
|
||||
| Email | Becomes your sign-in identity |
|
||||
| Password | Stored bcrypt-hashed |
|
||||
|
||||
Submitting creates the organisation and its **owner** — you.
|
||||
Submitting creates the organisation and its **owner** you.
|
||||
|
||||
:::warning Bootstrap works exactly once
|
||||
The endpoint is open only while the database has no users. As soon as the first
|
||||
@@ -43,30 +43,30 @@ nothing else.
|
||||
You land on the fleet dashboard, which is empty. The sidebar is the whole
|
||||
product:
|
||||
|
||||
| Section | What it does |
|
||||
| --- | --- |
|
||||
| Servers | The fleet — enrol, inspect, console, update |
|
||||
| Keys | SSH public keys and their assignments |
|
||||
| Workflows | Compose and run scripted work |
|
||||
| Steps | The reusable step library |
|
||||
| Monitors | HTTP, TCP, ICMP and TLS checks |
|
||||
| Secrets | The encrypted vault |
|
||||
| Audit | Every mutating action |
|
||||
| Settings | Members, SSO, alerts, retention, licence |
|
||||
| Section | What it does |
|
||||
| --------- | ----------------------------------------- |
|
||||
| Servers | The fleet enrol, inspect, console, update |
|
||||
| Keys | SSH public keys and their assignments |
|
||||
| Workflows | Compose and run scripted work |
|
||||
| Steps | The reusable step library |
|
||||
| Monitors | HTTP, TCP, ICMP and TLS checks |
|
||||
| Secrets | The encrypted vault |
|
||||
| Audit | Every mutating action |
|
||||
| Settings | Members, SSO, alerts, retention, licence |
|
||||
|
||||
## 4. Add the rest of your team
|
||||
|
||||
Go to **Settings → Access**. Add members with a role:
|
||||
|
||||
| Role | Can |
|
||||
| --- | --- |
|
||||
| `owner` | Everything, including billing-adjacent settings |
|
||||
| `admin` | Everything except owner-only settings |
|
||||
| `member` | Day-to-day work — servers, keys, workflows, monitors |
|
||||
| Role | Can |
|
||||
| -------- | -------------------------------------------------- |
|
||||
| `owner` | Everything, including billing-adjacent settings |
|
||||
| `admin` | Everything except owner-only settings |
|
||||
| `member` | Day-to-day work servers, keys, workflows, monitors |
|
||||
|
||||
Settings and organisation management require `owner` or `admin`.
|
||||
|
||||
If you would rather not manage passwords, configure OIDC instead — see
|
||||
If you would rather not manage passwords, configure OIDC instead see
|
||||
[Settings](../vantage/settings.md#single-sign-on-oidc). OIDC is configured per
|
||||
organisation, and the client secret is stored encrypted.
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ one-liner.
|
||||
:::warning The token is single-use and lives one hour
|
||||
It is the only credential in the flow, and it is spent the moment the agent
|
||||
calls `Register`. If you paste it somewhere and come back tomorrow, create a new
|
||||
enrolment instead — nothing is lost by doing so.
|
||||
enrolment instead nothing is lost by doing so.
|
||||
:::
|
||||
|
||||
## 2. Run the one-liner
|
||||
@@ -30,7 +30,7 @@ curl -fsSL "https://vantage.example.com/install?server_id=<id>&token=<token>" |
|
||||
|
||||
Run it as root. The script:
|
||||
|
||||
1. Detects architecture — `x86_64` and `aarch64` only; anything else exits.
|
||||
1. Detects architecture `x86_64` and `aarch64` only; anything else exits.
|
||||
2. Asks the Gitea API for the newest `agent/v*` release.
|
||||
3. Downloads the binary and `checksums.txt`, and **verifies the SHA-256**,
|
||||
aborting on a mismatch.
|
||||
@@ -52,14 +52,14 @@ MSI built by CI if you would rather deploy that.
|
||||
|
||||
:::info Windows agents are second-class on purpose
|
||||
They register, heartbeat, run workflow steps and report inventory. They do
|
||||
**not** manage `authorized_keys` — the key subsystem is Linux-only, and a
|
||||
**not** manage `authorized_keys` the key subsystem is Linux-only, and a
|
||||
Windows agent stops after the heartbeat portion of the poll.
|
||||
:::
|
||||
|
||||
## 3. Watch it come up
|
||||
|
||||
The server appears immediately as `pending`. Within one poll interval — 30
|
||||
seconds — it flips to `active`.
|
||||
The server appears immediately as `pending`. Within one poll interval 30
|
||||
seconds it flips to `active`.
|
||||
|
||||
On the machine:
|
||||
|
||||
@@ -72,10 +72,10 @@ What happens on that first run:
|
||||
|
||||
```
|
||||
1. Load /etc/vantage/config.yaml
|
||||
2. pre_reg_token present → Register() → save agent_token, clear pre_reg_token
|
||||
2. pre_reg_token present → register → save agent_token, clear pre_reg_token
|
||||
3. Reconnect with the permanent token
|
||||
4. Start: command stream · hourly update check · inventory · monitors
|
||||
5. Enter the SyncKeys poll loop
|
||||
5. Enter the key poll loop
|
||||
```
|
||||
|
||||
After registration the config no longer contains the pre-registration token; it
|
||||
@@ -87,19 +87,19 @@ SHA-256 of that token, never the token itself.
|
||||
Open the server's detail page. Within a minute or two you should see:
|
||||
|
||||
- Status `active`, with a recent last-seen timestamp.
|
||||
- Inventory — CPU, memory, swap, partitions, kernel. Metrics refresh every 30
|
||||
- Inventory CPU, memory, swap, partitions, kernel. Metrics refresh every 30
|
||||
seconds; the full static snapshot every 15 minutes.
|
||||
- Pending OS updates, checked hourly.
|
||||
|
||||
## If it does not appear
|
||||
|
||||
| Symptom | Cause |
|
||||
| --- | --- |
|
||||
| Script exits at "Unsupported architecture" | Not amd64 or arm64 |
|
||||
| "Checksum mismatch!" | Interrupted download, or a proxy rewriting the body. Re-run |
|
||||
| "Could not determine latest agent version" | The host cannot reach `gitea.hostxtra.co.uk`, or no `agent/v*` release exists |
|
||||
| Service runs, server stays `pending` | The machine cannot reach `GRPC_HOST`. Test it from that machine |
|
||||
| Registers once then goes `offline` | Reachable for `Register` but not for the poll — usually a firewall that permits the initial connection but drops the long-lived one |
|
||||
| Symptom | Cause |
|
||||
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Script exits at "Unsupported architecture" | Not amd64 or arm64 |
|
||||
| "Checksum mismatch!" | Interrupted download, or a proxy rewriting the body. Re-run |
|
||||
| "Could not determine latest agent version" | The host cannot reach `gitea.hostxtra.co.uk`, or no `agent/v*` release exists |
|
||||
| Service runs, server stays `pending` | The machine cannot reach `GRPC_HOST`. Test it from that machine |
|
||||
| Registers once then goes `offline` | Reachable for `Register` but not for the poll usually a firewall that permits the initial connection but drops the long-lived one |
|
||||
|
||||
A server is marked `offline` when its last-seen time passes the threshold; that
|
||||
sweep runs every two minutes, so allow for it before concluding anything.
|
||||
|
||||
@@ -42,7 +42,7 @@ a way you did not intend.
|
||||
Create `/opt/vantage/.env`:
|
||||
|
||||
```bash
|
||||
# The host:port agents dial. NOT the web URL — this port speaks gRPC.
|
||||
# The host:port agents dial. NOT the web URL this port speaks gRPC.
|
||||
GRPC_HOST=vantage.example.com:9090
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ openssl rand -hex 32
|
||||
:::danger Keep the encryption key
|
||||
`KEY_ENCRYPTION_KEY` encrypts SSH private keys, vault secrets, OIDC client
|
||||
secrets and console credentials with AES-256-GCM. Lose it and every one of those
|
||||
becomes unreadable — there is no recovery path. Back it up somewhere other than
|
||||
becomes unreadable there is no recovery path. Back it up somewhere other than
|
||||
the server it protects, and never rotate it without a planned re-encryption.
|
||||
:::
|
||||
|
||||
@@ -109,12 +109,12 @@ Continue with [First login](./first-login.md).
|
||||
|
||||
## Verifying the install
|
||||
|
||||
| Check | Expected |
|
||||
| --- | --- |
|
||||
| `docker compose ps` | five services `running` |
|
||||
| Check | Expected |
|
||||
| ---------------------------------------------- | ------------------------------- |
|
||||
| `docker compose ps` | five services `running` |
|
||||
| `curl -s localhost:8080/auth/bootstrap-status` | JSON saying bootstrap is needed |
|
||||
| `nc -z your-host 9090` | open |
|
||||
| `docker compose logs server \| grep -i fatal` | nothing |
|
||||
| `nc -z your-host 9090` | open |
|
||||
| `docker compose logs server \| grep -i fatal` | nothing |
|
||||
|
||||
## Common install problems
|
||||
|
||||
@@ -131,7 +131,6 @@ More in [Troubleshooting](../reference/troubleshooting.md).
|
||||
|
||||
## What this install does not include
|
||||
|
||||
The marketing site, the public form service, the HQ portal and this
|
||||
documentation site are separate services in `deploy/docker-compose.site.yml`.
|
||||
A self-hosted install deliberately runs none of them, and in particular never
|
||||
holds the licence signing key.
|
||||
The website, the HQ portal and this documentation site are hosted by us and are
|
||||
not part of a self-hosted install. It deliberately runs none of them, and in
|
||||
particular never holds the licence signing key.
|
||||
|
||||
@@ -27,8 +27,8 @@ stores everything durable; Redis stores sessions and nothing else.
|
||||
|
||||
**The agent** is a single Go binary running as root on each managed server. It
|
||||
polls the control plane every 30 seconds for desired key state, and holds a
|
||||
bidirectional command stream so the server can push work — run a workflow step,
|
||||
generate a key, apply updates — without waiting for the next poll.
|
||||
bidirectional command stream so the server can push work run a workflow step,
|
||||
generate a key, apply updates without waiting for the next poll.
|
||||
|
||||
**The web UI** is the operator interface. Everything it does goes through the
|
||||
REST API, which is the actual security boundary; the UI only ever makes things
|
||||
@@ -46,18 +46,18 @@ could guess on its behalf.
|
||||
|
||||
## Two request patterns
|
||||
|
||||
| Pattern | Used for | Why |
|
||||
| --- | --- | --- |
|
||||
| Poll (`SyncKeys`, every 30s) | desired SSH key state | Key changes are not urgent, and polling survives a dropped connection with no reconnection logic |
|
||||
| Push (`CommandStream`) | workflow steps, key generation, updates, agent self-update | Clicking Run should not wait up to 30 seconds |
|
||||
| Pattern | Used for | Why |
|
||||
| ----------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| Poll, every 30s | desired SSH key state | Key changes are not urgent, and polling survives a dropped connection with no reconnection logic |
|
||||
| Push, over the command stream | workflow steps, key generation, updates, agent self-update | Clicking Run should not wait up to 30 seconds |
|
||||
|
||||
## Multi-tenancy
|
||||
|
||||
Every document in the database carries an instance ID, and every query is scoped
|
||||
by it. One deployment can therefore host many independent tenants. On a
|
||||
self-hosted install that mechanism is still there — you simply have one tenant.
|
||||
self-hosted install that mechanism is still there you simply have one tenant.
|
||||
|
||||
## Next
|
||||
|
||||
- [Cloud or self-hosted](./cloud-vs-self-hosted.md) — which one you want
|
||||
- [Self-hosted install](./self-hosted-install.md) — stand it up
|
||||
- [Cloud or self-hosted](./cloud-vs-self-hosted.md) which one you want
|
||||
- [Self-hosted install](./self-hosted-install.md) stand it up
|
||||
|
||||
Reference in New Issue
Block a user