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

Introduction

← Monitra home

Monitra is a Rust uptime monitor operated from the command line. It checks network targets, can receive checks from host agents, and exposes a terminal and web dashboard.

Its operating principles are straightforward:

  • Show an unknown or stale state when Monitra lacks evidence. A broken collector or missing agent does not prove that a target is down.
  • Keep the normal installation self-contained: SQLite, an in-process cache, and a logging notifier need no external service.
  • Make capabilities available from the CLI, including monitor management and alert history.

Start with Getting started, then see Concepts and the CLI reference.

Getting started

Download options for Linux x86_64 and aarch64 are on the releases page.

MethodCommand
Verified installerRun the one-liner below.
GitHub ReleaseDownload the matching tarball and SHA256SUMS from the latest release, verify with sha256sum -c SHA256SUMS, and install the extracted binary.
Dockerdocker compose up -d with compose.yaml. See Deployment for the volume.
Cargo Binstallcargo binstall monitra --manifest-path Cargo.toml from a checkout. Plain cargo binstall monitra awaits crates.io publication.
Build from sourcecargo build --release with Rust and Node/npm on PATH.
curl -fsSL https://raw.githubusercontent.com/rustiqz/monitra/main/scripts/install.sh | sh

Verify a binary install with monitra --version. The installer defaults to ~/.local/bin; use --dir PATH to change it. Ensure the chosen directory is on PATH.

Configuration is optional. On a pristine machine, add a monitor directly; this creates the default SQLite database under your XDG data directory.

monitra monitor add --name example --target https://example.com --kind http --interval 30
monitra monitor list
monitra start

On first daemon start, Monitra generates an API token, writes it to its XDG config, and prints it once. Save it. The daemon binds 127.0.0.1:8080 by default. In another terminal, use monitra tui for a terminal dashboard or monitra web for the embedded browser dashboard. Both can start their own local backend when no --url is supplied.

For optional configuration, run monitra setup or read Configuration. See Deployment before exposing the daemon remotely.

Concepts

A Monitor names a target, a kind, and a check interval. Kinds include HTTP, TCP, ICMP, Kubernetes resources, and checks supplied by a host agent. monitra monitor add --name example --target https://example.com --kind http --interval 30 creates one.

A Check result records when a check ran, whether it succeeded, latency, and an optional message. monitra monitor history <ID> reads those observations.

An Alert records a monitor status transition and its notification outcome. monitra alert list shows recorded events, including whether delivery was sent or queued for retry.

An Agent is a registered process that pushes local checks to the backend. A Region is an optional label on an agent’s network vantage point. Region-tagged agents can probe HTTP, TCP, and ICMP targets for comparison through monitra monitor regions; Kubernetes checks are not assigned for regional probing.

Statuses include Pending before the first check, Up, Down, Paused, Stale when a feed or check becomes unreliable, and Unknown when an invalid stored interval quarantines that monitor. A quarantined monitor is skipped and has reason invalid stored interval; it does not fire a down alert. Monitra treats missing evidence as unknown or stale, rather than claiming the target is down. See Agents and Alerting.

CLI reference

All commands start with monitra. Use monitra <command> --help for parser help. Arguments in angle brackets are required; square brackets indicate optional values. There are no implicit defaults for required monitor add flags.

CommandArgumentsAction
monitra version—Print build version.
monitra start[--config <PATH>] [--bind <ADDR>] [--retention-days <DAYS>]Run the daemon; default bind 127.0.0.1:8080. --config replaces ./monitra.toml in the project config layer. Raw-result retention defaults to 7 days.
monitra setup—Run the optional config wizard.
monitra tui[--url <URL>] [--token <TOKEN>]Run the terminal client; without --url, start a local backend.
monitra web[--url <URL>] [--token <TOKEN>]Print the browser URL and token; without --url, serve a local backend.

tui and web resolve remote tokens from --token, then resolved configuration (including MONITRA_API_TOKEN). Their --token flag is ignored in embedded mode.

Monitors

