Demo mode — this is a read-only sandbox with fake data. Browse anything. Nothing here can be modified. Run your own →
Live
Fleet at a glance
Everything that needs your attention, in one screen.

Upcoming

next events from the calendar & scheduler

Open tickets

Recently acknowledged

Fleet health

Fleet heat map

health score per device — green healthy, red needs attention

Needs attention

Recent activity

Fleet roster · 7-day status

Offline hosts

Pending updates

CVE exposure

Config drift

Resource pressure

Fleet by group

Monitoring coverage

Stale agents

Mailbox watch

On-call now

Devices by OS

Agent versions

Device types

Top tags

Ungrouped devices

Recent activity

Attention by severity

Top attention items

Health score

Fleet size

Critical / high CVEs

Updates pending

Drifted files

Recent check-ins

Open alerts by severity

Maintenance windows

Monitor status

Container issues

Disk fill ETA

Devices by subnet

Patch compliance

Agent vs agentless

Never checked in

Lowest health hosts

Health grade spread

Agent version skew

Offline by group

Reboot required

World-exposed ports

Failed services

Failed timers

Disk SMART failures

UPS on battery

Over temperature

Backup jobs

Mount issues

Clock skew

Gateway unreachable

Recent OOM kills

Storage degraded

New ports (recent)

Firewall changes

SSH keys added

Expiring certificates

Active brute-force

Top bandwidth

Checks roll-up

Integration health

Alerts

Device Control
Manage and remotely control enrolled devices
0
Total devices
0
Online
0
Offline
Enrolled Devices
0 selected
Monitoring
Probes, device metrics, ports, and custom health checks
Targets
LabelTypeTargetStatusDetailChecked
No monitors configured.
Device metrics
Device Alert Memory Swap CPU load Disks
SNMP devices
Device Alert CPU Memory Storage Temp Uptime
No SNMP devices yet — enable SNMP on an agentless device's Settings tab.
Listening Ports
Loading…
Scripts
Running on
Failing
All OK
Script Device Group Status Last output Last run Duration
Click Refresh to load results.
Top Processes
Process PID Device CPU % Mem %
Click Refresh to load.
Users & Roles
Manage who can access this dashboard and what they can do. Built-in roles: admin (full control) and viewer (read-only). Define custom roles to grant specific actions on specific device groups/tags.
Accounts
UsernameCreatedRoleMFASource
Custom roles
A custom role grants a subset of actions — exec, reboot, upgrade — limited to a scope (all devices, or only named groups/tags). Members can act on their scope and see only those devices on the Devices roster; server config, user/role management and saved scripts stay admin-only.
Loading…
My Account
Your personal settings — these apply to you only, not the whole server.

Profile

?
Signed in as

PNG, JPEG, GIF or WEBP, up to 512 KB. It's downscaled in your browser before upload.

Language

Choose the interface language. Saved to your account and synced across devices.

Appearance

Interface

New UI is the Industrial interface (default); Old UI restores the classic look. Colour themes below apply to the Old UI.

Pick a theme for this browser. Follow system tracks your OS light/dark setting. The accent tints buttons and highlights on top of any theme.

Theme
Accent
Background

Permissions

What your role lets you do. Managed by an administrator under Users & roles.

Two-Factor Authentication (2FA)

Protect your account with an authenticator app (Google Authenticator, Authy, etc.).

SSH preferences

Your default SSH username. Used by the quick-SSH link on the Devices page so you don't retype it each time. Stored per-user, not shared.

My acknowledged alerts

Open alerts you've taken ownership of (acknowledged but not yet resolved).

Active sessions

Browsers and devices currently signed in as you. Revoke any you don't recognise.

Settings
Server configuration

Getting started

A quick checklist of the essentials for a new RemotePower install. Each step reflects your current state and links straight to where to do it.

Loading…

Interface

Choose how RemotePower looks. New UI is the Industrial interface (graphite & steel with the RemotePower blue) — the default. Old UI restores the previous look. The choice is saved in this browser and applies instantly; switch back any time. Colour themes under My Account → Appearance apply to the Old UI.

Server identity

Display name shown in the page title, push notification subject lines, and webhook payloads. Helps tell instances apart when you have more than one.

Default poll interval

How often newly-enrolled agents heartbeat back to the server. Existing devices are not affected — change theirs from the device detail page.

10–3600 (default 60)

Online TTL

A device is considered offline if no heartbeat is received within this window. Should be at least 2 × poll_interval to avoid false offline alerts during a single missed poll.

90–7200 (default 180)

Monitor check interval

How often monitors auto-check when the Monitor page is open. Also controls server-side offline/patch check frequency.

60–3600 (default 300)
consecutive over-threshold checks before a CPU/memory/disk/swap alert fires (1 = default, alert on first breach)
consecutive failed SNMP polls before SNMP unreachable fires (2 = default)

Wake-on-LAN

Magic packets are sent via UDP broadcast from the server. Adjust if your network uses a directed broadcast address.

Healthchecks.io watchdog

RemotePower pings this URL on a fixed interval so an external watchdog (Healthchecks.io, BetterStack, your own) flips red when the server stops serving requests. Off by default. Cadence defaults to 60 s, minimum 30 s.

Alerts inbox

When on, acknowledging an alert (single or "Ack selected") asks for an optional comment. The comment is stored on the alert and included in the acknowledgement webhook. Turn this off to acknowledge in one click.

Webhook destinations

Fire each event to any number of destinations simultaneously. Each entry has its own format adapter (Discord, Slack, Pushover, Teams, ntfy, generic JSON) and optional per-destination event filter. Use case: Pushover for critical-only push notifications + Discord channel for all events.

Pushover credentials (token + user key) are stored encrypted in config.json and redacted from the backup export.

Legacy webhook URL

The original single-URL field, still honoured for backward compatibility. New setups should use "Webhook destinations" above — it supports the same formats plus Pushover, Teams, per-event filtering, and labeling.

✓ Webhook is currently configured

Per-event toggles

Enable or disable each event type. Disabled events are recorded as "disabled" in the webhook log so you can see what was suppressed.

Email notifications (SMTP)

Send the same events via email as a sibling channel to webhooks. Both channels respect maintenance windows. Email is opt-in per event in the table above.

More secure option: set RP_SMTP_PASSWORD in the systemd unit or container env. The env var takes precedence, keeps the secret out of config.json, and is excluded from the backup export.

✓ Password is currently being read from RP_SMTP_PASSWORD. The field above is ignored.

Comma-, semicolon- or whitespace-separated list. All listed addresses receive every enabled event.
Tip: add a self-hosted help-desk's inbound address (osTicket, Zammad, Request Tracker, FreeScout) here to turn alerts into tickets — no extra setup. See Notifications docs.
Email a fleet-posture summary (offline hosts, pending updates, critical CVEs, policy violations, degraded storage) on a schedule. Uses the SMTP settings above; falls back to the Recipients list if no digest recipients are set.

Webhook log

Recent deliveries
TimeEventStatusDetail
No webhook deliveries yet.

Homelab software integrations

Poll popular self-hosted software for health and fold it into Alerts. Pick a type, point it at the service on your LAN, add an API token, and Test. The server polls on a cadence (default 5 min); an unhealthy or unreachable target raises an integration_down alert that recovers automatically.

Uncheck on an enterprise instance to hide this section and the Integration health dashboard widget for everyone (reduces noise). Saved with the button below.

Cloud import (AWS EC2)

Pull EC2 instances into the fleet as agentless device records (tagged cloud / aws / region). Read-only — uses an IAM access key with ec2:DescribeInstances. Re-running updates in place. Other providers come later.

Metrics push (Prometheus)

Periodically POST the fleet's Prometheus metrics (the same exposition served at /api/metrics) to a Pushgateway or compatible remote target — for stacks that pull from a gateway rather than scraping. Off by default. Sent through the SSRF-safe fetcher.

GitOps (config from Git)

Keep your drift profiles (watched-config-file sets) and their tag/group assignments in version control. RemotePower periodically fetches a JSON manifest from a raw Git URL and reconciles the profiles it owns to match it. It only manages watched-file lists and assignments — never command execution or file-content pushes — and host enforcement still follows each device's existing apply/enforce opt-in. Off by default; fetched through the SSRF-safe fetcher; profiles you create by hand are never touched. View drift profiles →

Status endpoint

A machine-readable fleet summary at /api/status for external dashboards — Uptime Kuma, Homepage, Grafana. It needs a status token (not a login), so a monitoring tool can poll it, but it is not public. Generate a token to enable it.

The same token also powers a read-only Home Assistant bridge at /api/ha?token=… — flat JSON shaped for an HA REST sensor (value_template: "{{ value_json.state }}"), with online/offline and alert counts as attributes. One-way: status only, no control.

Inbound webhooks & syslog

Two token types share this table:

  • Alert webhook — POST JSON {severity, title, …} to /api/webhook/in/<token>. Lands in the Alerts inbox. For Grafana, Alertmanager, Authentik, n8n, Home Assistant.
  • Syslog ingestion — POST RFC 3164/5424 lines (JSON {lines:[…]} or plain text) to /api/syslog/in/<token>. Lines append to the device's log_watch under unit syslog; existing log_alert rules fire as normal. For rsyslog (omhttp), fluent-bit (HTTP output), or any tool that can POST. Must be pinned to a device.
Tokens
LabelTypeScopeTokenHitsLast seenStatus
No inbound tokens yet.

Relay satellites

Run a satellite (client/remotepower-satellite.py) inside a segmented network — agents there reach this server through it (agent → satellite → server). Each satellite authenticates with its own token, so you can see and revoke relays independently of the agents. Set the minted token as RP_SATELLITE_TOKEN and RP_UPSTREAM on the satellite host, then point that segment's agents at http://<satellite>:8800.

Loading…

OIDC / OpenID Connect

Sign in via an external identity provider (Authelia, Authentik, Keycloak, Pocket-ID, Google, etc.). Users authenticate against your IdP and arrive with the role mapped from their group membership. Existing local users and LDAP keep working in parallel.

SAML 2.0 (enterprise SSO)

Sign in via a SAML identity provider (Okta, Azure AD / Entra, OneLogin, Ping, ADFS, …). Paste the IdP's entity ID, SSO URL and signing certificate; users arrive with the role mapped from their group attribute. Requires the pysaml2 library and the xmlsec1 binary on the server — when either is missing this stays disabled.

View SP metadata

SCIM provisioning (auto user lifecycle)

Let your identity provider (Okta, Azure AD, OneLogin, …) create and — importantly — deactivate users automatically. When the IdP offboards someone, their access and live sessions are revoked at once. SSO (OIDC/LDAP) only ever creates on first login; SCIM closes the offboarding gap. Endpoint base URL: <your-server>/api/scim/v2. Provisioned users start as viewer.

CVE details cache

How long OSV.dev vulnerability details are cached before being re-fetched. Higher = fewer external requests, lower = newer descriptions on existing CVEs.

1–90 (default 7)

IP allowlist

Restrict UI/API access to specific source IPs. Loopback (127.0.0.1, ::1) is always allowed so the local MCP sidecar keeps working. Agent paths (heartbeat, enrollment, agent download) are exempt — enabling this never blocks an agent. Off by default.

Your current IP: (loading). Add it first if you plan to enable the gate — the save handler refuses to enforce the allowlist while your address isn't in it.

Change approval (maker-checker)

When enabled, risky actions — Run command, reboot, shutdown, package update/upgrade, agent uninstall, and container start/stop/restart — are parked as a pending approval instead of executing immediately. A second admin approves them on the Confirmations page.

Listening-port & firewall audit

When enabled, the audit watches each host's listening sockets and active firewall ruleset, raising New listening port, World-exposed service and Host firewall changed alerts when a port first appears, first binds to a world-reachable address (0.0.0.0), or the firewall fingerprint drifts. This is noisy on Docker hosts, where docker-proxy publishes every container port to 0.0.0.0 — so it is off by default. The Exposure page still shows every socket regardless, so you keep the visibility without the alert noise.

Muted services — silence new-port / world-exposed alerts for a specific process and/or proto/port (e.g. docker-proxy) without turning the whole audit off. You can also mute straight from the Exposure table.

Secrets-on-disk scanning

When enabled, agents scan the paths below for exposed secrets (private keys, API tokens, passwords) and raise a secret_exposed alert when a new one appears. Off by default — it reads files and is heavier than other checks. The scan is redacting by design: the agent never sends a secret's value, only its type, location, a masked preview and a fingerprint. Findings appear on the Exposure page, where you can mute false positives.

Account guardrails

The controls the security-posture self-check (Audit page) grades. Everything enforces immediately on save; MFA-required users are prompted to enrol on their next sign-in.

Audit log forwarding

Mirror every audit entry to an external SIEM (HTTP JSON POST) or a syslog collector (RFC 5424 over UDP/TCP). Best-effort and non-blocking — a forwarding outage never affects local logging.

SIEM event streaming

Stream every fleet event and alert to a SIEM in its native ingest format. Distinct from audit-log forwarding above (which streams the audit trail). Best-effort and non-blocking.

OpenTelemetry export (OTLP)

Push rolled-up fleet gauges (devices online/offline, alerts by severity, health score) to an OTLP/HTTP collector — otel-collector, Grafana Alloy, or any OTLP endpoint. The push piggybacks on agent heartbeats, rate-limited to the interval below. Same metrics Prometheus scrapes at /api/metrics, pushed instead of pulled.

Browser push notifications

When enabled, high and critical alerts are pushed to operators who've turned on notifications in My Account → Browser notifications — even when RemotePower isn't the active tab. A VAPID key is generated automatically on first enable. Uses the Web Push standard; no third-party service.

Multi-tenancy

When enforced, each tenant's admins and operators see only their own devices; a platform superadmin (an admin in the built-in default tenant) still sees everything. Off by default — turning it on partitions the fleet by tenant, so enable it deliberately. Tenants, user-to-tenant and device-to-tenant assignment are managed via the API (/api/tenants, a user's tenant_id, and a device's tenant).

Agentless SSH

Run commands and collect basic metrics on hosts with no agent, over SSH. Off by default. Set an agentless device's reachability to SSH and its SSH user (device drawer), then use Poll/Run there. Connections are non-interactive (BatchMode, key-only, trust-on-first-use); each command is admin-only, allowlist-checked, and audited. The private key is write-only — never returned by the API.

Session length

How long a session lasts. Short by default; "remember me" extends to long.

LDAP / LDAPS authentication

External authentication source. Local users in users.json are tried first — emergency access never depends on LDAP being reachable. Users authenticated via LDAP are auto-provisioned with the role determined by group membership.

ldaps:// for TLS, ldap:// for plain (don't).

More secure option: set RP_LDAP_BIND_PASSWORD in the systemd unit or container env. The env var takes precedence, keeps the secret out of config.json, and is excluded from the backup export.

