Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration reference

helmsight reads one TOML file. The first of these is used:

  1. --config <path>
  2. $HELMSIGHT_CONFIG
  3. /etc/helmsight/helmsight.toml
  4. ./helmsight.toml

Türkçe sürüm

examples/helmsight.toml is a commented example of every option. Validate a file with helmsight config check; errors show the file, line, column and key:

error: helmsight.toml:23:1: `hosts[1].name`: duplicate host name `web-1`
error: helmsight.toml:41:8: `alerts.rules[0].expr`: unknown operator `=>` (use > >= < <= == !=)

Unknown keys are errors, so typos never pass silently.

Durations are strings such as "500ms", "30s", "5m", "1h30m", "7d", "2w" (ms milliseconds, s seconds, m minutes, h hours, d days, w weeks).

Secrets may be literal strings, but references are preferred:

FormMeaning
"secret:<name>"Stored encrypted in the database with helmsight secret set <name>
"env:<VAR>"Value of an environment variable
"file:<path>"Contents of a file (trailing newline removed)

env: works well with systemd’s EnvironmentFile= or container environment variables, and file: with Docker or Kubernetes secret files (/run/secrets/...).

Changes to the configuration take effect after a restart.

A complete example

# Top-level keys must come before any [section] header.
hosts_file = "hosts.toml"

[server]
listen = "127.0.0.1:8080"
data_dir = "/var/lib/helmsight"
public_url = "https://monitor.example.com"
trusted_proxies = ["127.0.0.1"]

[auth]
require_totp_for_admins = true

[ssh]
user = "monitor"
identity_files = ["/etc/helmsight/id_ed25519"]

[[alerts.rules]]
id = "disk-full"
expr = "disk_used_pct > 90 for 10m"
severity = "critical"

[[notify]]
id = "ops"
type = "slack"
url = "secret:slack-webhook"

[[certs]]
endpoint = "www.example.com:443"

In TOML, every key written after a [section] header belongs to that section. Write top-level keys such as hosts_file at the very top of the file; in the wrong place, config check reports them as unknown keys.

[server]

KeyDefaultDescription
listen"127.0.0.1:8080"Address and port to listen on
data_dir"data"Database, key file, known_hosts and TLS files; relative to the config file
public_urlnoneExternal https:// URL; required for OIDC, used in notification links and origin checks
trusted_proxies[]IP addresses whose X-Forwarded-For header is trusted

trusted_proxies matters for identifying clients correctly: sign-in rate limiting works per client address. Behind a proxy without this setting, every user appears to come from the proxy’s address.

[server.tls]

KeyDefaultDescription
mode"auto"auto (HTTP on loopback, self-signed otherwise), self-signed, files or off
cert, keynonePEM files for mode = "files"
allow_insecure_httpfalsePermit mode = "off" on a non-loopback address (behind a TLS proxy)

With a Let’s Encrypt certificate, point cert at fullchain.pem and key at privkey.pem, and restart helmsight after renewal (for example with certbot’s --deploy-hook).

[auth]

KeyDefaultDescription
session_ttl"12h"Maximum session lifetime (min 5m)
idle_timeout"2h"Sessions end after this much inactivity (min 1m)
require_totp_for_adminsfalseAdmins with local passwords must enrol TOTP before using the UI
disable_local_loginfalseOnly allow OIDC sign-in

[auth.oidc]

KeyDefaultDescription
issuerrequiredIssuer URL; discovery uses <issuer>/.well-known/openid-configuration
client_idrequired
client_secretnoneSecret reference recommended
scopes["openid", "profile", "email"]Must include openid
role_claim"groups"Claim with group or role names; dotted paths such as realm_access.roles work
role_map{}Claim value → viewer, operator or admin; the highest match wins
default_rolenoneRole for users without a match; unset denies access
label"Single sign-on"Text of the sign-in button

Register <public_url>/api/v1/auth/oidc/callback as the redirect URI. Roles are updated from the claim at every sign-in, so changing a user’s groups at the identity provider changes their role at their next sign-in.

Example (Keycloak):

[auth.oidc]
issuer = "https://sso.example.com/realms/ops"
client_id = "helmsight"
client_secret = "secret:oidc"
role_claim = "realm_access.roles"
role_map = { "helmsight-admin" = "admin", "sre" = "operator", "dev" = "viewer" }
label = "Sign in with company account"

Keeping a local administrator account for emergencies is recommended; use disable_local_login with care so that you do not lose access to the UI when SSO is down.

[ssh]

KeyDefaultDescription
user"monitor"Remote user (overridable per host)
identity_files[]Private key files, tried in order
use_agenttrueAlso try keys from SSH_AUTH_SOCK
known_hosts_files[]Extra OpenSSH known_hosts files, read-only
accept_new_host_keysfalseTrust keys of new hosts automatically; changed keys are still refused
connect_timeout"10s"TCP connect, key exchange and authentication
command_timeout"30s"One collection (updates checks get at least 5 minutes)
keepalive"30s"SSH keepalive interval