CommandArgumentsAction
monitra monitor add--name <NAME> --target <TARGET> --kind <KIND> --interval <SECS> [--agent-id <ID>]Add a monitor. Kinds: http, tcp, icmp, k8s-deployment, k8s-stateful-set, k8s-service, host-agent-check. Supply --agent-id for agent-fed checks. Intervals must be 1..=86,400 seconds.
monitra monitor list—List monitors.
monitra monitor show<ID>Show one monitor.
monitra monitor edit<ID> [--name <NAME>] [--target <TARGET>] [--interval <SECS>] [--agent-id <ID>]Change a monitor.
monitra monitor remove<ID>Delete a monitor.
monitra monitor pause<ID>Pause checks.
monitra monitor resume<ID>Resume into Pending.
monitra monitor history<ID> [--since <UNIX_SECS>]Show check results at or after the timestamp, capped at the retention cutoff.
monitra monitor regions[--since <UNIX_SECS>]Compare regional latency and failures since the timestamp, capped at the retention cutoff.

Agents, collectors, and services

CommandArgumentsAction
monitra agent register--name <NAME> --scope <SCOPE> [--region <REGION>]Register an agent and issue its push token.
monitra agent list—List agents.
monitra agent remove<ID>Deregister an agent.
monitra agent run--name <NAME> --scope <SCOPE> --backend-url <URL> --agent-id <ID> [--token <TOKEN> | --token-file <PATH>] [--config <PATH>]Run local checks and push results. Token or token file is required at runtime.
monitra k8s attach--name <NAME> --kubeconfig <PATH> [--context <CONTEXT>] [--namespace <NAMESPACE>]Attach a cluster; omitted context uses kubeconfig’s current context, omitted namespace uses default.
monitra k8s list—List attached clusters.
monitra k8s detach<NAME>Detach a cluster.
monitra service attach<URL>Configure a Store, Cache, or Notifier provider by URL.
monitra service detach<NAME>Clear store, cache, or notifier configuration.
monitra service list—List effective provider configuration and sources.
monitra alert list—Show recorded alert history, newest first.

Configuration commands write the XDG config and take effect on the next monitra start. monitra service manages providers, not an operating system service. See Providers.

HTTP API

Human API routes require a bearer token. GET /health is unauthenticated.

POST /monitors and PATCH /monitors/{id} accept interval_secs from 1 through 86,400. Invalid values return HTTP 400 with a backend: monitor interval_secs error.

Monitor responses include status and status_reason. status may be Pending, Up, Down, Paused, Stale, or Unknown. A legacy row with an invalid stored interval is returned as Unknown with status_reason: "invalid stored interval". The scheduler does not check that monitor until its interval is repaired. Quarantine never creates a Down alert.

GET /health includes quarantined_monitors, the current count of invalid-interval monitors skipped by the scheduler. This count updates on scheduler resync.

GET /monitors/{id}/history and GET /regions accept optional since Unix seconds. The server applies the later of since and the configured raw-result retention cutoff. Uptime percentages in clients use only the returned retained samples. GET /alerts reads stored alert events; it does not calculate from raw check results.

Configuration

Monitra uses embedded defaults if both config files are absent. Effective precedence, lowest to highest, is XDG config, ./monitra.toml, environment variables, then applicable CLI flags. monitra start --config <PATH> uses that file in place of ./monitra.toml. Configuration commands write only the XDG file, never the project file.

The k8s array is assembled from both files (XDG entries followed by project entries); unlike provider fields, the second file does not replace the first array.

LocationPurpose
$XDG_CONFIG_HOME/monitra/config.tomlUser config; falls back to $HOME/.config/monitra/config.toml.
./monitra.tomlOptional project config.
$XDG_DATA_HOME/monitra/monitra.dbDefault SQLite database; falls back to $HOME/.local/share/monitra/monitra.db.

Both config files use the same TOML keys:

# Leave provider URLs absent to use embedded defaults.
api_token = "choose-a-secret-token"
retention_days = 7

[[k8s]]
name = "production"
kubeconfig = "/path/to/kubeconfig"
context = "production"
namespace = "default"
KeyMeaningDefault
storeLegacy external Store URL; unsupported values fail startup. Remove with monitra service detach store.Embedded SQLite.
cacheLegacy external Cache URL; unsupported values fail startup. Remove with monitra service detach cache.In-process cache.
notifierwebhook://… or slack://… target.Log notifications.
api_tokenBackend bearer token.Generated and saved on first backend start, then printed once.
retention_daysRaw check-result retention, 1..=3650 days.7 days.
k8sArray of cluster entries with name, kubeconfig, optional context, optional namespace.No clusters.