✓ Bind password is currently being read from RP_LDAP_BIND_PASSWORD. The field above is ignored.

AD: (sAMAccountName={u}) · OpenLDAP: (uid={u}) · FreeIPA: (uid={u})

Content-Security-Policy reporting

When the browser blocks something the CSP forbids (an injected inline script, a stylesheet from a disallowed origin, …) it POSTs a report to /api/csp-report. Each report becomes one audit-log line tagged csp:…. Disable here if reports get noisy; raise the per-IP throttle if you're investigating an active issue.

0 = unlimited. Reports beyond the cap are silently dropped (no log row, still HTTP 204).
CSP reports in the last 24 h:

Audit log

Records every login, command, settings change, and CSP report. Live entries persist in audit_log.json; entries older than the retention window roll into the gzipped archive next to it. Retention is set in Settings → Advanced.

Live entries:
Archive on disk:
Retention window: days

Self-signed certificate

Generate a self-signed CA + server certificate for an internal / airgapped instance that can't use a real (Let's Encrypt) cert. The files are written under the data directory's tls/ folder; point nginx at server.crt / server.key and enrol agents with the printed fingerprint. Re-generating reuses the CA, so the server cert renews without re-trusting agents. Prefer a real cert when you have a public hostname — full guide in docs/tls-selfsigned.md.

Import a certificate (.p12 / .pfx)

Already have a certificate? Upload a PKCS#12 bundle (.p12 / .pfx) containing the certificate and its private key. The cert (plus any chain) and key are written to the data directory's tls/ folder as server.crt / server.key — point nginx at them and reload. The bundle password is optional and never stored.

Transport security (HSTS)

HSTS forces every future visit to use HTTPS — defence against a downgrade attack. Set by nginx, not the application; this panel just reports whether the response on your current page is carrying the header.

Checking…
To enable: uncomment the add_header Strict-Transport-Security line in server/conf/remotepower.conf (or your in-place nginx config), then sudo nginx -t && sudo systemctl reload nginx. Only do this once you're certain the site is HTTPS-only — HSTS is sticky in the browser for the configured max-age.

Branding (white-label)

Set the in-app product name and default accent colour shown to everyone — for MSPs reselling RemotePower. Users can still pick their own accent in My Account → Appearance; this is the org default. (The login-page logo image is unchanged.)

Audit log retention

Entries older than this many days are moved to audit_log_archive.jsonl.gz and kept indefinitely (gzipped, append-only). The live audit_log.json only holds recent entries — keeps the loaded-into-memory file small. Default 90 days. Set to 0 to disable age-based eviction (legacy count-only cap still applies).

Scheduled backup

Daily snapshot of /var/lib/remotepower to a tarball. Triggered once per 24h via the heartbeat hook (cheap when not due). Backup state and a "Run now" button are on the Server status page.

Debug logging

When enabled, verbose logs are written to the browser console (F12 → Console) and to /var/lib/remotepower/debug.log on the server. Disable in production — the log file grows unbounded.

Backup & restore

Two kinds of backup. The redacted export is a ZIP with API keys and integration secrets stripped — safe to store or share. The full disaster-recovery backup is a tar.gz of the entire data directory including the encrypted credentials vault and integration secrets — it can fully rebuild this controller, so keep it private. Restore applies a full backup and overwrites current data; a safety snapshot of the existing data is taken first (under restore-snapshots/ in the data dir).

Storage backend

RemotePower stores all data as flat-JSON files by default. For large fleets with many devices and frequent writes, switch to an embedded SQLite database (WAL mode), or to an external PostgreSQL server for concurrency, replication/HA and central backups. Switching migrates your data in place, verifies the round-trip, and only then flips the active backend — fully reversible (switch back the same way).

Loading current backend…

Data retention & maintenance

Cap how long historical records are kept. Set a value in days; 0 keeps everything (subject only to the per-log count limits). Old entries are pruned automatically once a day, and immediately when you run maintenance below. Open alerts are never purged — only resolved ones past their age limit.

Metric samples (the device Trend charts) are kept as a time-series only on the SQLite or PostgreSQL backend — that's what makes a 30-day point-in-time history practical. On the JSON backend the charts show the recent rolling window only.

Proxmox VE connection

Connect a single Proxmox VE node. The RemotePower server calls the Proxmox API directly to list QEMU VMs (Virtualization page) and LXC containers (Containers page), and to start / shut them down. Authentication uses a Proxmox API token — create one under Datacenter → Permissions → API Tokens.

Note: the API token secret is stored in the server's config.json (file mode 600). It is not encrypted at rest. Use an API token scoped to only the permissions it needs (VM.PowerMgmt, VM.Audit), not a full-access token.

More secure option: set the token secret in the environment variable RP_PROXMOX_TOKEN_SECRET (in the systemd unit or container env) instead of here. When that variable is set it takes precedence, the secret stays out of config.json, and it is not included in the backup export.

✓ The token secret is currently being read from the RP_PROXMOX_TOKEN_SECRET environment variable. The field below is ignored.

Proxmox ships a self-signed certificate by default — if you haven't installed a trusted cert, set Verify TLS to Off. Prefer installing a real certificate.

Off by default — these are destructive. When on, the Virtualization page gains action buttons. The API token needs the matching privileges (e.g. VM.PowerMgmt, VM.Snapshot, VM.Clone, VM.Migrate). With 4-eyes approval on, each action waits for a second admin.

Mailbox monitor

Count messages in a mailbox without IMAP/SMTP. Pick a device, give it one or more directory paths, and the agent counts the regular files in each (a Maildir new folder holds one file per unread message). Tick "Show on dashboard" to surface a device's count as a tile on the Home dashboard.

When any watched mailbox reaches this many messages, RemotePower fires a webhook alert. Leave blank to disable.

AI provider

Wire in an LLM for the AI buttons on the command output, journal, scripts, CVE findings, devices, and notifications. Disabled by default. Cloud providers send the content of the request to a third party; pick a local provider (Ollama or LocalAI) if you don't want data to leave the building.

Leave blank to keep the saved key. Type __clear__ to remove it. Not used for Ollama or LocalAI.

Privacy — what gets sent to the provider

By default, hostnames and IP addresses are stripped from every request before it leaves the building. Long hex strings, bearer tokens, and AWS access keys are always redacted regardless of these toggles. Cleartext journal content and command output are sent only when you explicitly opt in.

Context awareness (v2.1.7)

A small block of background ("you are an assistant inside RemotePower; the agent polls every 60s…") plus a one-line-per-device fleet snapshot is prepended to every AI request. The model stops giving generic Linux advice and starts giving advice that references your devices and your conventions. Project context is non-sensitive. Fleet context contains hostnames and group names by design — if you're on a cloud provider and don't want hostnames egressing, turn the fleet toggle off (project context will stay on).

Knowledge index (RAG) (v3.4.0)

Indexes your own infrastructure — device state, watched services, CVEs, containers, CMDB metadata & docs, runbooks, recent commands and alerts, plus the product docs — so the assistant answers from your fleet instead of generic knowledge. Lexical (keyword) search works with every provider, including Anthropic. Optional embeddings add semantic search when you run an embedding-capable provider. The credentials vault is never indexed.

Test retrieval

See exactly which indexed chunks a question would pull in — no model call, no tokens spent. Useful for checking coverage before you trust the assistant's answers.

Limits

Bounds to keep cloud-provider costs predictable. The token limit is per response. The daily request cap is per user — set to 0 to disable.

Test connection

Round-trip a one-word "say hi" request against the configured provider. Saves a settings round-trip before you start using the AI buttons in anger.

Prompt customization

Each AI feature uses a system prompt to set tone and constraints. Defaults are tuned for general-purpose models. Edit if your model needs different wording (e.g. DeepSeek reasoning models, smaller local models, format-specific quirks). Clearing a field reverts to the default for that feature.

Loading prompts…

Brute-force detection

Counts failed login attempts per source IP in a rolling window. Fires a webhook and shows in Needs Attention when the threshold is exceeded.

Health-score alerts

Fires health_degraded (and a health_recovered follow-up) when a device's fleet health score drops below the threshold. Edge-triggered — one alert per crossing, not every heartbeat. Set to 0 to disable.

Quiet hours

Hold non-critical webhook/email notifications during a daily window — events still land in the Alerts inbox and Recent Activity, they just don't page you overnight. Anything at or above the chosen severity always goes through. The window may cross midnight (e.g. 22:00–07:00).

After-hours activity detection

Flag selected events that fire outside business hours (a login, a new port, a command at 3am is more suspicious). Surfaces as a Needs Attention item. Applies Mon–Fri within the window below; anything outside it counts as after-hours.

On-call & escalation

An unacknowledged critical/high alert should get louder. Define escalation tiers (re-notify your webhook destinations after N minutes unacked) and an on-call rotation (the named person is included in the escalation message). Escalations re-fire the original alert through its existing channels — no extra setup.

Currently on call:

Backup file monitoring

Agent checks the mtime of each configured path on every heartbeat. Fires backup_stale and shows in Needs Attention when a file is older than the threshold.

Process thresholds

Fire process_alert (edge-triggered, with a process_recovered follow-up) when a process whose name matches crosses a CPU or memory threshold. Matched against the agent's top processes each heartbeat.

Log ignore patterns

Regex patterns (case-insensitive). Any log line matching a pattern is silently dropped before storage and alerting — for harmless kernel notes, vendor noise, etc.

Channel routing

For every alert kind, choose which surfaces it appears on. Needs Attention = the priority cards on Home; Recent Activity = the home feed; Alerts = the alerts inbox; Webhook = external delivery (Slack, Discord, etc.). Unchecking a column for a row silences that kind on just that surface — uncheck whole rows for a kind you never want to hear about.

Loading…

Ignored items

Items you've hidden using the × button on Needs Attention cards, device rows on the Containers page, or stale container rows. Click Restore on any entry to bring it back into view.

Loading…
IaC Generator
Generate Infrastructure-as-Code (Terraform, Ansible, Pulumi, Cloud-init) for any managed device. Server collects live state on demand, then the configured AI provider transforms it into IaC. Sensitive env vars and SSH keys are masked before leaving the host.
Generated code will appear here
Click Generate IaC to begin.
No conversation yet. Generate something first.
Command History
Log of all commands sent to devices
Recent commands
TimeActorDeviceCommand
Scheduled Commands
Queue shutdown or reboot at a specific time
Pending jobs
DeviceCommandScheduled forBy
No scheduled jobs.
Plain English → a standard 5-field cron expression, validated and previewed with its next runs. Requires the AI assistant to be configured.
Documentation
How to use RemotePower — quick reference for the common tasks
What's new — v4.7.0 "IntegrationsMatters" — monitor the popular homelab/fleet software you already run (26 integrations), plus run the agent as a container to watch a Docker host (no breaking changes)

v4.7.0 reaches outward: a new server-side integration subsystem polls popular self-hosted software for health and folds it into Alerts, and the Linux agent can now run as a container to monitor a Docker host with no install. Hard-reload once after upgrading (cache remotepower-shell-v4.7.0).

  • 26 homelab software integrations. Pi-hole, AdGuard, TrueNAS, UniFi, Home Assistant, Proxmox Backup Server, Kubernetes/k3s, vCenter/ESXi, Unraid, Traefik, Nginx Proxy Manager, Caddy, Netdata, Grafana, Uptime Kuma, Jellyfin, Plex, Nextcloud, the download clients (qBittorrent, Transmission, Deluge, SABnzbd, NZBGet), the *arr suite (one Servarr connector for Sonarr/Radarr/Prowlarr/Lidarr) + Bazarr, and Overseerr/Jellyseerr. Set them up under Settings → Integrations: pick a type, add a URL + token, Test.
  • Health → Alerts + dashboard. An unhealthy or unreachable target raises an integration_down alert (auto-resolved on recovery) routed through your channels, plus an Integration health dashboard widget and live status badges.
  • Read-only & SSRF-guarded. Every outbound call is blocked from loopback / link-local / cloud-metadata (RFC1918 LAN allowed), re-validated at connect time, no redirects. Credentials are stored server-side and redacted from every response; the raw URL is admin-only.
  • Containerized agent. Enroll device → Generate Docker compose, then docker compose up -d on a Docker host. The agent reads the host's facts (shared namespaces, host rootfs mounted read-only), names itself after the host, and persists credentials in a volume. Multi-arch image at ghcr.io/tyxak/remotepower-agent. Standard caps, no --privileged.
  • Enterprise declutter. A Show Homelab software switch (default on) is an instance-wide kill switch — off stops polling, hides the section, and removes the widget.

See docs/integrations.md and docs/docker-agent.md. Older releases → CHANGELOG.md.

What's new — v4.6.1 — a stability + hardening patch on v4.6.0: SCGI-worker fixes (ICMP ping, Postgres fork-safety), a ReDoS and a defence-in-depth XSS fix, and no more subtitle flash on reload (no breaking changes)

v4.6.1 is a small patch on top of v4.6.0. It fixes two issues that only surface under the optional SCGI prefork worker, closes a ReDoS and a defence-in-depth XSS finding, and removes a brief UI flash on page reload. No breaking changes, no schema changes. Hard-reload once after upgrading (cache remotepower-shell-v4.6.1).

  • SCGI worker: agentless ICMP devices stay online. The persistent worker runs with NoNewPrivileges, which blocked ping's capability elevation, so reachability sweeps reported agentless devices down. The unit now grants CAP_NET_RAW ambiently. Classic fcgiwrap/CGI was never affected.
  • SCGI worker: Postgres fork-safety. A forked worker child inherited the parent's psycopg connection, corrupting the protocol stream (consuming input failed: EOF detected). Each connection is now tagged with its owning PID and transparently reconnected in a child — the same guard the SQLite backend already had.
  • Security: ReDoS in TLS-host validation. _valid_tls_host used a nested-quantifier regex that backtracked catastrophically on a long letter/hyphen run. It now validates label by label in linear time, same accept/reject set.
  • Security: package update count coerced before render. The per-device update badge coerces the upgradable count to a number (or ?) before it reaches innerHTML — a non-numeric value can never become markup. The strict CSP is an independent second barrier.
  • UI: no subtitle flash on reload. Each page's descriptive subtitle is folded into a hover info icon at runtime; on a hard reload it briefly painted as raw text before the script ran. The subtitle is now hidden by default in CSS and revealed inline only in the Old UI.

A stability + hardening patch — every install keeps working exactly as before. See docs/v4.6.1.md. Older releases → CHANGELOG.md.

What's new — v4.6.0 "RepellantMatters" — a new Industrial interface ("New UI") as the default with a one-click New UI / Old UI toggle, plus a project-wide reliability, security and performance polish pass