[collect]

KeyDefaultDescription
interval"5s"Metrics: CPU, memory, load, disks, network, TCP, processes
medium_interval"60s"Listening ports, services, containers, sessions
inventory_interval"15m"OS, kernel, packages, enabled units, reboot flags
auth_interval"5m"Failed SSH logins
updates_interval"6h"Pending updates
max_parallel64Hosts collected at the same time
dnf_updatesfalseRun dnf/yum for pending updates (they write log files on the host)

Failed hosts are retried with backoff: exponential up to 5 minutes when unreachable, 1 to 5 minutes after authentication failures (to avoid triggering intrusion prevention) and every minute for host key problems.

Lowering interval increases chart resolution, but also increases the load on the hosts and the database proportionally. For large fleets, 10 to 15 seconds is a reasonable starting point.

[retention]

KeyDefaultDescription
raw"24h"Every sample (min 1h)
minute"7d"1-minute average, minimum and maximum
five_minute"90d"5-minute average, minimum and maximum
events"90d"Inventory changes, resolved alerts, failed logins, notifications

Charts pick the finest resolution that covers the requested range. Longer retention grows the database proportionally. Expired data is deleted automatically every hour; rollups are computed every minute.

Hosts

[[hosts]]

KeyDefaultDescription
namerequiredUnique; letters, digits, ., -, _
addressthe nameHostname or IP address
port22
userssh.user
identity_filenoneKey tried before the shared keys
groups[]Used for filtering, rules, actions, channels and display tokens
tags[]Free-form, typically key:value such as env:prod
baselinenoneHost used as the reference for drift and new-port detection
disabledfalseKeep the host listed but do not collect

hosts_file

A top-level hosts_file = "hosts.toml" loads additional [[hosts]] from another file (relative to the configuration file).

[ssh_config_import]

KeyDefaultDescription
path"~/.ssh/config"OpenSSH client configuration
hostsrequiredGlob patterns of aliases to import, e.g. ["web-*"]
groups, tags[]Added to every imported host

HostName, User, Port and IdentityFile are honoured, with OpenSSH “first value wins” semantics across matching Host blocks. Explicit [[hosts]] with the same name take precedence. Hosts with ProxyJump are skipped with a warning; Match and Include are not evaluated.

Alerts

[alerts]

KeyDefaultDescription
unreachable_after"2m"Delay before host_unreachable fires
failed_unitstrueAlert on failed systemd units and crashed OpenRC services
cert_warning_days21
cert_critical_days7
repeat_interval"4h"Remind about unacknowledged firing alerts; "0s" disables

Built-in rules: host_unreachable (critical; also for authentication failures), host_key_changed (critical), host_key_unknown (warning), failed_units (warning, one alert per unit), cert_expiry (warning or critical by days left; warning when the check fails).

[[alerts.rules]]

KeyDefaultDescription
idrequiredUnique
exprrequired<metric> <op> <threshold> [for <duration>]
severity"warning"info, warning or critical
summarynonePrefix for the generated description
hosts, groups, tagsall hostsScope; a host matches if it matches any entry

Operators: >, >=, <, <=, ==, !=. Thresholds accept the suffixes K, M, G, T (powers of 1000) and Ki, Mi, Gi, Ti (powers of 1024). Per-instance metrics produce one alert per instance (for example per mount point). While a host is unreachable, its metric alerts keep their state instead of resolving.

Metrics available to rules

MetricUnitPerDescription
cpu_pct%hostCPU busy time, all cores
cpu_iowait_pct%hostCPU time waiting for I/O
cpu_steal_pct%hostCPU time stolen by the hypervisor
mem_used_pct%hostMemory in use, excluding reclaimable cache
swap_used_pct%hostSwap in use
load1, load5, load15hostLoad averages
load1_per_corehost1-minute load divided by cores
disk_used_pct%mountFilesystem space used
disk_inodes_used_pct%mountFilesystem inodes used
disk_util_pct%deviceBlock device utilisation
net_rx_bytesB/sinterfaceBytes received per second
net_tx_bytesB/sinterfaceBytes sent per second
net_errors1/sinterfaceReceive and transmit errors per second
tcp_establishedhostEstablished TCP connections
process_counthostProcesses
failed_unitshostFailed systemd units or crashed OpenRC services
pending_updateshostPending package updates
pending_security_updateshostPending security updates
reboot_requiredhost1 when a reboot is required
ssh_failed_logins_1hhostFailed SSH logins in the last hour
uptime_secsshostSeconds since boot
clock_skew_secsshostDifference between host and server clocks
containers_not_runninghostContainers that exist but are not running

[[notify]]