MONITRA_STORE, MONITRA_CACHE, MONITRA_NOTIFIER, MONITRA_API_TOKEN, and MONITRA_RETENTION_DAYS override the corresponding file values. monitra start --retention-days <DAYS> has highest precedence for retention. External Store and Cache values are currently unsupported, including through environment variables. monitra setup prompts for a Notifier URL; a blank answer keeps the default. monitra service attach webhook://hooks.example.com/path is another way to set a provider in the XDG file. Changes are read at daemon startup; restart to apply them.

Providers

Monitra has four provider categories. The default build needs no external service. monitra service attach <URL> writes a Store, Cache, or Notifier URL to the XDG config; Kubernetes collectors use monitra k8s attach instead.

CategoryDefaultConfigured option and current statusFailure behavior
StoreSQLitePostgreSQL is not implemented; postgres:// and postgresql:// are unsupported.Startup fails with a named error; history is never silently moved to another store.
CacheIn-processRedis is not implemented; redis:// is unsupported. Current daemon use is limited to health reporting.Unsupported configuration fails startup. An implemented cache that later becomes unreachable would degrade under §4.1.
NotifierLog sinkwebhook://host/path posts JSON to https://host/path. slack://host/path posts to https://host/path when built with optional slack feature. Both are implemented.Failed sends enter a bounded retry queue; a build without slack rejects that URL at startup.
CollectorNoneKubernetes resource collector requires optional kubernetes feature and an attached cluster.Collector errors become unknown/stale for affected monitors and are logged.

webhook:// and slack:// are configuration markers, not transport protocols. The notifier converts each to HTTPS. Without a notifier URL, alerts are logged instead of sent. Optional Cargo features are slack and kubernetes. See Alerting and Kubernetes.

Alerting

Monitra emits an alert when a monitor’s evaluated status changes. The engine formats a transition message, passes it to the configured notifier, and records an alert event with the monitor ID, new status, time, attempted sink, and delivery outcome.

monitra alert list

The default notifier logs messages. A configured webhook://hooks.example.com/path sends a JSON message over HTTPS. With the slack Cargo feature, slack://hooks.example.com/services/path sends a Slack text payload. See Providers.

The alert request channel holds 256 entries; if full, it drops the newest request and logs a warning. The notifier retry queue also holds 256 entries; on overflow it drops the oldest and logs it. Failed deliveries are recorded as queued for retry, with retries on a 30-second interval. Alert history remains queryable even when delivery fails. monitra alert list shows all recorded events, newest first; monitor detail also has per-monitor alert history.

Agents

An agent pushes local host checks and regional network probes to a Monitra backend. Register it first, then save the issued push token. Re-registering the same name issues a new token and revokes the old one.

monitra agent register --name host-a --scope host --region eu-west
monitra agent list
monitra agent run --name host-a --scope host --backend-url http://127.0.0.1:8080 --agent-id 1 --token-file /path/to/token --config /path/to/checks.toml

--token and --token-file are mutually exclusive. The check file is optional; an agent with no local checks still pushes an empty batch as a heartbeat. A supplied but missing check file is an error. A check file can define disk, systemd, and process checks tied to existing host-agent-check monitor IDs:

interval_secs = 30

[[checks]]
kind = "disk"
monitor_id = 1
path = "/"
min_free_pct = 10.0

Create that monitor with monitra monitor add --name root-disk --target / --kind host-agent-check --interval 30 --agent-id 1. The agent fetches regional assignments and probes HTTP, TCP, and ICMP targets from its location. monitra monitor regions compares observations from region-tagged agents. Omitting --region excludes an agent from regional aggregation; repeating registration without it clears a prior region. Kubernetes monitors are not regional assignments.

Failed pushes are buffered up to 256 results by default; overflow drops the oldest with a warning. The agent attempts a final flush on SIGINT/SIGTERM. Host agent Kubernetes fallback polling is not yet implemented. See Limitations.

Kubernetes

Kubernetes collection is optional. Build with the kubernetes Cargo feature, attach a cluster, then create a Kubernetes monitor whose target identifies the resource to inspect.

