Files
worker/docs/install.md
Gleb Tv bd6070ee1f
Все проверки выполнены успешно
CI / test (push) Successful in 3m13s
Docker / Build and publish worker image (push) Successful in 10m35s
feat(installer): build worker source over SSH
2026-08-13 00:07:43 +03:00

274 строки
11 KiB
Markdown

# Installation
The `rsmon-worker install` subcommand turns a built binary (or a published
Docker image) into a running, enabled systemd service on a Linux host. It is
the supported way to deploy the worker: it writes the configuration, the
systemd unit, and the data directory, then starts the service.
> A Go SSH source installer (`rsmon-worker source-install`) builds the worker
> from source on a remote host over SSH - prerequisites, verified Go toolchain,
> clone/update of the public repository (resolved to the remote default branch
> unless pinned), resolved branch/commit record, and a staging build - without
> yet installing a service. See
> [source-installation.md](source-installation.md). Today the local
> `install` copies the binary you invoke it from (or pulls the `--image`
> digest), so build first with `make build` and run the resulting
> `./bin/rsmon-worker`.
## Requirements
- Linux with systemd.
- Root (`install must be run as root`). The worker runs as `root` so it can
reach the Docker socket for Compose discovery and use `CAP_NET_RAW` for ping
checks without extra setup.
- For the binary install: the worker binary you want to install.
- For the Docker install (`--docker`): the `docker` CLI and an immutable
`repository@sha256:<64 lowercase hex>` image digest.
Host dependencies for browser-backed HTTP checks (Debian/Ubuntu):
```bash
sudo apt-get update
sudo apt-get install -y ca-certificates chromium libcap2-bin tzdata
```
## Configuration sources
The installer reads the same environment variables the worker runtime reads.
Each variable is resolved with this precedence (highest first):
1. **Explicit flags** (`--url`, `--public-url`, `--token`, `--host`, `--port`,
`--login`, `--password`, `--name`).
2. **`--env-file`** — a strict, systemd-safe `KEY=VALUE` file (validated before
anything is written to disk).
3. **Process environment**, including a `.env` file in the working directory
(loaded automatically at startup via `godotenv`).
4. **Built-in defaults** (`RSMON_URL=https://rsmon.ru`, `WORKER_HOST=127.0.0.1`,
`WORKER_PORT=27401` for the primary instance).
`.env` files are loaded before the install command runs, so
`sudo rsmon-worker install` from a directory containing a `.env` picks up those
values automatically. To override a value, pass the matching flag.
### Variables
| Variable | Required | Default | Purpose |
| --- | --- | --- | --- |
| `RSMON_URL` | yes | `https://rsmon.ru` | Control-plane base URL. |
| `RSMON_TOKEN` | yes | none | Worker bearer token. |
| `WORKER_HOST` | no | `127.0.0.1` | Operator-console bind address. |
| `WORKER_PORT` | no | `27401` (primary) | Operator-console port. **Required** for named instances. |
| `PUBLIC_URL` | no | none | Advertised public origin: absolute http(s) URL with scheme and authority only (no userinfo, query, fragment, or path). Canonical name; `WORKER_URL` is a deprecated legacy alias read only during the bounded migration. |
| `WORKER_LOGIN` | no | `admin` (generated) | Operator-console basic-auth login. |
| `WORKER_PASSWORD` | no | generated | Operator-console basic-auth password. |
| `WORKER_COMPOSE_ENABLED` | no | feature default (on) | Enable Docker Compose discovery/management. |
| `WORKER_CLUSTER_*` | no | none | Optional Raft cluster (`ID`, `PORT`, `PEERS`, `DATA_DIR`, `ENABLED`). |
| `WORKER_RELEASE_URL` | no | none | Self-update release feed URL. |
`WORKER_LOGIN` and `WORKER_PASSWORD` must both be set or both be left empty. If
both are empty, the installer generates a random password (login `admin`),
writes it to the env file, and prints it once. Record it; the operator console
requires it for both the browser login and the `/web/api/*` HTTP basic-auth
endpoints.
`PUBLIC_URL` does not bind a listener or terminate TLS. It advertises the one
external origin used for the console, authenticated peer status, and planned
Raft `/raft` transport. It must be an absolute `http`/`https` URL with a scheme
and authority and nothing else; a path (other than `/`), userinfo, query, or
fragment is rejected at install time and at worker startup. `PUBLIC_URL` is the
canonical variable; the legacy `WORKER_URL` is still accepted for the bounded
migration defined in
[public-endpoint-and-identity.md](public-endpoint-and-identity.md), and is
dropped from a freshly written env file whenever `PUBLIC_URL` is also set.
The legacy `WORKER_URL` is held only to the tolerant absolute-URL check, so
shapes that previously installed keep working. In an explicitly production
environment (`DEPLOY_ENV=production`, or `RSMON_ENV`/`GO_ENV=production`) a
plain-HTTP `PUBLIC_URL` on a non-loopback host is rejected at startup; a legacy
`WORKER_URL` keeps the historical warn-only behavior. Both variables reject a
missing hostname, e.g. `https://:27401`.
Values must be systemd-safe: no whitespace, quotes, backslashes, or `$`
interpolation inside a value. This keeps the file unambiguous across systemd
`EnvironmentFile` and `docker --env-file`.
## Single-instance install (one worker per host)
The classic install uses the canonical paths and the default port 27401.
```bash
make build
printf '%s\n' 'YOUR_WORKER_TOKEN' > worker-token
chmod 600 worker-token
sudo ./bin/rsmon-worker install \
--token-file worker-token \
--port 27401 \
--password 'choose-a-console-password'
rm worker-token
```
If you keep configuration in a `.env` (recommended for repeatability):
```bash
# .env
RSMON_URL=https://rsmon.ru
RSMON_TOKEN=...
WORKER_PORT=27401
WORKER_LOGIN=admin
WORKER_PASSWORD=...
```
```bash
sudo ./bin/rsmon-worker install
```
Installed layout:
| Path | Contents |
| --- | --- |
| `/usr/local/bin/rsmon-worker` | Worker binary. |
| `/etc/rsmon-worker/worker.env` | Configuration, mode `0600`. |
| `/var/lib/rsmon-worker/` | Data directory (SQLite, webapp state). |
| `/etc/systemd/system/rsmon-worker.service` | systemd unit. |
## Multi-instance install (several workers per host)
`--name` installs a co-located worker under `rsmon-worker-<name>` with its own
binary, config, data, systemd unit, and port. This is how you run a staging
build next to production, or isolate tenants on one host.
```bash
sudo ./bin/rsmon-worker install --name edge --port 27403 --password '...'
```
A named instance must have an explicit `WORKER_PORT` (the default 27401 belongs
to the primary). The name must be 1–32 chars, lowercase alphanumeric and
hyphens, starting and ending alphanumeric.
Named layout (for `--name edge`):
| Path | Contents |
| --- | --- |
| `/usr/local/bin/rsmon-worker-edge` | Binary. |
| `/etc/rsmon-worker-edge/worker.env` | Configuration, mode `0600`. |
| `/var/lib/rsmon-worker-edge/` | Data directory. |
| `/etc/systemd/system/rsmon-worker-edge.service` | systemd unit. |
Each instance is an independent service (`rsmon-worker.service`,
`rsmon-worker-edge.service`, …) and can be managed separately.
## What the installer does
For a binary install, `rsmon-worker install` performs these actions in order:
1. **Validates** the instance name, the `--env-file` (if any), and the resolved
`RSMON_URL`/`RSMON_TOKEN`. Nothing on the host changes before validation
passes.
2. **Resolves** every supported variable with the precedence above and, when
`WORKER_LOGIN`/`WORKER_PASSWORD` are both unset, generates a random console
password.
3. **Copies the binary** from the running executable (or `--binary`) to
`/usr/local/bin/rsmon-worker[-<name>]` with an atomic rename.
4. **Creates** the data directory (`/var/lib/rsmon-worker[-<name>]/webapp`) and
the config directory (`/etc/rsmon-worker[-<name>]`, mode `0750`).
5. **Writes the env file** to `<config dir>/worker.env` (mode `0600`), in a
stable canonical order.
6. **Writes the systemd unit** to
`/etc/systemd/system/rsmon-worker[-<name>].service`.
7. Runs `systemctl daemon-reload`, `systemctl enable`, and, unless `--no-start`,
`systemctl restart` followed by `systemctl is-active --quiet` to confirm the
service came up.
8. **Prints a summary**: unit name, binary, env file, data dir, console URL,
status, and the generated password if one was created.
### The generated systemd unit
The unit is a hardened `Type=simple` root service ordered after
`network-online.target` and `docker.service`:
- `ExecStart=/usr/local/bin/rsmon-worker[-<name>]`
- `EnvironmentFile=/etc/rsmon-worker[-<name>]/worker.env`
- `Environment=HOME=/var/lib/rsmon-worker[-<name>]`
- `Environment=RSMON_WEBAPP_DATA_DIR=/var/lib/rsmon-worker[-<name>]/webapp`
- `AmbientCapabilities=CAP_NET_RAW` / `CapabilityBoundingSet=CAP_NET_RAW` for
ICMP checks.
- `PrivateTmp`, `ProtectHome`, `ProtectSystem=full`, and
`ReadWritePaths=<data dir>` to constrain writes.
- `Restart=always`, `RestartSec=5s`.
## Docker install
Installs a systemd unit that runs the published image instead of a local
binary. Requires an immutable digest; mutable tags are rejected.
```bash
sudo ./bin/rsmon-worker install --docker \
--image 'reg.rsxx.ru/rsmon/rsmon-worker@sha256:<64-hex-digest>' \
--token-file worker-token
```
`--name` works with `--docker` too; the container and volume are namespaced by
instance (`rsmon-worker-edge`, `rsmon-worker-data-edge`). The container always
mounts its data volume at the in-image `/var/lib/rsmon-worker`.
## Options reference
```
rsmon-worker install [--token TOKEN|--token-file FILE|--env-file FILE]
[--name NAME] [--port PORT] [options]
```
| Flag | Purpose |
| --- | --- |
| `--token`, `--api-key` | Worker API token (`RSMON_TOKEN`). |
| `--token-file` | File containing the worker token (avoids shell history). |
| `--env-file` | Strict worker env file; validated then used as the config source. |
| `--url` | Control-plane URL (`RSMON_URL`). |
| `--public-url` | Advertised public origin (`PUBLIC_URL`; scheme + host, no path). |
| `--host` | Console bind address (`WORKER_HOST`). |
| `--port` | Console port (`WORKER_PORT`; required with `--name`). |
| `--login` | Console login (`WORKER_LOGIN`). |
| `--password`, `--password-file` | Console password, or a file containing it. |
| `--name` | Instance name for a co-located worker. |
| `--binary` | Binary to install (default: this executable). |
| `--docker` | Install the prebuilt Docker image (requires `--image`). |
| `--image` | Immutable `repository@sha256:<64 hex>` digest. |
| `--no-start` | Enable without starting. |
`--token`/`--token-file` and `--password`/`--password-file` are mutually
exclusive within each pair; combining a direct secret with its file form is an
error.
## Post-install operations
```bash
systemctl status rsmon-worker[-<name>]
journalctl -u rsmon-worker[-<name>] -f
sudo systemctl restart rsmon-worker[-<name>]
```
The public liveness endpoint is `GET /healthz`; probe it with
`rsmon-worker liveness`. The operator console is at `http://127.0.0.1:<port>`
(loopback by default) and exposes the JSON API under `/web/api/*` using HTTP
basic auth.
### Uninstall
There is no `uninstall` subcommand yet. To remove an instance manually:
```bash
sudo systemctl disable --now rsmon-worker-<name>
sudo rm /etc/systemd/system/rsmon-worker-<name>.service
sudo rm -rf /etc/rsmon-worker-<name> /var/lib/rsmon-worker-<name> /usr/local/bin/rsmon-worker-<name>
sudo systemctl daemon-reload
```
## Security notes
- Keep `/etc/rsmon-worker[-<name>]/worker.env` mode `0600`; the installer writes
it that way.
- Prefer `--token-file`/`--password-file` or a `.env` over passing secrets as
flags, which can leak through shell history and process inspection.
- Bind the console to loopback (`WORKER_HOST=127.0.0.1`, the default) or front
it with an authenticated TLS reverse proxy.
- Each worker should use its own control-plane token.