Register an agent
From Monitor settings in the dashboard, choose Register agent and give it a name. The token is shown once, at creation, alongside the exact install command with that token already filled in. If you lose the token, revoke it and register a new one: tokens are stored hashed, so nobody at RealUptime can read yours back to you.
Install
Linux, one line (Docker if it is there and usable, otherwise a hardened systemd service under your existing Node.js 22+), first metrics within about a minute:
curl -fsSL https://realuptime.io/agent/get | REALUPTIME_TOKEN=rua_your_token_here shThe script downloads the release and its checksums, refuses to unpack on a mismatch, verifies the release signature when cosign is installed, and puts the token in a root-only file rather than on a command line. Re-running it upgrades in place. It is the same file reviewed at apps/agent/install/install.sh in the repository, served byte-identical from this site.
The installer script itself is versioned and checksummed, so you can verify it before piping anything into a shell:
curl -fsSLo agent-install.sh https://realuptime.io/agent/install.sh
curl -fsSL https://realuptime.io/agent/install.sh.sha256 | sha256sum -c
REALUPTIME_TOKEN=rua_your_token_here sh agent-install.shThe ghcr.io/realuptimehq/agent package is not public yet. Until that setting flips, an anonymous pull against it fails with "unauthorized", including the Docker half of the one-liner above on any host where Docker is already installed and usable, since that is the path it picks by default. The installer says exactly this (not a bare docker error) when a pull is denied, and names the fix: add --method systemd to force the systemd path, which needs only Node.js 22 or newer and no Docker at all. Once the package is public, both paths work with no flag needed.
Docker, one command (works once the package above is public):
docker run -d --name realuptime-agent --restart unless-stopped \
--network host \
-e REALUPTIME_TOKEN=rua_your_token_here \
ghcr.io/realuptimehq/agent:latestDocker Compose:
services:
realuptime-agent:
image: ghcr.io/realuptimehq/agent:latest
restart: unless-stopped
network_mode: host
environment:
REALUPTIME_TOKEN: rua_your_token_hereBoth carry host networking on purpose. An agent watching its own host has to share that host's network, or localhost means the container and every check against a host-local service is refused while the service is healthy. Drop the flag only if you mean to watch the container itself.
Windows Server
From an elevated PowerShell, with Node.js 22 or newer installed:
iwr -useb https://realuptime.io/agent/install.ps1 | iex; Install-RealUptimeAgent -Token rua_your_token_hereThis registers a Scheduled Task that starts at boot as LOCAL SERVICE and restarts on failure. A task rather than a Windows service on purpose: node.exe is not a Service Control Manager binary, and the usual fix is a third-party wrapper, which would put someone else's code on your machine. If you already run WinSW, pointing it at node.exe dist\agent.js works the same.
Kubernetes
A DaemonSet runs one agent per node, reading the node's own /proc, /sys and /run through a read-only mount of its root filesystem, so each pod reports its node's health, not its own. A token identifies one reporting host, so register one agent per node and put the tokens in one Secret keyed by node name; the manifest hands each pod exactly its own node's key. Set REALUPTIME_CLUSTER in the manifest to your cluster's name and the dashboard groups the nodes under it.
kubectl create namespace realuptime
kubectl -n realuptime create secret generic realuptime-agent-tokens \
--from-literal=node-a=rua_token_for_node_a \
--from-literal=node-b=rua_token_for_node_b
kubectl apply -f https://raw.githubusercontent.com/realuptimehq/realuptime/main/apps/agent/deploy/kubernetes/daemonset.yamlmacOS, or from source
Node.js 22 or newer:
pnpm install
pnpm --filter @realuptime/agent build
REALUPTIME_TOKEN=rua_your_token_here node dist/agent.jsRun it under whatever supervisor you already use (launchd on a Mac). A minimal systemd unit:
[Unit]
Description=RealUptime Monitor agent
After=network-online.target
[Service]
ExecStart=/usr/bin/node /opt/realuptime-agent/dist/agent.js
Environment=REALUPTIME_TOKEN=rua_your_token_here
Restart=always
RestartSec=10
User=realuptime
NoNewPrivileges=true
ProtectSystem=strict
PrivateTmp=true
[Install]
WantedBy=multi-user.targetThe hardening directives in that unit are safe to keep. The agent writes nothing to disk.
apt and yum packages are built by scripts in the repository (apps/agent/packaging) and will be published when the package repository exists; until then the line above is the Linux install.
Verify the image
Published images are signed with cosign, using a key pair generated for this purpose rather than GitHub's keyless OIDC flow: this image is built and published from operator hardware, not a GitHub Actions runner, so there is no OIDC token for cosign to use. Each build also carries a software bill of materials (SPDX, generated with syft) and a provenance record naming the builder, the git commit, and the build time, attached to the same image as signed attestations.
Verify a pulled image against the public key this site serves:
cosign verify --key https://realuptime.io/.well-known/cosign.pub \
ghcr.io/realuptimehq/agent:latestCheck the software bill of materials the same way:
cosign verify-attestation --key https://realuptime.io/.well-known/cosign.pub \
--type spdxjson ghcr.io/realuptimehq/agent:latestThe public key lives at a stable address, realuptime.io/.well-known/cosign.pub, not a page-specific download link, so a script can fetch it the same way every time. Signing rolls out with the image's first signed release: an image published before that date has no signature to check, and cosign verify failing against an older pull means exactly that, not a broken install.
The systemd install resolves latest from this agent's public mirror repository (github.com/RealUptimeHQ/realuptime-agent), never from RealUptime's private monorepo, which an anonymous request cannot reach at all. Pin a build with --version 0.3.1 (or REALUPTIME_AGENT_VERSION=0.3.1), and see what a run would resolve without installing anything with install.sh --print-version.
Configuration
Environment variables only. There are no flags and no config file.
| Variable | Required | Default | Purpose |
|---|---|---|---|
REALUPTIME_TOKEN | Yes | none | The agent token from the dashboard. |
REALUPTIME_URL | No | https://realuptime.io | Override only for a self-hosted or staging deployment. |
REALUPTIME_TOKEN_FILE | No | none | A path to read the token from once, at start, for Kubernetes (one Secret key per node) and Docker secrets. |
REALUPTIME_SECRET_<NAME> | No | none | The value of a secret an authenticated check references as ${SECRET:NAME}. Read when the check runs, never logged, and never sent to RealUptime: the check carries only the name. |
REALUPTIME_SECRETS_FILE | No | none | A path to a NAME=value file for secrets no variable sets. Re-read when it changes, so a rotated credential needs no restart. |
REALUPTIME_AUTH_HEADERS | No | none | Header names this agent may send a secret in, beyond Authorization, Proxy-Authorization, Cookie and X-Api-Key. Set on this machine only; RealUptime cannot add one. Authenticated checks need agent 0.4.0 or later. |
REALUPTIME_CLUSTER | No | none | A label: which cluster this host belongs to. The dashboard groups hosts by it. |
REALUPTIME_NODE | No | the hostname | A label: this host's node name. |
A missing token is the only condition that stops the agent. Everything else, including a rejected token, is retried indefinitely.
The one setting that arrives from RealUptime rather than the environment is the service watch list: the names of services you asked the dashboard to report status for on this host. It can only name a unit (the agent checks the shape again on receipt), and it is applied on every poll.
Outbound only
The agent opens outbound HTTPS on port 443 to one hostname, and nothing else. It opens no inbound port: nothing can connect to it, and there is no listening socket to expose, scan, or firewall. It never runs a shell and never runs anything RealUptime names: there is no remote command channel, and nothing in the poll response can name a program or a path. RealUptime can tell it which addresses to check, how often, and which service names to report the status of, and nothing else. There is nothing in this program by which RealUptime, or anyone who compromised RealUptime, could run anything on your machine.
On Linux it runs no external program at all: every reading is a file under /proc, /sys or /run. On macOS and Windows, which expose no such files, it runs a short fixed list of stock read-only operating-system programs with fixed arguments (vm_stat, df, netstat, ps, launchctl list, sw_vers on macOS; one constant PowerShell script, with wmic as a disk fallback, on Windows), listed in the agent's source as the complete allow-list; anything else is refused before it is looked up. A watched service name is matched in the agent after a listing of all services returns, so a name you typed never reaches a command line.
It reads no configuration file, no credentials, and none of your data. For an HTTP check it reads the status line and immediately aborts the response body, never buffering, inspecting, or logging it. A TCP check writes nothing to the socket and reads nothing from it. A DNS check reads only the records it queried for. A process is reported by id and executable name only, never its command line, environment or owner.
If you run it inside a container
If the agent itself runs inside a container, its server-health metrics describe the container, not the underlying host, and RealUptime records them that way: this is a real, useful thing to monitor, not a limitation to work around. CPU, memory, and disk figures then reflect the container's own resource limits, which can be very different from the host machine's. The vantage a token first reports under is pinned: if the agent later reports a different vantage on the same token (moved from a container to the host, or back), RealUptime refuses the batch rather than silently mixing a different kind of reading into the same history. Register a new agent token for the new vantage instead.
If your goal is host-local targets, services bound to localhost or a host-only interface, or you want the machine's own CPU, memory, and disk rather than the container's, run the agent with host networking, or directly on the host, not inside an isolated container. The install commands above already do this: --network host for docker run, network_mode: host for Compose.
An agent that finds itself in a container with a network of its own says so. It reports that with its host identity, logs the fix on its own output at startup, and its page in the dashboard carries the warning; a check of its that targets localhost and comes back refused is shown as an agent that cannot see the host's network rather than as a service that is down.
What data is collected
Once a minute the agent takes one sample of the machine it runs on and posts it. The four core readings below are the same on Linux, macOS and Windows Server (Windows has no load average and reports none); agents from version 0.2 add network I/O per interface, the top processes by CPU and memory (executable name only), containers from cgroup v2 on Linux, and the status of services you name. See server health for what each shows.
| Field | Unit | Source |
|---|---|---|
| CPU used | fraction of total capacity across all cores, 0 to 1 | /proc/stat, delta between two readings |
| Memory used | bytes, total minus available (not minus free) | /proc/meminfo |
| Disk used | bytes, per mounted filesystem, up to 32 | /proc/mounts plus a statvfs reading |
| Load average | raw 1/5/15 minute kernel averages, not normalized by core count | /proc/loadavg |
Each check result the agent sends is a check id, up or down, an HTTP status code where there is one, a latency in milliseconds, an error string when the check failed, and the timestamp of the observation. Nothing about a machine's process list, file listing, or their contents is ever sent. See server health for what the charts built from this data show, and when they alert you.