cargo build --release --features kubernetes
monitra k8s attach --name production --kubeconfig /path/to/kubeconfig --context production --namespace default
monitra k8s list
monitra monitor add --name api --target production/default/api --kind k8s-deployment --interval 30

The CLI also accepts k8s-stateful-set and k8s-service kinds. Omitted context selects the kubeconfig current context; omitted namespace uses default. Cluster attachments are saved in XDG config and take effect on the next daemon start. monitra k8s detach production removes one.

The engine polls a collector at each monitor’s interval. If the collector cannot be created or queried, it logs the error and records an unknown observation; it does not assert that the resource is down or stop the whole daemon. Without the kubernetes feature, no collector factory is available. See Providers.

Deployment

The release page provides static Linux binaries. The compose example uses ghcr.io/rustiqz/monitra:latest, binds the web API to host loopback port 8080, and persists /data in a named volume. The image sets XDG_DATA_HOME=/data and XDG_CONFIG_HOME=/data/config, so its default SQLite database is /data/monitra/monitra.db (DESIGN.md §11.14). Keep the volume across image upgrades. For a host bind mount, make the directory writable by UID 10001.

docker compose up -d
docker compose exec monitra monitra --version

Save the API token from the first start. On first startup the container generates a human API token and prints it once, to the container log. Copy it from docker compose logs monitra straight away; it is not shown again. It is also stored in /data/config/monitra/config.toml inside the volume, and you can supply a token yourself through MONITRA_API_TOKEN.

Build the release binary from source with Rust and Node/npm available. A Linux musl static build also needs the Rust musl target and musl-gcc (provided by musl-tools on Ubuntu):

rustup target add x86_64-unknown-linux-musl
CC_x86_64_unknown_linux_musl=musl-gcc cargo build --release --target x86_64-unknown-linux-musl

Run monitra start to serve the API and embedded web dashboard. It binds 127.0.0.1:8080 by default. monitra start --bind 0.0.0.0:8080 listens on all interfaces; choose a bind address appropriate to your network. Human API routes require the bearer token saved in XDG config or supplied through MONITRA_API_TOKEN; /health is public, and agent ingestion uses a separate per-agent token. On first startup without a human token, Monitra generates and prints one once.

For a remote client, pass the daemon URL and token to monitra tui --url <URL> --token <TOKEN> or monitra web --url <URL> --token <TOKEN>. The latter prints a URL and token to enter in the browser; it does not start a second remote server. The backend serves until SIGINT/SIGTERM and coordinates an engine and HTTP drain on shutdown.

Provider configuration is loaded at startup. monitra service attach <URL> configures a provider for the next start; it does not manage an operating system service. See Configuration.

Limitations

Current behavior has these boundaries:

  1. PostgreSQL Store and Redis Cache are not implemented. Their Cargo features were removed; configured URLs fail startup with a named unsupported-provider error. Clear legacy values with monitra service detach store or monitra service detach cache.
  2. Agent-side Kubernetes fallback polling is not yet implemented. Kubernetes collection uses the daemon’s optional collector.
  3. SIGINT/SIGTERM are wired into daemon shutdown, but shutdown still depends on task drain completing; inspect logs if a process does not exit promptly. The engine has a 10-second drain deadline.
  4. The cache is currently used for health reporting; engine and backend do not yet use Cache::get or Cache::set for data caching.
  5. Remote tui and web token resolution checks --token, then environment/config. An error suggests monitra setup, but setup does not generate a token; generation happens on backend start.
  6. Hourly and daily rollups from DESIGN §5.4 are not yet implemented. Uptime percentages use retained raw samples only and are not a 90-day statistic.
  7. monitra monitor history <ID> --since <UNIX_SECS> accepts Unix seconds without an upper bound check. Very far-future queries are not rejected in the CLI.
  8. Kubernetes resources are polled on each monitor’s interval, rather than a separate global collector interval.

See Configuration for supported defaults and Providers for current provider availability.

Contributing

The repository contribution guide covers the project workflow. The design document contains the architecture and ADRs in section 9.

Before proposing a code change, run the repository’s development checks:

cargo build --workspace
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --all --check
python3 scripts/dep-check.py

The backend build script requires Node/npm on PATH, including when Cargo builds or tests workspace crates. Documentation pages live in docs/site/src/ and can be built with mdbook build docs/site.