v4.6.0 gives RemotePower a look of its own — an Industrial interface that replaces the generic dark-slate template, while keeping our blue accent — and pairs it with a thorough sweep across the whole project: bug fixes, security hardening, performance, and data-binding polish. A toggle lets anyone keep the old look. Hard-reload once after upgrading (cache remotepower-shell-v4.6.0).

  • Industrial "New UI" (default). Warm graphite/steel palette (keeping the RemotePower blue), with the sidebar/nav set in self-hosted IBM Plex Mono and the rest of the UI in the familiar Inter, plus instrument-panel motifs: corner ticks on panels, dashed technical rules, mono uppercase eyebrow labels, tabular figures, sharper corners. A genuine re-skin of the chrome (sidebar, headers, cards, tables, controls) via body[data-ui="industrial"].
  • New UI / Old UI toggle. A new Settings → Interface tab (and a control in My Account → Appearance, so non-admins can switch too) flips between the Industrial look and the classic one. Per-browser, default New, applied instantly with no reload.
  • Navigation tidy-up. A dedicated Admin group (Links now lives there), and every sidebar group is alphabetically sorted for quicker scanning.
  • Bind-it-together & polish. The device drawer now shows CPU model, kernel, total RAM and total disk alongside the live usage; more lists and tables cap at ~15 rows then scroll internally; the disk-forecast table sorts correctly by GB and percent.
  • Security hardening. Tighter SSRF guards on appliance / integration targets, resolved-role checks on a couple of read endpoints, and hardened agent credential storage on Windows and macOS. Independently pentested clean (see the security review).
  • Performance. Fewer per-tick round-trips on the dashboard, single-row reads on a hot path, and lighter agent heartbeats (cached tool lookups, no blocking uptime probe).
  • CSP-safe by construction. Pure CSS plus one data-ui attribute; the toggle is wired through the existing data-action dispatch with no inline scripts, styles or on* handlers.

Switch the look any time under Settings → Interface. See docs/v4.6.0.md. Older releases → CHANGELOG.md.

What's new — v4.5.0 "TrustMatters" — TLS onboarding: a one-command self-signed CA, fingerprint-verified rollout to agents, Docker opt-in TLS, and a server-only self-signed → real migration (no breaking changes)