KeyApplies toDescription
idallUnique
typeallwebhook, slack or email
min_severityallDefault warning
hosts, groups, tagsallOnly alerts of these hosts (host-less alerts such as certificates go to unscoped channels)
urlwebhook, slackhttps:// URL (plain http only for localhost)
headerswebhookExtra HTTP headers; values may be secret references
smtp_host, smtp_portemail
smtp_securityemailstarttls (default), tls, or none for a relay on localhost
smtp_username, smtp_passwordemail
from, toemailSender and recipients

Notifications are sent when an alert fires, when it resolves (if the firing notification was sent) and as reminders. Silenced alerts are recorded but not notified. Failed deliveries are retried three times and listed with the alert. Send a test from the API: POST /api/v1/notify/<id>/test.

Webhook payload:

{
  "version": 1,
  "source": "helmsight",
  "status": "firing",
  "alert": {
    "id": 42,
    "rule": "disk-full",
    "host": "web-1",
    "instance": "/var",
    "severity": "critical",
    "summary": "disk_used_pct on /var is 93.1% (> 90.0%)",
    "value": 93.1,
    "started_at": "2026-09-30T16:56:12Z",
    "resolved_at": null,
    "acknowledged_by": null
  },
  "url": "https://monitor.example.com/alerts?id=42"
}

status is firing, resolved, reminder or test.

[[certs]]

KeyDefaultDescription
endpointrequiredhost:port
server_nameendpoint hostSNI name and name to validate
interval"6h"

The certificate is read even when it does not validate; trust problems are shown separately from connection failures. Checks run from the helmsight server, so only endpoints that helmsight can reach can be checked.

[[actions]]

KeyDefaultDescription
idrequiredUnique
labelrequiredButton text
description""Shown in the UI
commandrequiredExact single-line command; privileged commands must start with sudo -n
hosts, groups, tagsrequiredHosts where the action is offered; at least one entry
role"operator"operator or admin
timeout"60s"1s to 1h

[prometheus]

KeyDefaultDescription
enabledfalseServe /metrics
tokenrequired when enabledBearer token
scrape_configs:
  - job_name: helmsight
    scheme: https
    authorization:
      credentials_file: /etc/prometheus/helmsight.token
    static_configs:
      - targets: ["monitor.example.com"]

Exposed metrics are prefixed with helmsight_: host_up, host_alerts_firing, cpu_percent{mode}, memory_*_bytes, load1/5/15, filesystem_{size,used,avail}_bytes{mount}, disk_{read,written}_bytes_per_second{device}, network_{receive,transmit}_bytes_per_second{interface}, tcp_connections{state}, pending_updates, pending_security_updates, reboot_required and more, all labelled with host.

Command line

CommandDescription
serve [--local] [--listen ADDR]Run the server. --local monitors only this machine by reading /proc (no SSH, no configuration needed).
init [--force] [--non-interactive] [options]Create a configuration file, the data directory, the key file and the first administrator; asks for values not given as options (--listen, --public-url, --ssh-user, --ssh-key, --generate-key, --admin, --password-stdin)
user add <name> [--role viewer|operator|admin] [--password-stdin]Create a local user
user remove <name>Delete a user (the last admin cannot be removed)
user reset-password <name> [--password-stdin] [--reset-totp]Set a new password and end the user’s sessions
user listList users
hosts test [--trust] [names...]Connect to hosts and report status; --trust confirms unknown host keys interactively
hosts bootstrap [--from ADDR] [--user USER] [--key PATH] [--no-journal]Print a script that creates the monitoring account on a host, e.g. helmsight hosts bootstrap --from 10.0.0.5 | ssh root@web-1 sh
config checkValidate the configuration and check that referenced secrets exist
secret set <name> [--stdin] / secret list / secret delete <name>Manage encrypted secrets
audit verifyVerify the audit log hash chain

Global options: --config <path>, --data-dir <dir> (overrides server.data_dir; without a configuration file, commands use the local-mode default ~/.local/share/helmsight, or /var/lib/helmsight for root), --log-format text|json.

When no user exists, serve prints a one-time setup link (/setup#token=...) for creating the first administrator in the browser.

Environment variables

VariableDescription
HELMSIGHT_CONFIGConfiguration file path
HELMSIGHT_DATA_DIRSame as --data-dir
HELMSIGHT_LOGLog filter, e.g. info, debug, info,server=debug
SSH_AUTH_SOCKssh-agent socket used when ssh.use_agent = true

HTTP API

The web UI uses the same versioned JSON API under /api/v1. The OpenAPI document is served at /api/v1/openapi.json. Authenticate with the session cookie from POST /api/v1/auth/login; state-changing requests need the X-CSRF-Token header returned by GET /api/v1/auth/me. Live updates are available as server-sent events at /api/v1/events. Wall displays call /api/v1/display/state with Authorization: Bearer <display token>. /healthz returns ok without authentication.