# 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 is planned in > [source-installation.md](source-installation.md). Today > `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-` 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[-]` with an atomic rename. 4. **Creates** the data directory (`/var/lib/rsmon-worker[-]/webapp`) and the config directory (`/etc/rsmon-worker[-]`, mode `0750`). 5. **Writes the env file** to `/worker.env` (mode `0600`), in a stable canonical order. 6. **Writes the systemd unit** to `/etc/systemd/system/rsmon-worker[-].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[-]` - `EnvironmentFile=/etc/rsmon-worker[-]/worker.env` - `Environment=HOME=/var/lib/rsmon-worker[-]` - `Environment=RSMON_WEBAPP_DATA_DIR=/var/lib/rsmon-worker[-]/webapp` - `AmbientCapabilities=CAP_NET_RAW` / `CapabilityBoundingSet=CAP_NET_RAW` for ICMP checks. - `PrivateTmp`, `ProtectHome`, `ProtectSystem=full`, and `ReadWritePaths=` 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[-] journalctl -u rsmon-worker[-] -f sudo systemctl restart rsmon-worker[-] ``` The public liveness endpoint is `GET /healthz`; probe it with `rsmon-worker liveness`. The operator console is at `http://127.0.0.1:` (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- sudo rm /etc/systemd/system/rsmon-worker-.service sudo rm -rf /etc/rsmon-worker- /var/lib/rsmon-worker- /usr/local/bin/rsmon-worker- sudo systemctl daemon-reload ``` ## Security notes - Keep `/etc/rsmon-worker[-]/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.