v4.5.0 makes TLS easy to stand up where a real cert is hard — internal / airgapped / no-public-DNS instances. A real cert is still recommended. Hard-reload once after upgrading (cache remotepower-shell-v4.5.0). Full guide: docs/tls-selfsigned.md.

  • Self-signed CA, not a bare cert. make tls-selfsigned HOST=rp.internal (tools/gen-ca.sh) generates a private CA + a server leaf (ECDSA P-256, SAN, serverAuth), installs the leaf for nginx, and prints the CA's SHA-256 fingerprint. Agents trust the CA, so make tls-renew re-issues the server cert without touching any client.
  • Fingerprint-verified rollout. install-client.sh --server https://rp.internal --ca-fingerprint <sha256> (and the macOS / Windows installers) fetch /ca.crt over HTTP and refuse to trust it on a fingerprint mismatch — a safe bootstrap with no TLS yet. The CA is wired in via RP_CA_BUNDLE; full verification (hostname + TLS 1.2 floor) is never weakened.
  • One nginx routing snippet. The HTTP and HTTPS server blocks now include the same remotepower-locations.conf (and serve /ca.crt) so they can't drift — HTTPS is a clean uncomment.
  • Docker opt-in TLS. RP_TLS_SELFSIGNED=1 makes the container generate a CA+leaf into the data volume on first boot and serve HTTPS on :8443, printing the fingerprint to docker logs.
  • Self-signed → real is server-only. Agents trust the system roots and the CA simultaneously, so you point nginx at a real (Let's Encrypt) cert and reload — agents keep working with no redeploy.

A TLS-onboarding release — HTTP-only and real-cert installs are untouched. See docs/v4.5.0.md and docs/tls-selfsigned.md. Older releases → CHANGELOG.md.

What's new — v4.4.1 "DocumentationMatters" — a documentation + triage release: every open CodeQL code-scanning alert triaged (all false positives), a documentation-coverage pass, and two no-behaviour weak-hash annotations (no code-behaviour changes)

v4.4.1 resolves the open CodeQL code-scanning alerts and runs a documentation-coverage sweep. No runtime behaviour changed. Hard-reload once after upgrading (cache remotepower-shell-v4.4.1).

  • All 13 CodeQL alerts are false positives. Each (1 Critical, 12 High) was read against the actual code path and the feature that governs it — none is an exploitable vulnerability. The full write-up, mapping every alert to the feature/function that already covers it, is in docs/security-review-4.4.1.md.
  • XSS / DOM-as-HTML (7). Every flagged innerHTML assignment interpolates only values that pass through the project's escHtml() / escAttr() sanitizers, which CodeQL's default model doesn't recognise; the strict no-inline CSP is an independent second barrier.
  • SSRF (1, Critical). fetch('/api' + path) is the same-origin front-end API client — an origin-pinned relative path, never a user-supplied host. Not request forgery.
  • Weak hashing (2). One points at the audit-log chain, which is HMAC-SHA256 (strong); the other is a non-security dedup key already marked usedforsecurity=False. The two MD5 cache-key fingerprints now carry usedforsecurity=False too — the signal the scanner honours.
  • Clear-text logging / storage (3). The admin-gated diagnostics download (by design, no-store), a non-sensitive stderr diagnostic, and the app's own atomic chmod 0600 data-file write — none is a secret-disclosure path.
  • Documentation pass. A sweep across the in-app docs, README, Manual and per-version notes confirmed every shipped feature/function is documented and the headline counts are accurate (65 webhook events, the 66-widget dashboard catalog, 18 MCP tools).

A documentation + triage release — every install keeps working exactly as before. See docs/v4.4.1.md and docs/security-review-4.4.1.md. Older releases → CHANGELOG.md.

Older releases — v4.0.0 and earlier

Per-release notes for the five most recent versions are kept above. The complete, forensic release history — every version, newest first — lives in CHANGELOG.md at the repository root.

Enrolling devices — get a host into RemotePower

Quick (interactive): Click "Enroll device" in the dashboard. You get a 6-digit PIN, valid for 10 minutes. On the target machine: sudo remotepower-agent enroll, paste the PIN.

Automated (Ansible / cloud-init): Use the API to mint a one-time-use enrollment token (Settings → API or POST /api/enrollment-tokens), pass it via $REMOTEPOWER_ENROLL_TOKEN or /etc/remotepower/enroll-token, then run remotepower-agent enroll-token --server https://<host>. Token is consumed atomically — same one can't enroll twice. Default expiry 24h, max 7 days.

The token resolution order is: --token arg → environment variable → on-disk file (mode 600, auto-deleted on success).

Docker host (no install): Click "Enroll device → Generate Docker compose" for a ready-to-run docker-compose.yml (your server URL + a one-time token pre-filled). On the host: docker compose up -d. The agent runs as a container, monitors the host (shared PID/network namespaces, host rootfs mounted read-only) and is named after the host automatically. Standard capabilities, no --privileged. Compliance scans and systemd/journal collection aren't available from a container — see docs/docker-agent.md.

Metric alerts — disk / memory / CPU thresholds

RemotePower fires metric_warning, metric_critical, and metric_recovered webhooks when a device's resource crosses its configured threshold. Defaults:

MetricWarningCritical
Disk usage (per mount)80%90%
Memory85%95%
Swap20%50%
CPU load ratio (loadavg / cpu_count)1.5×3.0×

Per-device overrides: Devices page → ⋯ menu → "Metric thresholds". The modal shows current sysinfo values for context, then warn/crit fields per metric (empty = use default). Per-mount disk overrides go in the bottom section — useful when /var fills with logs or /backup is meant to fill.

Hysteresis: a metric must drop 5 points below its warn threshold before "recovered" fires. Without this, oscillation around 80% would generate webhook spam every 60s.

Trends over time: Monitor page → Device metrics row → "Trend" button. Same chart as the per-device sysinfo modal.

Web terminal — open SSH from the browser

Click "Web terminal" on a device. Modal asks for SSH user, port, password, plus your RemotePower admin password (re-prompted every time, by design).

Architecture: a separate remotepower-webterm daemon handles the WebSocket+SSH bits because RemotePower's CGI can't hold persistent connections. nginx proxies /api/webterm/connect to it. SSH credentials live only in memory for the duration of the session — never persisted.

Setup (one-time): sudo bash packaging/install-webterm.sh. Auto-detects the CGI user (www-data, nginx, http, etc.), installs Python deps, generates the daemon ↔ CGI shared secret, prints the nginx snippet you need to add. Run with --dry-run first if you want a preview.

Recordings: Every session recorded to /var/lib/remotepower/webterm-sessions/<id>.cast in asciinema v2 format. Output-only by default (set RECORD_INPUT=1 in daemon env to capture keystrokes too — only do this if you've thought about who can read the recordings dir). Replay with asciinema play <file>.

Commands — run shell, shutdown, reboot, upgrade

Per-device dropdown menu has the common actions: shutdown, reboot, Wake-on-LAN (if device has a known MAC), agent self-update, upgrade packages, custom command.

Commands queue in cmds.json. The agent picks them up on its next heartbeat (default 60s, configurable per-device). Output comes back on the heartbeat after execution finishes — for apt upgrade that can be a few minutes.

Batch mode: tick checkboxes on multiple devices, the batch bar at the bottom of the page lets you run any of those actions across all selected devices at once.

Custom commands: "Custom command" in the menu, or save reusable ones to the Library (Admin → Library) and pick from a dropdown when you run them.

Webhooks — get notified when things happen

Settings → Webhooks. RemotePower auto-detects the format from your URL: Discord webhook URLs get embed-style messages; ntfy URLs get priority + emoji tags; everything else gets generic JSON.

Events you can subscribe to: device_offline / device_online, monitor_down / monitor_up, service_down / service_up, patch_alert, cve_found, log_alert, container_stopped / container_restarting, metric_warning / metric_critical / metric_recovered, command_queued / command_executed.

Each event can be toggled independently. The "Send test event" button fires a sample payload so you can verify your endpoint works before relying on it.

External monitors — ping/TCP/HTTP probes

Monitor page → "Add target". The server runs these probes itself, not the agents — useful for checking your ISP gateway is up, a web service is responding, or an SSH port is open.

Probes run on a schedule (monitor_interval, default 300s, minimum 60s). The schedule piggybacks on incoming CGI requests, so as long as any agent is heartbeating or anyone's browsing, monitors run on time. State transitions fire monitor_down / monitor_up webhooks.

Proxmox virtualization — managing QEMU VMs

RemotePower can connect to one Proxmox VE node and manage its guests. Configure it under Settings → Proxmox: the node's host, the node name, and a Proxmox API token (created in Proxmox under Datacenter → Permissions → API Tokens). Use a scoped token — VM.Audit and VM.PowerMgmt are enough — not a full-access token. There's a "Test connection" button to verify the setup.

Once configured, the Virtualization page lists the node's QEMU virtual machines: status, CPU and memory while running, uptime. Each guest has Start and graceful Shutdown actions. The connection is server-to-API — the RemotePower server talks to the Proxmox REST API directly; no agent runs on the Proxmox node.

This is a single-node integration. The Virtualization nav entry is always visible; if Proxmox isn't configured the page simply tells you so.

Proxmox LXC containers

LXC containers on the Proxmox node appear on the Containers page, in a section below the agent-reported Docker/Podman containers. They carry the same Start and Shutdown actions as QEMU VMs.

The LXC section only appears once Proxmox is configured (Settings → Proxmox). Like the VM list, it's fetched live from the Proxmox API each time you open the page.

Snapshots & rollback — point-in-time guest states

Each Proxmox guest — QEMU on the Virtualization page, LXC on the Containers page — has a Snapshots button. It opens a panel listing the guest's snapshots and lets you create, roll back, and delete them.

Create — give the snapshot a name (a letter followed by letters, digits or underscores) and an optional description. Snapshots are disk-only — the VM's RAM state is not captured. A typical workflow: take a snapshot named before_upgrade immediately before a risky change.

Rollback — returns the guest to a snapshot's state. This is destructive: every change made since the snapshot was taken is discarded. Because of that, RemotePower asks you to type the guest's name to confirm — a deliberate speed bump, not just an OK button. After a rollback the guest is at a crash-consistent disk state (no live memory, since snapshots are disk-only).

Delete — removes a snapshot. Irreversible, but it does not affect the running guest — only the saved point-in-time state is gone.

Snapshot operations run asynchronously on Proxmox. RemotePower sends the request and refreshes the list shortly after; a slow operation may not show on the first refresh — reopen the panel. Every snapshot action is recorded in the fleet event log.

Quick SSH from the Devices page

Set a default SSH username under Settings → Security → SSH preferences. It's stored per-user.

On the Devices page, a small SSH icon appears next to each device's hostname. Clicking it builds an ssh:// link to that device — using the device's IP if known, otherwise its hostname — with your default username, and also copies the plain ssh user@host command to your clipboard.

Whether the ssh:// link opens a terminal depends on your own machine having an ssh:// handler registered (the OS, PuTTY, a terminal emulator). If it doesn't, the copied command is the reliable path — paste it into any terminal.

Mailbox monitor — unread-message counts

A lightweight way to see a mailbox's message count without any IMAP/SMTP setup. Configure it under Settings → Mailbox monitor: pick a device, enter one or more absolute directory paths, and Save. The agent counts the regular files directly inside each directory and reports the numbers in its heartbeat — for a Maildir new/ folder that file count is the unread-message count.

Tick "Show this device's mailbox count on the dashboard" to add an "Unread mail" tile to the Home dashboard, alongside the devices / updates / drift / CVE tiles.

Counts refresh on the agent's schedule — roughly every five minutes, not instantly. The agent needs read access to the directory; if it doesn't have it, the count shows the reason (e.g. "permission denied") rather than a number. No email content is ever read — only files counted.

Scan packages now — on-demand inventory

The agent submits its full package inventory (used for CVE scanning) and the patch/upgradable count only every few hours. Right after you patch a host, use the "Scan packages now" item in the device action menu to get a fresh report sooner.

It sets a one-shot request; the device sends a fresh package list and patch count within a heartbeat or two — typically a minute or two, not instantly. The agent must be running 2.4.5 or newer to act on it.

Status endpoint — for external dashboards

RemotePower can expose a small machine-readable fleet summary at /api/status for external dashboard tools — Uptime Kuma, Homepage, a Grafana panel.

Generate a status token under Settings → Advanced → Status endpoint. The endpoint then answers at /api/status?token=YOUR_TOKEN — reachable by a polling tool, but not public. It returns a rolled-up health word (ok / warning / critical), device online/offline counts, and attention counts by severity. Rotate or disable the token any time from the same place.

Two-factor authentication (TOTP)

Settings → Security → "Enable two-factor". Scan the QR with any authenticator app (1Password, Authy, Google Authenticator, etc.). After enabling, every login asks for a 6-digit code in addition to your password.

To disable, you need to authenticate with a current TOTP code first — prevents someone with stolen session cookies from removing your second factor.

Tables: filter, sort, density

Every fleet table — Devices, Services, CVE Findings, Containers, Monitor, TLS, Patches, Audit Log, Command History, Schedule, Maintenance, plus admin tables — has a substring filter and clickable column headers.

First click sorts ascending, second descending, third clears. Hold Shift to add a secondary sort key (small superscript shows the priority).

The Devices grid has four density modes: Minimal (table layout, multi-select via checkboxes), Compact, Comfortable, Spacious. All preferences (filter, sort, density) sync per-user across browsers.

Backup & restore

All state lives in /var/lib/remotepower/ as JSON files. To back up:

sudo tar czf rp-backup-$(date +%F).tar.gz /var/lib/remotepower/

To restore: stop nginx briefly so no writes interleave, untar, restart.

v1.12.1+ keeps a rolling .bak next to each file. If a file ever ends up corrupted, load() automatically falls back to the .bak with a warning to the nginx error log. The dashboard keeps working with last-known-good data.

Troubleshooting common issues

Devices show "Offline" but agent is running: agent token doesn't match server. Check journalctl -u remotepower-agent for "Credentials rejected" — re-enroll on the device with sudo remotepower-agent enroll.

Web terminal fails with 404: nginx routes /api/webterm/connect to fcgiwrap instead of the daemon. The exact-match location = /api/webterm/connect block must come BEFORE any location ^~ /api/ in the same server block.

Web terminal fails with 502: nginx is correctly trying the daemon but the daemon isn't running. sudo systemctl status remotepower-webterm and journalctl -u remotepower-webterm.

Per-mount disk thresholds aren't taking effect: Agent must be v1.11.10+ to report per-mount data. Push an agent self-update from the toolbar.

Update history is empty for old agents: Pre-v1.11.7 had a bug where command output never reached the server. Push agent self-updates; the next upgrade will populate history.

API access — automation and integrations

Every dashboard action has an underlying API endpoint. Browse the full schema at /swagger.html (also linked from the sidebar as "API Reference").

Auth: two methods. Session tokens (login flow, time-limited) for short-lived scripts. Named API keys (Admin → API Keys → "New key") for CI / cron / Ansible — these don't expire. Pass via X-Token: <token> header.

Common patterns:

# List devices
curl -H "X-Token: $T" https://remote.example.com/api/devices | jq

# Reboot a specific device
curl -X POST -H "X-Token: $T" -H "Content-Type: application/json" \
  -d '{"device_id":"abc123"}' \
  https://remote.example.com/api/reboot

# Set per-device thresholds
curl -X PATCH -H "X-Token: $T" -H "Content-Type: application/json" \
  -d '{"mem_warn_percent": 70, "disk_per_mount": {"/var": {"warn":70,"crit":85}}}' \
  https://remote.example.com/api/devices/abc123/metric-thresholds
Devices page — your fleet, at a glance

Home page. Every enrolled device shown as a card or table row, depending on density. Each card shows: status (online/offline), name, OS icon, last-seen time, group badge, tag pills, key sysinfo (CPU/RAM/disk sparklines if metrics are flowing), pending updates count, open CVEs count.

Density modes: top-right toggle. Minimal = table, one row per device, sortable, multi-select. Compact = small cards. Comfortable = default. Spacious = roomy cards with bigger metric blocks.

Per-device dropdown (⋯ button) covers the common actions: reboot, shutdown, custom command, agent update, upgrade packages, web terminal, metrics chart, metric thresholds, edit notes, edit tags, change group, delete.

Batch actions: tick checkboxes on multiple devices, the batch bar at the bottom lets you run any of the above across the selection.

Filter & sort: top-bar substring filter matches name, hostname, group, tags, IP, OS. Click any column header (in minimal mode) to sort; Shift-click for secondary sort. Filter and sort persist per user.

CMDB page — asset metadata + credentials vault

Per-device structured metadata that the agent doesn't auto-discover: asset ID, server function (web / db / nas / firewall…), hypervisor URL, SSH port, free-form Markdown documents.

Multiple documents per asset (v2.0): attach as many titled Markdown docs as you want — runbook, hardware spec, change log, vendor contacts. Each doc has its own title, body, and timestamp. Docs render as expandable cards in the asset view.

Credentials vault: store SSH passwords, BMC credentials, vendor portal logins encrypted at rest. Encryption is AES-GCM with PBKDF2-SHA256-derived keys; the passphrase is shared across admins (set once at vault setup). Reveal events are audit-logged. Each credential row exposes an ssh:// link button if the asset has an SSH user/port set.

Server functions list: editable in Settings, used as autocomplete suggestions when filling the function field on an asset.

Containers page — what's running where

All containers across your fleet, in one table. Auto-detected from each agent: Docker (via socket), Podman (rootless or root), Kubernetes pods (via kubelet, where applicable). Read-only — RemotePower doesn't manipulate containers, just observes them.

Per-row info: device, container name, image, status, restart count, ports, namespace (k8s). Filter by name, image, device, or namespace.

Alerts: three webhook events fire automatically — container_stopped (unexpected stop), container_restarting (restart count climbed), containers_stale (device hasn't reported container info recently — usually means the agent's container detection isn't working).

Homelab software integrations — monitor the self-hosted apps you already run

A read-only, server-side subsystem polls popular self-hosted software for health on a cadence and folds the result into the Alerts inbox and the dashboard. Nothing is installed on the target — each connector only reads a service's own health/status API. Set one up under Settings → Integrations: pick a type, point it at the service on your LAN, add an API token, and Test.

26 connectors: Pi-hole, AdGuard, TrueNAS, Unraid, Kubernetes/k3s, vCenter/ESXi, Proxmox Backup Server, UniFi, Traefik, Nginx Proxy Manager, Caddy, Netdata, Grafana, Uptime Kuma, Jellyfin, Plex, Home Assistant, Nextcloud, the download clients (qBittorrent, Transmission, Deluge, SABnzbd, NZBGet), the *arr suite (one Servarr connector for Sonarr/Radarr/Prowlarr/Lidarr) + Bazarr, and Overseerr/Jellyseerr.

Alerts & widget: an unhealthy or unreachable target raises an integration_down alert (auto-resolved on recovery) routed through your channels, plus an Integration health dashboard widget and live status badges.

Read-only & SSRF-guarded: every outbound call is blocked from loopback / link-local / cloud-metadata (RFC1918 LAN allowed), re-validated at connect time, with no redirects. Credentials are stored server-side and redacted from every response; the raw URL is admin-only. A Show Homelab software switch (default on) is an instance-wide kill switch — off stops polling and hides the section + widget.

Containerized agent — run the agent as a container to watch a Docker host

The Linux agent can run as a container that monitors its Docker host and reports to the server, with no package install on the host. In the UI choose Enroll device → Generate Docker compose, then run docker compose up -d on the host.

The agent reads the host's facts (it shares the host PID and network namespaces and mounts the host root filesystem read-only), names itself after the host, and persists its credentials in a volume so a recreate doesn't re-enroll. Published multi-arch at ghcr.io/tyxak/remotepower-agent.

It runs with standard capabilities and no --privileged: SMART/DMI is an opt-in profile, and container inventory via the Docker socket is opt-in (with a host-root warning). Host package inventory and CVE scanning read the host package database directly; host compliance scans and systemd/journal collection are honestly reported as unavailable from inside a container.

GPUs page — fleet-wide GPU state (NVIDIA + AMD)

The Monitoring → GPUs page shows every GPU across the fleet in one rich view — NVIDIA and AMD — with utilisation and VRAM meters, temperature, power draw and fan speed, ordered hottest-busiest first, plus a fleet summary (count, per-vendor, total power). Hosts report via nvidia-smi / rocm-smi, with a tooling-free amdgpu sysfs fallback for AMD hosts that have no ROCm tooling.

Each GPU card carries temperature + utilisation trend sparklines (about the last four hours), so you can see a card heating up or a job ramping without opening the host.

Thermal alerting: a GPU at or above the temperature threshold (default 85 °C, configurable) raises the standard high-temperature alert and auto-resolves when it cools — GPU sensors participate alongside the existing CPU/board sensors, so it reuses the existing hardware-temperature alert with no new alert type.

Unmonitored hosts show their data too. Telemetry and inventory views — thermal, power, storage, exposure, predictive-health/SMART, patches, listening ports, processes and this GPU page — now display unmonitored devices, flagged in the UI; only alerting stays suppressed for them.

Network page — topology graph

Manual topology map drawn from each device's connected_to field. RemotePower doesn't auto-discover topology — set the upstream switch / router for each device, and the graph renders.

Switches, APs, and other agentless devices live as full-fledged records in the device list (with their own CMDB / vault / SSH-link as agented devices). Use Devices → Add agentless device.

The graph is positional — drag nodes around, the layout persists. Useful for finding the "who's downstream of this switch" answer at a glance.

Monitoring page — probes, metrics, ports, scripts, services, logs

The Monitoring sidebar group has six items that each deep-link to a section of this page and smooth-scroll to it on arrival:

  • Targets — ICMP ping, TCP port, HTTP HEAD probes the server runs against external targets. State transitions fire monitor_down / monitor_up webhooks.
  • Device Metrics (v1.12.0) — fleet-wide memory / swap / CPU / disk view, color-coded by alert level. Filter by name, group, mount path.
  • Listening Ports (v2.8.1) — all open ports across monitored devices, grouped by port number with process name and device list. Live filter by port, process, or device.
  • Custom Scripts — fleet-wide results table for your bash health-check scripts. Filter by name or status.
  • Services — systemd unit health matrix for watched services.
  • Logs — fleet log tail with regex pattern-alert rules.

Trend button (v2.0): next to each device in Device Metrics, opens the time-series chart modal for that device.

TLS / DNS page — certificate & record watchlist

Server-side probes that warn before things expire. Add a hostname (or hostname:port for non-443) and the type — TLS for cert expiry, DNS for record-set health. Probes run on schedule alongside the monitor probes.

TLS: connects, fetches the leaf cert, reports expiry days remaining + issuer + SAN list. Alerts at <30 days, critical at <7. Self-signed and otherwise-invalid certs flagged with reason.

DNS: resolves A/AAAA/MX/TXT (whichever exist), reports the TTL of the soonest-expiring record. Useful for catching domain registrar issues before the domain itself lapses.

Both fire alerts via the existing webhook system — no separate config needed.

Patches page — pending updates across the fleet

Aggregates pending-update counts from every agent. Linux agents run apt list --upgradable / dnf check-update / pacman -Qu / apk list --upgradable on a schedule (default every 3 hours) and report the count + package list back.

Per-device row: total upgradable, security-only count (where the package manager exposes that), oldest pending update age. Click into a device for the full list.

Patch alert webhook: Settings → Webhooks → Patch alert. Configurable threshold; fires patch_alert when a device has more than N pending updates.

Run upgrade: per-device dropdown → "Upgrade packages" runs the appropriate package manager non-interactively and returns the output as Update history. Batch select to upgrade many at once.

Custom Scripts — your own bash health checks on devices

Define arbitrary bash scripts server-side and assign them to any set of enrolled devices. The agent runs each assigned script every 5 minutes with a 30-second timeout. Exit code 0 = OK; anything else = FAIL.

Create a script: Custom Scripts → New script. Paste a body directly, or type a description and click AI Generate to have the AI draft one. Assign the script to one or more devices using the device picker. Save.

Results: The Custom Scripts page shows a fleet-wide table — script name, device, status badge, last output snippet, when it last ran, and how long it took. Click any output snippet to see the full stdout/stderr.

Alerts: Status changes fire webhooks — custom_script_fail when a script flips from OK to FAIL (includes the first line of output), custom_script_recover when it returns to OK. Both are edge-triggered: they fire once on the transition, not on every failing run.

Script execution: Scripts run as the agent user (root on most setups), with stdout and stderr merged, capped at 4 KB. The script body is written to a private temp file (chmod 700), executed by /bin/bash, then deleted. Scripts are pushed from the server — no SSH needed.

Examples: check a web endpoint returns 200, verify a backup file was recently modified, test a database port is accepting connections, confirm a cron job's sentinel file exists.

Host Configuration — declare and enforce host state from the server

Define the desired state of each Linux host server-side. The agent applies it on the next heartbeat (~60 s) and reports current state every 15 minutes so the server can detect drift.

Open the editor: Devices page → device dropdown → Host Config. A modal opens with one tab per section.

Sections managed:

  • Repos — full content of /etc/apt/sources.list or /etc/yum.repos.d/remotepower.repo
  • Netplan — written to /etc/netplan/01-remotepower.yaml, then netplan apply
  • nmcli — connection file at /etc/NetworkManager/system-connections/remotepower-managed.nmconnection
  • resolv.conf — DNS resolver config; resolves symlinks on systemd-resolved hosts
  • /etc/hosts — static host entries
  • Services — list of systemd units that should be enabled; agent runs systemctl enable --now
  • Users — ensure local users exist with correct shell, groups, and SSH authorized_keys (no passwords)
  • Groups — ensure local groups exist
  • Sudoers — written to /etc/sudoers.d/remotepower, validated with visudo -c before applying
  • MOTD — login banner written to /etc/motd

Fetch current: Each tab has a "Fetch current" button that loads the live state last reported by the agent. Use it to pre-fill a section before editing, or to inspect what's actually running.

Drift detection: The agent reports current state every 15 minutes. The server compares it against the desired config. If any section diverges, an amber banner appears on the modal and a config_drift webhook fires — once on first detection, not on every heartbeat. Drift is audit-only; the agent does not auto-remediate.

Security: Only admins can write host config. Sudoers content is syntax-checked before writing. authorized_keys are written with mode 0600 and correct ownership. No passwords are ever stored — SSH keys only.

CVEs page — known vulnerabilities in installed packages

Cross-references each agent's installed-package list against OSV.dev on a schedule (default daily). Findings are severity-ranked and grouped by device.

Each finding shows: CVE ID, severity (CRITICAL / HIGH / MEDIUM / LOW), affected package + installed version, fixed version (if any), summary, references. Click for the full OSV record.

Ignore list: known false positives or accepted risk can be ignored per CVE-ID + per-package combo. Ignored findings disappear from the active view but stay in audit history. The "Show ignored" toggle reveals them.

cve_found webhook: fires when new CVEs appear that aren't on the ignore list. Useful for plugging into the team's incident channel.

Services page — systemd unit health matrix

Per-device watched-services view. Define which units to watch in Settings → Service watch (or via API), and the agent reports their state on every heartbeat: active, inactive, failed, activating, etc.

Matrix view: rows are devices, columns are services; cell color reflects state. Filter by service name, device, or group; sort by failure count.

Webhooks: service_down when a watched unit transitions to inactive/failed; service_up on recovery. Maintenance windows suppress these without losing the audit trail.

Logs page — log tail across the fleet with pattern matching

Per-device journalctl output for watched units. Agents submit log lines on every heartbeat; server keeps a rolling 6-hour buffer.

Search: regex over the buffered logs. Filter by device, unit, time range. Useful for "did this error happen anywhere in the last hour?"

Pattern alerts: Settings → Log rules. Define regex patterns; matches fire log_alert webhook with the matched line, device, and unit. Useful for kernel oops, OOM kills, fail2ban bans, anything you want a notification on.

Per-device or fleet-global rules: rules can be scoped to a device (only matches there fire) or fleet-global (matches on any device fire).

Schedule page — one-shot & recurring commands

Schedule reboots, shutdowns, package upgrades, or arbitrary commands. Two modes:

One-shot: pick a date+time, RemotePower fires the command once then discards the job.

Recurring: choose a friendly preset (every hour, every N hours, daily at HH:MM, weekly on day+time, monthly on day+time) or enter a custom 5-field cron expression. DOW follows cron convention (0 = Sunday).

Run a script: select "Run script…" in the command picker to choose any saved script from the Scripts library. The body is resolved at fire time so editing the script updates all pending recurring jobs.

Per-device, per-group, or fleet-global. Two optional checkboxes on create:

  • Maintenance window: auto-checked for disruptive commands (reboot, upgrade); suppresses all suppressible alerts for 1 hour around the scheduled time.
  • Add to calendar: creates a calendar entry at the next computed occurrence. For recurring schedules (daily, weekly, monthly), the calendar event inherits the same recurrence so all future runs appear in the calendar automatically.
Calendar page — visual timeline of scheduled events

Month-view calendar of upcoming scheduled commands and maintenance windows. Useful for "what's planned this week?" and avoiding accidentally double-booking maintenance.

Create events: click any day cell to create a one-off event. The event modal has a Recurrence dropdown: None, Daily, Weekly, Monthly, or Yearly. Recurring events are stored once on the server and expanded into occurrences within the displayed window (cap: 500). They appear with a refresh icon in the grid.

Delete recurring events: opening a recurring event shows a "Delete all occurrences" confirmation so a single click removes the entire series.

Schedule integration: the "Add to calendar" checkbox on the Schedule form creates a recurring event automatically when the schedule itself is recurring — daily/weekly/monthly schedules produce matching calendar recurrence.

Tasks page — operational checklist

Free-form per-fleet task list. Write down what you need to do, check items off, leave notes. Doesn't drive any automation — just a place to keep track of "rebuild X next maintenance window" or "investigate why Y is restarting".

Tasks have title, description, optional due date, status (open / in-progress / done). Filter by status; sort by due date.

Maintenance page — alert-suppression windows

Schedule windows during which webhook alerts are suppressed for specific devices, groups, or the whole fleet. Useful for planned downtime where you don't want to be paged for an expected outage.

Two modes: one-shot (start time + end time) or recurring (cron pattern + duration). Scope: device, group, or all.

Suppressed alerts are still logged — you can see exactly what would have fired during the window via the audit log. So if something unexpected happens during maintenance, you can find it after the fact.

History page — command execution log

Every command run via RemotePower, with actor (which user), target device, command, exit code, output preview, timestamp.

Used together with the Audit log (which covers admin actions like creating users, changing settings) to reconstruct what happened during an incident.

Rolling buffer of last 200 commands. For longer-term retention, configure log forwarding to your central logging system.

Settings page — server-wide configuration

Tabs:

  • Account — change password, enable/disable TOTP 2FA, view active sessions, revoke sessions.
  • Webhooks — add destination URLs (Discord, ntfy, Slack, generic JSON), per-event toggles, "send test event" buttons.
  • SMTP — outbound email settings for the digest endpoint and password resets.
  • LDAP — bind URL, search base, attribute mappings; "Test connection" button.
  • Service watch — list of systemd units the agents should monitor, applied to all devices unless overridden.
  • Log rules — regex patterns for log_alert events.
  • Server functions — autocomplete list for CMDB asset function field.
  • Backup — one-click ZIP download of all state JSON files.
Users page (Admin) — local accounts

Manage local user accounts. Each user has a username, bcrypt password, role (admin or viewer), optional TOTP secret, optional email for password reset.

Roles: admin can do everything. Viewer is read-only — can browse all pages but every write endpoint returns 403.

LDAP users auto-create on first successful bind; their role defaults to viewer until an admin promotes them.

API Keys page (Admin) — non-expiring tokens for automation

Named API keys that don't expire (unlike session tokens). Use for CI scripts, cron jobs, Ansible, Grafana scraping /api/metrics.

Keys are bound to a user account — when you create a key, it inherits your role. To make a "ci-bot" key with limited access, create a viewer-role user first and create the key while logged in as that user.

Pass via X-Token: <key> header (same as session tokens). Keys can be revoked instantly from this page; revoked keys 401 immediately.

Library page (Admin) — saved command snippets

Reusable shell-command bookmarks. Save common diagnostics ("show disk usage by mount"), restart routines ("kick the failing service"), or chained operations as named entries.

When running a custom command on a device, the modal has a dropdown that auto-populates from this library — no need to remember the exact find incantation.

Audit page (Security) — admin event log

Every administrative action: user created/modified/deleted, password changed, settings changed, API key minted/revoked, enrollment token created, vault unlocked, credentials revealed.

Each entry: timestamp, actor (user), action, detail string, source IP. Filter by actor, action, or substring; sort by any column.

For command execution, see the History page (separate). The Audit log is for "who changed what configuration" rather than "who ran what command". Now in the Security sidebar group alongside TLS/DNS, Patches, CVEs, and Drift.

Links page — shared bookmark dashboard

Card grid grouped by category. Click any card to open the link in a new tab. Group links by category — useful for "Monitoring", "Infrastructure", "Vendor portals", etc.

Scope: mark a link as Internal (LAN-only, behind VPN, etc.) or External. Internal links get an amber dashed border; external links get an accent (blue) solid border — so it's visually obvious at a glance which links require VPN.

Dashboard widget: once at least one link is saved, a "Quick links" card automatically appears on the Home dashboard showing all links as a compact grid. Click "Manage →" to jump to the full Links page.

Display-only — RemotePower doesn't proxy or health-check these URLs.

Navigation: Links is a standalone top-level item in the sidebar, directly below Home — accessible to all users regardless of role.

Scripts — the multi-line script library (v2.1+)

Like the command library but for full bash scripts — multi-line, with `set -euo pipefail`, error handling, the works. Stored in scripts.json; created and edited via the Scripts page.

Save flow: paste a script → editor runs bash -n (syntax check) and a regex-based dangerous-pattern detector (rm -rf /, fork bomb, dd if=/dev/zero of=/dev/sda, curl|bash, chmod 777 /, etc.). Both must pass before save.

Run on a device: Devices page → ⋯ menu → "Run script…", pick from the library, confirm. Output comes back on the next heartbeat after execution finishes.

Batch run: tick checkboxes on multiple devices, batch bar → "Run script", pick from the library. The batch tracker shows per-device progress; output collects under the batch job ID for ~1h.

Tagged runs: instead of ticking devices, target a tag or group via the API: POST /api/exec/batch with tag, group, or device_ids.

Full reference: docs/scripts.md.

AI assistant — five providers, AI buttons across the dashboard (v2.1.3+)

Disabled by default. Enable in Settings → AI assistant. Five providers: Anthropic (Claude), OpenAI (ChatGPT), DeepSeek, Ollama (local), LocalAI (local). Pure stdlib — no extra pip deps. Pick a local provider (Ollama / LocalAI) if you don't want data leaving the building.

Where the AI buttons appear:

  • Device dropdown (⋯ menu) → Investigate, Generate runbook.
  • Device detail modal → Explain on each command output, Find the problem on the journal panel.
  • Services page → service detail → Diagnose on failed/inactive units.
  • TLS page → table row → Triage on warning/critical/error certs.
  • Patches page → table row → Prioritise on devices with pending updates.
  • CVE Findings → row → Triage.
  • Scripts editor → Generate from prompt / Explain / Audit for risks.
  • Notifications → webhook log row → Explain.
  • Help → AI Assistant → standalone chat with model picker and Ollama server stats.

Privacy: hostnames and IPs are redacted before leaving the building unless you toggle "Send hostnames" / "Send IP addresses" in Settings. Bearer tokens, AWS keys, and long hex strings are always redacted regardless. AI-generated scripts go through the same dry-run + dangerous-pattern detection as anything else — no AI-trusted bypass.

Slow local models (smallthinker, qwq, deepseek-r1) routinely take 60–180 s per response. The HTTP timeout is 5 min on the Python side, but nginx's fastcgi_read_timeout defaults to 60 s and will cut you off first — add a location /api/ai/ block with fastcgi_read_timeout 300s;. See docs/ai.md for the snippet and the full reference.

Rate limits: per-user per-day cap in Settings (default 100; 0 = unlimited). Per-button max_tokens tuned client-side so a short Explain doesn't sit waiting for 4000 tokens to generate.

Device runbooks — AI-generated, per device (v2.1.7)

What it is: a structured operations document for each device, generated by the AI from the device's current state (sysinfo, watched services, containers, recent commands, journal, CVE findings, patch status). Saved per-device; regenerable any time.

How to generate: Devices page → ⋯ menu → Inspect → Generate runbook. The AI gets the live snapshot of the device plus the fleet context (so it can say "this is your mail server" rather than just "this is a Linux box"). Takes 15–90 s depending on provider and model.

What's in it: sections for purpose / role, installed stack, running services, listening ports, scheduled jobs, recent activity, "things to know," and known risks. Format is Markdown — rendered inline on the device detail modal under a Runbook section.

When it's worth re-running: after a major change to the device, before handover, when documenting a system for a colleague, after the OS upgrade. The data is current as of when it ran — the timestamp is shown alongside the runbook.

Privacy: runbooks contain hostnames and IPs by design (a redacted runbook is useless). The redaction toggles in Settings → AI assistant apply, but you'll want "Send hostnames" + "Send IP addresses" on for runbook generation specifically. Storing hostnames in a runbook that lives in your own JSON file isn't a privacy concern; what matters is whether they cross over to a cloud provider on generate.

Configuration drift detection — per-device file integrity monitoring (v2.2.0)

What it is: the agent computes SHA-256 hashes of a list of watched config files every few heartbeats and ships them in the heartbeat payload. The server stores baselines (first-seen hash per file per device) and fires a drift_detected webhook when a current hash diverges from the baseline.

Hash-only by design. The contents of /etc/sudoers, /etc/ssh/sshd_config, etc. never cross the wire on routine polling. To see what actually changed, an operator action queues a cat command through the existing exec mechanism (subject to the usual audit + permission checks).

Where to find it: sidebar → Security → Drift. Fleet-wide table shows devices sorted with drifted ones at the top; click Detail for per-file status, drift count, history of the last 20 changes, and the Accept as baseline button.

Default watched list: /etc/ssh/sshd_config, /etc/sudoers, /etc/fstab, /etc/crontab, /etc/hosts, /etc/resolv.conf, /etc/nsswitch.conf, /etc/pam.d/sshd. Customisable globally (cfg['drift']['default_watched_files']) and per-device (device.watched_files).

Webhook: drift_detected fires once per change (debounced — not on every poll that reports the same new hash). Route it to a channel you check, especially for after-hours alerts.

Compliance: covers configuration management controls in SOC 2 (CC6.1, CC6.6), ISO 27001 (A.12.4.3, A.14.2.4), HIPAA (164.312(c)), PCI DSS (11.5), FedRAMP. Baseline-acceptance audit-log entries are designed to be readable as evidence.

Agent version: requires v2.2.0+ for the agent-side hash reporting. Older agents work normally otherwise but show "no drift data" on the Drift page.

Full reference: docs/drift.md.

MCP server — natural-language fleet queries from Claude Desktop, Cursor, VS Code (v2.2.0)

What it is: RemotePower ships an MCP (Model Context Protocol) server at mcp/remotepower-mcp.py. Connect it to an MCP-compatible AI host and you can ask things like "Which devices have pending security updates?" or "Show me the journal for mail01 from the last hour" in plain English.

Architecture: the MCP server runs on the operator's laptop, not on the RemotePower server. The AI host (Claude Desktop, Cursor, etc.) spawns it as a stdio subprocess. The MCP server makes HTTPS calls to RemotePower's REST API on behalf of the AI using an API token you provision. Credentials live in the host's config file and never reach the AI provider.

18 tools: 14 read + 4 guarded write. Read: list_devices, get_device, get_journal, get_services, get_containers, get_cves, get_drift, get_recent_commands, get_runbook, get_patches, get_tls, get_snmp_data, search_devices, search_fleet. Write — each gated behind a server-side allow-list, per-MCP-token role, and an explicit confirmation flag: reboot_device, run_saved_script (saved, vetted scripts only — no free-form commands), force_package_scan, force_acme_rescan. Every write is audit-logged with the AI host and the prompt that triggered it.

Setup (Claude Desktop):

  1. Settings → API keys → Generate a viewer token; copy the rpk_... value.
  2. Copy remotepower-mcp.py to your laptop (scp works).
  3. Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows) — add an mcpServers.remotepower entry with the command, args, and env (URL + token).
  4. Restart Claude Desktop. The tool indicator should show remotepower.

Device-name resolution: exact → prefix → substring → ambiguity error. You can pass web01 and the server finds web01.example.com automatically (as long as there's exactly one match).

Pure stdlib Python. No pip install. A single ~900-line file.

Full reference: docs/mcp.md.

Notification setup — getting alerts to land where you'll see them

RemotePower has webhook (Discord / Slack / ntfy / generic JSON) and SMTP email channels. Pick whichever you actually check.

Recommended baseline (most operators want):

  1. One webhook for page-me-now events: device_offline, service_down, monitor_down, metric_critical, cve_found. Point at ntfy / Pushover / your phone.
  2. One webhook for FYI-during-business-hours events: metric_warning, patch_alert, log_alert, container_stopped. Point at a Discord/Slack channel.
  3. Email digest for the slow stuff (weekly CVE summary, patches pending) once cron_email_digest is enabled.

Per-event toggles: each webhook URL has independent toggles for every event type. The "Send test event" button fires a sample payload so you can verify the integration works before relying on it.

Maintenance windows suppress alerts during planned downtime. Suppressed alerts are still logged — you can see what would have fired in the audit log. So if something unexpected happens during maintenance, you can find it after.

Explain on alerts: each webhook log row has an "Explain" button that asks the AI to rewrite the raw alert into a single short paragraph ("postfix on mail01 stopped at 14:32 after matching connection refused 3 times — likely upstream MX is unreachable; check DNS and try a manual delivery"). Useful during on-call when you're seeing a wall of cryptic alerts at 3am.

Device Drawer — click any device to open

Clicking a device name (Devices page or Dashboard fleet roster) opens a full-screen drawer with two tabs:

Actions & Settings tab — all actions for that host in one grid: Run command · Reboot · Shut down · Wake on LAN · Upgrade packages · Scan packages · Web terminal · Run script · Update agent · Docker compose · Host config · AI Investigate · CMDB · Runbook · Maintenance · Adjust poll · Remove device. Below the grid: inline settings form (group, tags, monitored toggle, poll interval, watched services, log rules, drift files, command allowlist) with a Save button.

Audit tab — 11 collapsible sections, all lazy-loaded on first open: System info (uptime, IPs, mounts, AI "Find the problem") · Listening ports (searchable) · Packages · Logs (unit selector) · Command history (last 5, expand per entry) · Fleet events · Drift state · CVE summary · Containers · Metrics · Host config.

The ⋮ button on the Devices page also opens the drawer directly on the Actions & Settings tab.

Settings → Dashboard — personalise the dashboard

Settings → Dashboard tab controls what appears on the home dashboard for all users:

Brute-force detection — enable/disable, set threshold (default 20 failed attempts from same IP in a 5-minute window), and window length.

Backup file monitoring — add file paths and max-age thresholds. The agent checks mtime every heartbeat; backup_stale webhook fires edge-triggered and a Needs Attention item appears.

Process thresholds — watch a process by name and fire process_alert (edge-triggered, with a process_recovered follow-up) when its CPU or memory percentage crosses the limit. Evaluated server-side against each heartbeat's top processes.

Log ignore patterns — regex patterns (case-insensitive) that silently drop matching log lines before storage and alerting. Useful for noisy kernel notes like Note: After setting.*old kernels.

Needs Attention kinds — one toggle per alert type. Toggling a kind off hides it from both the Needs Attention panel and the Recent Activity feed simultaneously.

Recent Activity events — toggle the remaining informational events (device online, command queued/executed) independently.

Listening Ports — Monitor page + per-device Audit

Fleet-wide view: Monitor page → Listening Ports section. Shows all open ports across all online monitored devices, grouped by port number, with process name and which devices are listening. Shows 10 rows by default; expand button for the rest.

Per-device view: Device drawer → Audit tab → Listening Ports section. Searchable table filtered by port number or process name.

Port data is collected by the agent as part of sysinfo (every ~10 minutes) and persisted in devices.json. New ports trigger a new_port_detected webhook compared against the port baseline.

CVE Findings — package vulnerability scanning

RemotePower checks installed packages against OSV.dev. The dashboard tile always shows Critical CVEs first with the count, and high/med/low counts in the subtitle.

Scan all devices — runs OSV lookups for every device that has submitted a package list. Can take a minute for large fleets. Button shows progress and result.

Send list (per-device) — asks the agent to send its full installed package list on the next heartbeat (~60 seconds). The CVE scanner then runs automatically. Use this after installing new packages before the agent's next scheduled scan.

Scan (per-device) — re-runs the OSV lookup using the already-stored package list. No need to wait for the agent.

The dashboard tile shows 0 for critical even when there are only high/medium/low findings — click it to see the full breakdown per device.

IaC Generator — generate Infrastructure-as-Code for a device

The IaC Generator page (left nav) produces Terraform, Ansible, Pulumi, or Cloud-init code that describes a managed device's current state. Useful for codifying a host you've configured by hand, or for migrating a host to a new platform.

Flow:

  1. Select a device, the categories of state you care about, and an output format.
  2. Click Generate IaC (full LLM flow) or Gather RAW JSON (collect only, download masked state).
  3. On the agent's next heartbeat (~60 seconds), it collects the requested categories and sends raw state back.
  4. The server calls your configured AI provider (Settings → AI) with the raw state, and returns the resulting code.

Categories (18): OS & identity, installed packages, systemd services (enabled), local users (uid≥1000), groups (gid≥1000), SSH authorized_keys (LLM converts to variables), network configuration, mounts (fstab), containers (Docker/Podman), custom repos, firewall, cron jobs (incl. RemotePower scheduled), TLS certificates (paths only), system environment (non-default), snaps (Ubuntu), kernel modules (persistent), sysctl parameters (non-default), RemotePower-specific (tags, group, custom scripts, host-config desired state).

Output formats: Terraform (HCL), Ansible (YAML), Pulumi (Python), Pulumi (TypeScript), Cloud-init (YAML).

Output tabs: Generated Code | AI Conversation. The Conversation tab shows the full system+user prompt and the raw LLM response, so you can see exactly what the model produced before fence-stripping.

Re-run AI / JSON download: After a successful generation, the Re-run AI button re-prompts the LLM using the already-collected data (no second agent wait). The { } JSON button downloads the masked state as a JSON file.

Extra instructions: A textarea below the format dropdown lets you append custom guidance ("use Terraform 1.5+ syntax", "wrap in a reusable module"). Persisted in localStorage.

Reasoning-model safety net: The prompt instructs the LLM to wrap output between <<<BEGIN_IAC>>> and <<<END_IAC>>> markers. The stripper extracts only what's between them — so DeepSeek-R1-style reasoning prose gets discarded automatically.

Security: Before the payload leaves your server for the LLM, env vars whose name matches PASSWORD|SECRET|TOKEN|KEY|PASS|AUTH|CRED|PRIVATE are masked with <REDACTED_BY_REMOTEPOWER>. TLS certificate paths are sent but never the certificate contents. SSH authorized_keys are sent raw — the LLM is instructed to convert them to variables.

Endpoints: POST /api/iac/request · GET /api/iac/status/<id> · POST /api/iac/generate · GET /api/iac/payload/<id> (v3.0.0)

Per-item ignore lists (v3.0.1) — × button on Needs Attention and stale containers

Each Needs Attention card and each stale Containers row now has a × button that hides that specific entry from view. Ignores are per-item (one specific CVE on one specific device, not the whole category).

Restore: Settings → AI Assistant → Ignored items lists every hidden entry with a Restore button. Three categories are tracked separately: Needs Attention, Stale containers, Devices.

Stability: Needs Attention items are keyed by a stable SHA1 of kind+device+summary, so the same alert firing in a later poll stays hidden until you restore it. New variants (e.g. the same CVE but a new package version) get a fresh key and re-appear.

Storage: /var/lib/remotepower/ignored_items.json

Endpoints: GET /api/ignored · POST /api/ignored · POST /api/ignored/remove

Log ingestion (v3.0.1) — embedded timestamps + content dedupe

The Logs page ingestion path was rearchitected to handle re-submitted file-based logs (apt.history, nginx access, syslog) correctly.

Previous bug: agents resubmit log files on every poll. The server used to stamp every line with now, so apt.history entries from days ago appeared as "new" and the 6-hour TTL never evicted them. Worse, the resulting bloat pushed nginx and brute-force lines past the 2 MB byte cap (silently dropped).

Fix (v3.0.1):

  1. Each incoming line is hashed (sha1[:16]) and compared against the buffer. Duplicates are dropped at ingestion.
  2. The line's own embedded timestamp is used when present. Supported formats: apt.history Start-Date: YYYY-MM-DD HH:MM:SS, nginx access [DD/MMM/YYYY:HH:MM:SS +TZ], syslog Mon DD HH:MM:SS, ISO YYYY-MM-DDTHH:MM:SS.
  3. The 2 MB byte cap was removed. With dedupe + TTL, the buffer can't grow unboundedly on idle units anymore.

Impact: If you upgraded from a buffer that had 11 000+ apt.history lines, give it one full TTL window (6 hours) for old entries to drop out. Nginx and brute-force events should re-appear immediately after restart since they're no longer being crowded out.

Logwatch severity (v3.0.1) — OK / WARN / CRIT classification

Log alert rules (per-device and fleet-wide) carry a severity field — OK, WARN, or CRIT — modelled after CheckMK's classification.

Semantics:

  • WARN (default) — fires the log_alert webhook with severity: "WARN".
  • CRIT — same as WARN but with severity: "CRIT" in the payload, so your alerting routes accordingly.
  • OK — silent: the rule fires (the match is recorded internally) but no webhook is sent. Use OK rules as noise-suppressors that confirm an expected pattern is still present, without alert spam.

Set the severity when creating or editing a rule in the Logs page rule modal.

AI prompt customization & fine-tuning (v3.0.1) — per-feature settings

Each AI feature (IaC Generator, Investigate, Diagnose Service, Runbook, etc.) uses a system prompt to set tone and constraints. Defaults are tuned for general-purpose models but may need adjusting per-model — a DeepSeek-R1 prompt doesn't necessarily fit a small local Llama.

Where: Settings → AI Assistant → Prompt customization. One card per AI feature (15 cards total).

Per card:

  • System prompt textarea — edit; click Save prompt to persist; clear and save to revert to default.
  • ● customized badge appears when overridden.
  • Default button restores the hardcoded default for that feature.
  • Fine-tuning (collapsible) — per-call temperature (0.0–2.0), top_p (0.0–1.0), max_tokens (1–16000), num_ctx (512–131072, Ollama/LocalAI only). Empty fields fall back to provider defaults.
  • ● tuned badge appears when any fine-tuning value is set.

Storage: config.json under ai_prompt_overrides and ai_param_overrides.

Endpoints: GET /api/ai/prompts · POST /api/ai/prompts · GET /api/ai/params · POST /api/ai/params

Force-upgrade agent (v3.0.1) — re-deploy regardless of version

The Device Drawer's Force-upgrade button pushes the currently-bundled agent binary to a device, even if the agent already reports the same version.

Use cases: recovery after a corrupt or truncated update, pushing a rebuilt binary at the same version, testing the self-update path.

How it works: the server sets force_agent_upgrade: true on the device record. The next heartbeat (within online_ttl seconds) delivers the flag and the server clears it. The agent calls check_for_update(force=True), which skips the version comparison and re-downloads + replaces its binary. Systemd then respawns the agent with the new binary.

Endpoint: POST /api/devices/<id>/agent/force-upgrade (admin only)

Confirmed in the audit log as agent_force_upgrade.

Update banner snooze 30d (v3.0.1)

The "RemotePower v<X> is available" banner has a Snooze 30d button. Click it to hide the banner for that specific version for 30 days.

Snooze is per-version, so a newer release re-shows the banner. State lives in localStorage under rp_version_snooze_<version>.

Custom monitoring scripts (v2.6.0)

Custom scripts let you ship arbitrary monitoring logic to selected devices, run on a schedule, and surface output in the UI.

Library: Scripts page → New script. Each script has a name, description, runtime (bash or python3), assignment selector (devices/tags/groups), schedule (interval in minutes), and timeout. Server pushes the body and metadata in the heartbeat response; agent stores them locally and runs them on schedule.

Output: per-device → Scripts page → Click a device row, or via the Device Drawer → Custom scripts chip. Each run records rc, output (capped at 8 KB), and ts.

Security: Scripts are pushed by the server, signed implicitly via the device token, and run as the agent user (root by default). Treat the script library as you would a CI/CD pipeline.

Host configuration management (v2.6.0)

Per-device Host Configuration captures a desired state for a small set of system attributes; the agent reconciles on every poll.

Where: Device Drawer → Host config.

Tabs:

  • Packages / Sysctl / Units / Modules — structured fields. Each reconciled by the agent on every poll.
  • Logrotate — free-text content for /etc/logrotate.d/remotepower. The agent writes this file verbatim; useful for adding custom log rotation without SSH.
  • Cron (root) — free-text content for root's crontab (crontab -u root). The agent applies via a temp file on each poll; useful for device-specific jobs you want managed centrally.

Reconciliation: agent reports the current state alongside the desired state. A diff is visible in the UI. Drift events are surfaced under the device's Drift tab.

Files: server keeps host_config_current/<dev_id>.json for each device's reported state.

Debug logging (v2.7.0+) — client-side observability

The UI ships an in-page debug logger that captures api() calls, toast() events, click handlers, and other instrumented events.

Enable: Settings → Advanced → Enable debug logging. State persists in localStorage under rp_debug, so a fresh page load picks it up immediately.

Output: debounced (250 ms) flush to the server, surfaced in the audit log and (when enabled) a developer console panel.

Use this when something looks broken but the server logs are quiet. Most "the button doesn't fire" bugs show up clearly here.

Report an issue — file a GitHub bug report from inside the app

The Documentation page header and the About page both have a Report an issue button. It opens a prefilled GitHub bug report in a new tab.

What it includes: the RemotePower version, your browser/environment, the current page, and any client-side errors captured this session (automatically scrubbed of token/secret-shaped values).

What it never includes: credentials, session tokens, or fleet/device data. The report is a public GitHub issue — review it before submitting. Security vulnerabilities should go through SECURITY.md (private), not the public tracker.

Security hardening (v2.3.2 / v3.0.0)

Several security improvements accumulated through the 2.x and 3.0 line:

  • Password storage: PBKDF2-HMAC-SHA256 at 600 000 iterations with per-user salt. The previous bare-SHA-256 fallback was removed.
  • Default admin: the first admin/admin account has must_change_password set. A persistent banner in the UI nags until the password is changed.
  • Backup export: the /api/backup export now redacts Proxmox tokens, SMTP passwords, LDAP bind passwords, and similar secrets. The backup is otherwise full-fidelity.
  • IaC payload masking: env vars whose name matches PASSWORD|SECRET|TOKEN|KEY|PASS|AUTH|CRED|PRIVATE are masked before being sent to the LLM. TLS cert paths are sent, never the contents.
  • Recursion depth guard (v3.0.1) on the IaC mask walker so a pathological JSON payload can't trigger a RecursionError.
ACME / Let's Encrypt — manage acme.sh certs across the fleet

Lives under Security → TLS / DNS expiry, in the "ACME certificates" section below the existing TLS watchlist.

How it works: the agent walks ~/.acme.sh/ on each device (root, $HOME, or /etc/acme.sh/ — first match wins), parses every <domain>/<domain>.conf, and reports state to the server. No credentials leave the device — the agent uses whatever's already in ~/.acme.sh/account.conf or env. acme.sh's own cron handles renewals; RemotePower visualises and provides force-renew/revoke/cancel.

DNS-01 only. v1 supports dns_cf (Cloudflare) explicitly with credential-location hints; the provider dropdown lists Route53, DigitalOcean, deSEC, Hetzner, Porkbun, etc. RemotePower never touches nginx/apache/HTTP-01 plumbing.

Wildcards are supported via the Issue wizard's checkbox. Must-staple is intentionally not exposed — Let's Encrypt is sunsetting OCSP (August 2025), so OCSP-stapled certs would fail.

Cancel pending actions: any queued renew/issue/revoke with no rc yet shows a Cancel button. If the action is still in the queue it's removed cleanly; if the agent has already grabbed it, RemotePower stops polling but the agent may still complete the operation (last-write wins on the meta).

Per-domain action logs (captured stdout from acme.sh, 256 KB cap) live in /var/lib/remotepower/acme_logs/.

Mitigation runners — investigate alerts with diagnostic + AI suggestion + confirmed fix

Every Needs Attention card with a supported alert kind (patches, disk, drift, service_down, reboot, brute_force) shows an Investigate button. Three-tab modal:

  1. Diagnostic — server queues a hardcoded read-only command on the agent (e.g. for disk: df -h + top dirs + files >500MB + journal disk usage). Live-polls every 2s, up to 3 min.
  2. AI Analysis — when diagnostic completes, the AI runs automatically with a playbook-specific system prompt (5 new keys in Settings → AI Assistant: mitigate_cpu, _memory, _disk, _service, _patches). It outputs a root cause + one specific fix command between BEGIN_FIX / END_FIX markers.
  3. Apply Fix — choose pre-approved playbook fix, AI-suggested fix, or paste your own. Safety classifier shows red banner for denylisted commands (rm -rf /, dd of=/dev/sd*, fork bombs, etc. — refused outright) or amber for sensitive ones (reboot, kill -9, systemctl stop, apt purge, curl | bash — requires typing RUN).

All investigations and fixes go to the audit log. Output captured per-action in /var/lib/remotepower/mitigate_logs/.

Diagnostic commands are server-defined — user input never flows into the shell. Service unit names go through a strict regex (alphanumeric + ._@-) before any template substitution; shell metachars and path traversal are rejected.

Needs Attention vs Recent Activity — what goes where

Needs Attention = "fix this NOW". Only items whose underlying state is currently broken: a service that's down right now, a probe that's failing right now, pending patches that still need to be applied, etc.

Recent Activity = event log of things that happened in the past — transitions, dispatches, ACK'd alerts. A service that went down at 14:30 and came back up at 14:35 shows in Recent Activity but disappears from Needs Attention once it's healthy again. Click the ✕ Clear button in the Recent Activity header to hide all current entries; this lasts for the browser session (persisted via sessionStorage) and resets when you close the tab.

v3.0.1 audit (attention coverage): these state-derived kinds now appear in NA whenever the condition is active:

  • service_down — any watched systemd unit in failed (critical) or inactive/deactivating (warning). Carries the unit name as target so the Investigate button can run systemctl status + journalctl -u <unit> automatically.
  • monitor_down — any monitor target whose latest probe came back ok: false.
  • custom_script_fail — any custom monitoring script reporting non-zero rc in its latest result.

Already covered: offline, patches, cve, drift, mailbox, brute_force, snapshot, backup, disk, tls, reboot, agent_version.

Log watching — systemd units AND arbitrary file paths

Per-device and fleet-wide log rules live in Settings → AI Assistant → Log alerts. Each rule:

  • Source type: systemd unit (via journalctl) or arbitrary file path (agent tails the file directly).
  • Pattern: Python regex against each new line.
  • Threshold: minimum matches before firing.
  • Severity: OK (silent on match — used to suppress noise), WARN, CRIT.

File-path rules: agent tracks inode + byte position in /var/lib/remotepower/file-log-state.json. Rotation (inode change) resets to position 0; truncation also resets. First-time setup skips existing content — only new lines from then on are sent, so a freshly-configured rule doesn't dump the entire historic file.

Submitted as synthetic unit file:<path>. Caps: 200 lines and 256 KB per poll, per file.

Force-upgrade agent — push a fresh binary to a single device

Per-device drawer → Force upgrade button. Sets a one-shot flag on the device record. On the next heartbeat (within 60s), the server includes the flag in the response; agent calls check_for_update(force=True), which bypasses the version-compare check and re-downloads the binary regardless of "we're already at version X". Flag is cleared atomically inside the heartbeat lock so it fires exactly once.

v3.0.1 fix: the flag had been silently dropped (copied to the wrong scope inside the heartbeat handler) so the operator got a success toast but nothing happened. Now wired through correctly, with a regression test. Use for re-deploys, recovery from corrupted binaries, or rolling out same-version rebuilds.

Sidebar navigation — collapsible groups and section deep-links

Grouped layout: the sidebar organises all pages into five collapsible sections. Each group opens and closes independently; state persists in localStorage. Fleet and Monitoring are expanded by default; Admin is collapsed.

GroupPages
FleetDevices, CMDB, Containers, Virtualization, Network
MonitoringTargets, Device Metrics, Listening Ports, Custom Scripts, Services, Logs
SecurityTLS/DNS, Patches, CVEs, Drift, Audit
PlanningSchedule, Calendar, Tasks, Maintenance, History
AdminSettings, Users, API Keys, Library, Scripts, IaC Generator, Server Status

Monitoring deep-links: each item in the Monitoring group navigates to the Monitoring page and smooth-scrolls to its section — so clicking "Listening Ports" skips straight to that section without manual scrolling.

Narrow mode: click ◀ at the top to shrink the sidebar to a 56-px icon strip. Click ▶ to expand. Preference saved in localStorage and applied before first paint. Mobile ignores this — the slide-in drawer is unchanged.

Standalone items: Home and Links sit above the groups as always-visible direct links (no group required to reach them).

Package manager coverage — apt, dnf, yum, pacman

Patch status detection works across all four: apt (apt list --upgradable), dnf (dnf check-update), yum (yum check-update — RHEL 7 / older CentOS, reports as manager: dnf so it shares the CVE path), pacman (pacman -Sy + pacman -Qu).

pacman 7+ sandbox: the new download sandbox user (alpm) fails on hosts where that user isn't usable — CachyOS in particular. v3.0.1 probes pacman --help for --disable-sandbox support and passes it when available, in both the agent's status check and the server's _UPGRADE_CMD. On real failure, upgradable is reported as None (UI shows "unknown") instead of 0 ("fully patched") — the previous silent-0 was the reason CachyOS devices appeared up-to-date when they weren't.

CVE scanning: uses OSV.dev. Mapping: Debian/Ubuntu by codename, Rocky/AlmaLinux/RedHat for rpm-based, no Fedora (no OSV feed). Arch / CachyOS intentionally unsupported — Arch packages aren't in OSV.

Ignored items — hide alerts without deleting the underlying state

Every Needs Attention card and Containers row has an × button. Click it to hide the item; restore from Settings → Ignored items. Three categories: Needs Attention (per-alert), Stale containers (per-container), Devices (whole-device hide on Containers page).

Stored in /var/lib/remotepower/ignored_items.json. Ignores survive backups and aren't redacted in the export.

Multi-webhook destinations — fire every alert to multiple endpoints (v3.0.2)

Up to 20 webhook destinations, each with its own format adapter (Discord, Slack, Pushover, Teams, ntfy, generic JSON). Per-destination filters: limit by event name or minimum priority. Configure in Settings → Notifications → Webhook destinations.

Pushover uses form-encoded POST with token + user + message + priority. Internal critical (priority=2) maps to Pushover priority=1 (high), not 2 (emergency tier) — that requires retry+expire and forced acknowledgment, must be operator-explicit. Credentials are write-once-and-redacted (UI shows ••••• (set)) and redacted from the backup export.

The legacy single webhook_url field still works for backward compatibility. New setups should use the multi-webhook editor.

Full doc at docs/webhooks.md.

Server status — RemotePower watching itself (v3.0.2)

New sidebar entry. Reports server version + memory, /var/lib/remotepower disk usage with the top 20 largest files, fleet device freshness, webhook delivery success rate (24h + 7d), audit log size, and scheduled backup state.

Closes the "who monitors the monitor?" gap — if RemotePower itself starts misbehaving (webhooks failing silently, disk filling, agents stuck), the page surfaces it. GET /api/self/status works for external monitoring (Uptime Kuma, Grafana, Homepage).

Full doc at docs/self-monitoring.md.

Scheduled backup — daily snapshot of /var/lib/remotepower (v3.0.2)

Daily gzipped tarball, 14-day retention (both configurable in Settings → Advanced → Scheduled backup). Triggered via the heartbeat hook with a 24h sentinel and stale-lock recovery.

Manual triggers (Server status page):

  • Run backup now — immediately snapshots /var/lib/remotepower regardless of the 24h cadence.
  • Export backup — also triggers a snapshot before streaming the ZIP download.
  • Clear backup archives — deletes all remotepower_data_*.tar.gz from the backup directory and resets the backup state. Useful before a migration or to reclaim disk space. Requires confirmation.

Excluded from tarball: the backups directory itself, in-flight .tmp.* files, existing .gz archives. Owner/group stripped so restoring on a different host doesn't fail.

No in-UI restore — backups are tarballs you extract yourself. Procedure in docs/self-monitoring.md.

Bulk operations — fleet-wide operations on filtered devices (v3.0.2)

From the command palette (/ → "Bulk actions") or Settings → Advanced → Bulk actions. Filter by all monitored / by group / by tag, then pick an action: upgrade packages, reboot, shutdown, force package scan, force ACME rescan.

Destructive actions (reboot, shutdown) require typing RUN to confirm. Every queued command is audit-logged. No undo once a command is queued — operator must reach the agent another way (SSH) to cancel before the next heartbeat picks it up.

Full doc at docs/bulk-operations.md.

Command palette & keyboard shortcuts/, Ctrl-K, ? (v3.0.2)

Press / or Ctrl-K to open the global search. Indexes all pages, every device (from the cached list), and quick actions. Arrow keys to navigate, Enter to activate.

? shows the cheat sheet. g-prefix shortcuts: press g, then h/d/l/s/c/m/a/v within 1.5 seconds to jump to Home/Devices/Logs/Settings/CVE/Monitor/Audit/serVer-status.

All shortcuts disabled when an input field has focus. Full doc at docs/keyboard-shortcuts.md.

Force ACME rescan — bypass the hourly scan cadence (v3.0.2)

When you've issued or renewed a cert via the acme.sh CLI on the host and don't want to wait up to an hour for RemotePower to catch up: from the ACME table, click Rescan on the device row.

Sets a one-shot force_acme_rescan flag on the device. Next heartbeat (within 60s by default) carries the signal, agent re-walks ~/.acme.sh/ regardless of the ACME_CHECK_EVERY cadence. Same flag-on-heartbeat-lock pattern as force-upgrade and force-package-scan.

Per-request load() cache — performance under the hood (v3.0.2)

CGI gives a fresh interpreter per request, so the cache lives only as long as one handler. Within that handler though, CONFIG_FILE was being parsed up to 4× per heartbeat and LONGPOLL_FILE 3× in handle_longpoll_exec. The cache deduplicates redundant reads.

Two safety properties: deep-copy on every load() so caller mutations don't corrupt the cache, and explicit invalidation in _LockedUpdate.__exit__ when the save aborts due to exception — otherwise the next load would return uncommitted in-flight changes.

AI Assistant
Free-form chat against the configured provider. Local-model stats when running Ollama or LocalAI.
AI is disabled
Enable it in Settings → AI assistant first.
No messages yet — type a prompt below.
Conversation history is kept in your browser (localStorage) — not on the server. Clearing the conversation clears only your view.
Server status
RemotePower watching itself — disk, devices, webhooks, audit, backups. Documentation.
Loading…
Compliance
Control-mapped PCI DSS / HIPAA / SOC 2 checklist, scored from data RemotePower already collects. An audit-prep aid — never a formal attestation. Documentation.
Loading…
A named set of pass/fail checks evaluated against each host's reported state — patches, reboot, failed units, disk, CVEs, agent integrity. Severity-weighted across applicable checks; the daily trend is below. Toggle a check off to exclude it fleet-wide.
Loading…
Runs oscap xccdf eval on the endpoint against its SCAP Security Guide datastream and reports the score, pass/fail tallies and failing rule ids. Requires openscap-scanner plus the SSG content for the host's OS — on RHEL/Fedora that's scap-security-guide; on Debian/Ubuntu it's ssg-debian / ssg-debderived. The profile list below is what your fleet's datastreams actually contain (it fills in after the first scan). Profiles are OS-specific: Debian/Ubuntu ship the ANSSI BP-028 profiles (anssi_np_nt28_minimal…_high) — those have real rules and produce a meaningful score; the Debian standard profile selects almost no rules (expect 0). CIS / PCI-DSS / STIG / OSPP exist only in the RHEL/Fedora scap-security-guide, not on Debian. A profile that isn't in the host's datastream, or that evaluates no applicable rules, reports "not available" with the reason. The content must match the host's OS release — oscap scores 0 if it doesn't (every rule "not applicable"). Best results per OS: Ubuntu — install Canonical's usg (Ubuntu Security Guide); the agent uses it automatically for CIS/STIG profiles and it ships content for the exact release (incl. 24.04, where the distro ssg-ubuntu datastream lags). Debianssg-debian matching the release, then an ANSSI BP-028 profile. RHEL/Fedorascap-security-guide. If a scan reports "not available", the reason names exactly what to install. Scans run in the background and report on the next heartbeat. The full oscap / usg HTML report is uploaded with each successful scan — click Report in the results row to open it.
Loading…
Sends a compact live snapshot of the fleet to the model and ranks anomalies. On-demand — costs one AI request. Requires the AI assistant to be configured.
Forecast
Per-mount disk-fill projection across the fleet, from each host's daily metrics history. A least-squares trend on observed usage, extrapolated to capacity — lead time, not a guarantee. Ephemeral mounts (/tmp, /run, /dev/shm, …) are excluded, and a heavily-fluctuating mount shows fluctuating instead of a misleading date. Documentation.
Loading…
Timeline
A single chronological history — fleet events and command runs merged into one stream — for the whole fleet or one device. Pick the scope below. Documentation.
Loading…
Reports
One fleet posture report — health score, patches, CVEs, and compliance in a single export, on demand or emailed on a schedule. Documentation.

Fleet posture report

Loading summary…

The evidence pack bundles this posture report with the 90-day compliance-baseline trend and an audit-log excerpt for the period into one JSON document — the artifact auditors ask for. Admin only; generating it is itself audit-logged.

Capacity

Loading…

Agent integrity

Each agent reports its own binary hash; the server attests it matches the canonical published build. A mismatch on the current version flags tampering, corruption, or a partial update.
Loading…

Resource anomalies

Hosts whose latest memory / swap / disk reading deviates sharply from their own recent baseline (statistical, model-free).
Loading…

Software metering

Track install counts of named software across the fleet against an allowance. One per line as name = limit (limit 0 = just count). Matches package names in the collected inventory.

Uptime (SLA)

Loading…

Scheduled email delivery

Email the posture report on a cron schedule. Leave recipients empty to use the configured notification recipients. Admin only.
Example: 0 8 * * 1 = every Monday at 08:00.

Custom reports

Build a report from the sections you care about, download it, or schedule it to a specific audience. Saved per server.

Checks
Every monitored signal on every host as OK / WARN / CRIT / UNKNOWN, with output. Sort and filter; toggle a check off to silence it on a host.
Host Group Check Status Output
Loading…
Fleet Query
Filter the fleet by ad-hoc criteria (all conditions are ANDed). Save the ones you run often. Documentation.
Set criteria and Run.
Automation
When an event fires on matching devices, run a saved script and/or notify a destination. Rules are evaluated on every event; each has a cooldown. Documentation.
Rules
Loading…

New rule

Release Signing
Sign the agent release so agents refuse any self-update that isn't validly signed by your key. Documentation.

Server-side signing is the convenient mode. The private key lives on this server, so it protects against tampering of the published files at rest (mirror/CDN), but not a full compromise of this server. For the strongest guarantee, sign off-server in CI with tools/sign-agent-release.sh and only publish the public key here.

Loading…

Distribute the public key to agents

Pin this on each agent host at /etc/remotepower/release.pub. Once present, that agent enforces signatures (fail-closed). No key pinned → agent keeps using sha256-only verification.

About
RemotePower — self-hosted device management
RemotePower
RemotePower
Server version:
Agent version
GitHubgithub.com/tyxak/remotepower
LicenseMIT
Latest releasechecking…
Report a bug

Self-hosted remote device management — shutdown, reboot, Wake-on-LAN, monitoring, scheduled commands, and agent self-update.

No inbound firewall rules on clients. Agents poll the server over HTTPS. Flat JSON storage, Nginx + Python CGI. No Docker, no Node.js.

Did you know?

Command Queue
Commands waiting to be picked up by each agent on its next heartbeat — handy when a host is offline and you want to see (or cancel) what's pending before it comes back. Anything already delivered to the agent has left the queue.
Pending per device
Loading…
API Keys
Named non-expiring keys for scripts and CI pipelines
Keys
NameRoleUserCreatedExpires
Sites & teams
Group the fleet by location, team, or customer — one level above device groups. Assign a device to a site from its drawer. Super-admins always see every site.
Sites
NameSlugDevicesCreated
Loading…
Patch Report
Overview of pending system updates across all devices — percentage only counts online devices with data
Export (filtered):
Total
Fully Patched
With Patches
Total Pending
Patch Rate
DeviceGroupOSStatusPkg ManagerPendingPatch StatusRecent Patch Cmds
Click Refresh to load patch report.

Software inventory search

Find which hosts have a package — e.g. openssl older than a version. Searches the collected package inventory.

Patch catalog

Pending updates aggregated by package — which update is waiting, and on how many hosts. The inverse of the device table above.
Loading…

Install software

Install one or more packages from the host's own repositories — on a single device, or across a whole group or tag. Detects the package manager (apt / dnf / yum / zypper / pacman / apk). Requires the exec permission; honours quarantine and change-windows.
Package names only (no shell). Space- or comma-separated, up to 30. Uninstall removes the named packages (no dependency auto-removal or config purge). Hold/Unhold pins a package at its current version so a fleet upgrade skips it.
CVE Findings
Package vulnerabilities per device, via OSV.dev — scan checks installed packages against known CVEs.
0
Critical
0
High
0
Medium
0
Low
0
Devices Scanned
DeviceGroupEcosystemKEVCriticalHighMediumLowLast scan
Click Refresh to load findings.
Pentest
Authorized vulnerability scans against enrolled hosts you manage and ownership-verified domains. The target is derived server-side — you can only scan assets you own. Network scans run on a scanner satellite; on-host audits run on the device's agent. Documentation →
0
Running / queued
0
Critical findings
0
High findings
0
Scans
TargetStatusCritHighMedLowCreated
No scans yet. Select an enrolled device and queue one.
Verified web targets — scan domains / IPs you own that aren't enrolled hosts. Prove ownership once, then scan.
Scheduled scans — recurring scans on a cron. They use the device/target + tool/profile/intensity selected in the toolbar above. High/critical findings raise an alert.
Services 0 maintenance window(s) active
systemd units watched per device. Click a row to see history, logs, and configuration.
0
Services Up
0
Services Down
0
Devices Reporting
0
Units Watched
DeviceGroupWatchedUpDownLast report
Click Refresh to load.
Logs
6-hour rolling buffer across the fleet. Search, tail live, or manage alert rules.
0
Lines in buffer
0
Devices reporting
Last line
0
Alert rules
Live tail — auto-refreshing every 30s
Alert rules
Regex match on incoming log lines fires a log_alert webhook.
DeviceGroupUnitPatternThreshold
No per-device rules configured.
Fleet-wide rules apply to every device that submits logs for the named unit. Use * for the unit to match any unit on any device.
UnitPatternExclude patternThresholdCreated
Maintenance Windows
Scheduled windows suppress webhook alerts for specific devices, groups, or the whole fleet.
ReasonScopeTargetWhenEventsStatus
Click Refresh.
Recent Suppressions
WhenEventDeviceWindowReason
Auto-patch
Apply package updates automatically on a schedule across a group, tag, site, or the whole fleet. Queued upgrades respect maintenance windows and device quarantine.
Policies
NameTargetScheduleRebootEnabled
Loading…
Backups
Define a backup command per device (restic / borg / rsync / …), run it on demand, or schedule it with cron. Pairs with the backup-freshness monitoring in each device's drawer.
Backup jobs
NameDeviceScheduleLast runEnabled
Loading…
Proxmox guest backups
Recency of each guest's vzdump backup archives on the connected Proxmox node — distinct from VM/LXC snapshots. Stale or missing backups also raise a dashboard attention item.
days
Loading…
Ansible
Run Ansible playbooks against the fleet, with this server as the control node. Define a playbook, then run it against a group / tag / site over SSH.
Playbooks
NameLast runResult
Loading…
Rollouts
Push an upgrade or saved script to the fleet in ordered rings — canary, then pilot, then broad. Each ring is verified (upgrades use post-deploy verification) before the next is released, automatically or on your approval.
A one-time install is the un-staged sibling of a rollout: it installs a package straight away through each target's package manager (apt/dnf/yum/zypper/pacman/apk), on a single device or a whole tag.
Click Refresh.
Recent installs & jobs
Follow one-time installs and batch script runs here — each host shows a checkmark when it finishes (red on a non-zero exit). Updates live while anything is still running.
No recent jobs.
Calendar
Shared events across all users — backups, deploys, renewals, anything you want to remember.
Mon
Tue
Wed
Thu
Fri
Sat
Sun
Tasks
Shared kanban board. Drag cards between columns. Optionally link a task to a device.
● Upcoming 0
● Ongoing 0
● Pending 0
● Closed 0
CMDB
Configuration Management Database — asset metadata, documentation, and encrypted credentials per enrolled device.
Checking vault status…
Name Asset ID Function OS IP Hypervisor Docs Creds
Containers
Docker / Podman / Kubernetes pods reported by enrolled agents. For Docker/Podman you can start, stop, restart, and pull logs — and deploy compose stacks (below). Actions queue to the agent and run on its next heartbeat.
DeviceOSTotalRunningStoppedRestarting (≥5)RuntimesReported
Image updates
Containers whose pulled image is behind the registry's current digest for that tag. Notify-only — RemotePower flags staleness, you decide when to pull.
ImageTagHostsStatusRegistryLast checked
Compose stacks
Upload a docker-compose file and deploy it to a device — up / down / redeploy. Admin-only and audited, and only to devices where you've turned on compose deploys. RemotePower runs the file as-is on the host; it doesn't sandbox it.
StackDeviceStatusLast action
Proxmox LXC containers
LXC containers on the Proxmox node. Actions hit the Proxmox API directly.
Virtualization
QEMU virtual machines on the Proxmox node. Start / shutdown actions call the Proxmox VE API directly from the RemotePower server.
Network map
Topology view from manually-set connected_to links and tunnels (peer links). Drag nodes to reposition — positions persist across refresh. Add agentless devices on the Devices page.
Unmanaged hosts on the LAN
Hosts seen by agents that ran a LAN scan (device drawer → Health & Hardware → Scan LAN) and that aren't enrolled in RemotePower.
No scan data yet — run a LAN scan from a device's Health & Hardware card.
Configuration drift
Watched config files across the fleet. Agent hashes each file every few heartbeats; server alerts when a hash diverges from the stored baseline. Hash-only — no file content crosses the wire. Documentation.
Drift profiles

Reusable named sets of watched files. Assign a profile to a device, tag, or group and every matching host monitors that set. A device's own explicit file list (set in its drawer) still overrides any profile; an unassigned host falls back to the global default.

Loading…
Enforcement policy

Auto-apply the desired config for every device matching a tag or group — apply pushes it every poll, correct on drift re-applies only when a host diverges. A device's own per-device setting (in its drawer) still wins. Only devices that already have a desired host config are affected.

Loading…
DeviceGroupFiles watched DriftMissingLast check
Exposure
Every listening socket across the fleet, classified by where it can be reached from. World = bound to a public/wildcard address; LAN = private network; Local = loopback only. A service first becoming world-reachable raises an alert. Documentation.
DeviceProto/PortProcess Bind addressScope
Loading…
Exposed secrets on disk
Redacted findings from the opt-in agent scan — keys, tokens and passwords found in files. Values are never collected; each row shows a masked preview and a fingerprint. Enable the scan in Settings → Security. Mute a false positive to stop it alerting.
DeviceType PathPreview Line
Loading…
Risk
A per-asset risk score (0–100) computed on demand from everything RemotePower already knows — open CVEs, world-reachable services, software-policy violations, pending updates, contract/license expiry, mount issues and more. Every point is attributed. Findings you've ignored (CVEs) or muted (Exposure) don't count. Risk is a security-posture lens, independent of fleet health.
DeviceRisk LevelTop factors
Loading…
Integrations
Live health of the homelab/fleet software you've connected — Pi-hole, TrueNAS, the *arr suite, download clients and more. Each tile shows status plus key stats pulled from the service's own API. Documentation.
Loading…
GPUs
GPU state across the fleet — NVIDIA and AMD. Utilisation, VRAM, temperature, power and fan for every reporting host, hottest/busiest first. Hosts report via nvidia-smi / rocm-smi (or the amdgpu sysfs fallback). A GPU at or above the thermal threshold (default 85 °C, set in Settings) raises a High Temperature alert and auto-resolves when it cools. Documentation.
Loading…
Storage health
ZFS, mdadm and btrfs pool/array state across the fleet. Degraded or faulted arrays are listed first and raise an alert; ZFS scrub freshness is tracked. Documentation.
DevicePoolType StateCapacityLast scrub
Loading…
Thermal health
Hottest hosts across the fleet — CPU, chipset and disk temperatures the agents already report. Each host shows its single hottest sensor; the list is sorted hottest-first and anything ≥75 °C is flagged. Documentation.
DeviceMax temp Hottest sensorType Sensors
Loading…
SSH key audit
Every authorized_keys entry across the fleet, with OpenSSH SHA256 fingerprints. Weak key types and keys reused across multiple hosts are listed first. Documentation.
DeviceUser TypeComment FingerprintHosts
Loading…
Power & energy
UPS status and measured power draw across the fleet. Hosts on battery are listed first. Set your electricity price to estimate energy cost from the live total. Documentation.
DeviceUPS status BatteryLoad RuntimePower
Loading…

Cost allocation (chargeback)

Estimated monthly energy cost per group and per tag, from each host's measured draw × your price/kWh above. A rough allocation for showback/chargeback — instantaneous watts projected to a 30-day month.

Loading…
Predictive health
Hardware predicted at risk before it fails — disks (reactive SMART verdict + trends in reallocated/pending sectors and SSD wear) and hosts restarting unusually often. Most urgent first; an ETA appears once there's enough history. Documentation.
RiskDevice DiskWear ETASignals
Loading…
Frequently restarting hosts
DeviceRestarts (7d) Last boot reason
Software policy
Rules evaluated against every host's installed-package inventory: banned (must not be installed), required (must be installed), min version. Optionally scope a rule to device tags. Documentation.
Policy rules
Current violations
DeviceRulePackage ExpectedFound
Loading…
Software center — installed packages

Every package installed across the fleet, with the versions in use and how many hosts run each. Type to filter; click a row to see which hosts (and versions) on the Patches → inventory search.

Loading…
DMARC
Email-authentication posture for your domains — SPF, DKIM and DMARC records over DNS — plus aggregate (RUA) reports fetched from your DMARC mailbox over IMAP.
Domain Status DMARC SPF DKIM Findings Checked
Aggregate reports (RUA)
Who is sending mail as your domains, and whether it passes DMARC — parsed from reports in your DMARC mailbox.
Reporter Domain Policy Window Messages Pass Fail
Sending sources
IP addresses seen sending as your domains across all ingested reports.
Source IP Pass Fail From domains Last seen
TLS / DNS
Server-side cert and DNS watchlist. Probes run from the RemotePower server. Defaults: warn at 14 days, critical at 3 days.
StatusHostPortDays leftExpiresIssuerLast check
ACME certificates
Lets Encrypt certs managed by acme.sh on each device. Server scans ~/.acme.sh/ and shows next renewal, alt names, and the configured DNS provider. Renewal stays under acme.sh's own cron; this page just visualises and provides force-renew, revoke, and a wizard to issue new certs (DNS-01 only).
No devices have reported any ACME state yet. Either acme.sh isn't installed, or the agent hasn't completed its first scan (runs ~ once an hour, plus on startup).
Device Domain Challenge Provider Created Next renewal Status Actions
Loading…
Alerts
Operational alert inbox — acknowledge, resolve, and track every fired event. Recover events (device_online, service_recover, custom_script_recover) auto-resolve their matching open alert.
Severity Time Title Device Ack by
Loading…
MCP Confirmations
Pending write actions queued by MCP clients against devices with require_confirmation=true. Each entry shows the originating AI host and the natural-language prompt that led to the action. Approve to run, reject to discard. Pending entries expire after 1 hour.
Status Requested Action Device AI host Prompt
Loading…
Audit Log
Security audit trail — logins, commands, session revocations
Security posture — how the live config measures against secure defaults.
TimeActorActionDetailSource IP
Command Library
Saved shell command snippets — pick from the exec modal
Snippets
NameCommandDescription
No snippets yet.
Scripts
Multi-line bash scripts. Lint with bash -n + dangerous-command detection before they go anywhere. Run on a single device from the device dropdown, or on a batch via the multi-select bar.
Saved scripts
Name Description Size Updated Flags