A glanceable wall view — rolled up by group/site/tag so it stays readable on a large fleet, with every problem host surfaced regardless of fleet size.
| Label | Type | Target | Status | Detail | Checked | |
|---|---|---|---|---|---|---|
| No monitors configured. | ||||||
Import / export monitors
Paste an existing monitoring config and RemotePower proposes equivalent monitors. Preview first (dry-run) to see what maps and what doesn't, then apply. Accepts an Uptime Kuma backup JSON, Nagios/Icinga object config (define host/service), a Zabbix XML export — or a RemotePower export from another instance. Duplicates (same type + target) are skipped.
Export downloads your monitor definitions in a format this same Import accepts, so moving a set between your own instances is copy-paste rather than retyping. Definitions only — no history, and a monitor's satellite assignment is left out (it's local to this install).
Define an availability target (e.g. 99.9% over 30 days), then tick the SLO on each remote probe that should count toward it. Availability is check-weighted across the attached probes; the error budget shows how much downtime allowance is left. Also exported as Prometheus gauges at GET /api/slo.
| Name | Target | Window | Probes | Availability | Error budget left | Status | |
|---|---|---|---|---|---|---|---|
| No SLO objects yet — define an availability target (e.g. 99.9% over 30 days), then tick it on the probes that should count toward it. | |||||||
| Device | Alert | Memory | Swap | CPU load | Disks | |
|---|---|---|---|---|---|---|
| Device | Alert | CPU | Memory | Storage | Temp | Uptime | |
|---|---|---|---|---|---|---|---|
| No SNMP devices yet — enable SNMP on an agentless device's Settings tab. | |||||||
| Script | Device | Group | Status | Last output | Last run | Duration | |
|---|---|---|---|---|---|---|---|
| Click Refresh to load results. | |||||||
| Process | PID | Device | CPU % | Mem % |
|---|---|---|---|---|
| Click Refresh to load. | ||||
| Username | Created | Role | MFA | Source | |
|---|---|---|---|---|---|
Your weekly time log — record billable (debtable) and internal hours by day. Hours you log on a ticket land here too.
Your team name — used by the Tickets "My team's open tickets" view to group tickets assigned to your teammates. Everyone who types the same team name is on that team.
HTML signature appended to ticket emails you send (sent as a rich HTML part, with a plain-text fallback). Paste HTML — e.g. your full contact block with links.
Choose the interface language. Saved to your account and synced across devices.
Pick a theme for this browser. Follow system tracks your OS light/dark setting; Time of day switches on the clock instead — which is what you want when the OS is pinned to dark, as it is on most servers and kiosks. The accent tints buttons and highlights on top of any theme.
Applies live — the boundary is crossed without a reload, so a wall-mounted dashboard switches on its own. A window that wraps midnight (day from 21 to 5) works, for night shifts.
Auto-hide pauses while there are open alerts — the sidebar stays visible so nothing needing attention is concealed.
Get a desktop notification on this device when a high or critical alert fires — even when RemotePower isn't the active tab. Per-browser; enable it on each device you want notified.
Get alerts on your own webhook or email, with your own filters — in addition to the org-wide channels (this never turns those off). You only receive alerts for devices you're allowed to see.
Protect your account with an authenticator app (Google Authenticator, Authy, etc.).
Phishing-resistant sign-in with a security key, your phone, or this device's biometrics. A passkey also satisfies any MFA-required policy.
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.
How temperatures are shown to you. Everything is stored and alerted on in Celsius — this only changes what you read, so switching it can't move a threshold. Per-user, so operators on the same instance can disagree.
The tab badge is passive — it only helps if you look at the tab. These are the active half, for a dashboard sitting on a second monitor. Both are off by default and are per-user: a sound is the most intrusive thing a page can do. Only a rise in the open-alert count announces, so opening the dashboard with existing alerts stays silent — announcing history rather than news is how people learn to ignore an alert sound.
Open alerts you've taken ownership of (acknowledged but not yet resolved).
Browsers and devices currently signed in as you. Revoke any you don't recognise.
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.
Compares the running version against the latest published release.
Guided self-update (advanced)
Optionally point this at a server-side update script (absolute path). When set, "Run update now" executes it — your script pulls the new version and restarts the service the way your install expects (git / package / container). It runs directly, never through a shell, with no arguments. Leave empty to keep self-update disabled.
A ready-made, install-aware script ships in the repo at packaging/remotepower-server-update.sh (auto-detects git / pacman / apt and restarts the worker). Install it and grant the API user scoped passwordless sudo — the script's header has the two commands. Then set the path below to /usr/local/sbin/remotepower-server-update.
Restart server
Restarts the app-server service — for picking up a manual code change or clearing in-memory state without an SSH session. The page will briefly disconnect, then reconnect. Grant the API user scoped passwordless sudo to the restart script (packaging/remotepower-server-restart.sh, its header has the two commands); the button is hidden until that's set up, and disabled in a container (restart the container instead).
Display name shown in the page title, push notification subject lines, and webhook payloads. Helps tell instances apart when you have more than one.
How often newly-enrolled agents heartbeat back to the server. Existing devices are not affected — change theirs from the device detail page.
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.
How often monitors auto-check when the Monitor page is open. Also controls server-side offline/patch check frequency.
Magic packets are sent via UDP broadcast from the server. Adjust if your network uses a directed broadcast address.
Reach a Windows host's desktop from the device drawer. RemotePower mints a short-lived session that bridges the host's loopback 3389 over SSH to a local port for mstsc/Remmina — there is no in-browser RDP client. Off by default.
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.
Refuse a batch reboot or shutdown that would hit too many hosts at once unless it's explicitly confirmed. Either cap can be set independently; 0 disables it. Single-device actions are never affected.
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.
When the SAME alert fires on at least this many devices at once (a network outage, a bad driver batch, a mis-shipped config), automatically open a status-page incident pre-filled from the cluster, and auto-resolve it once every alert in it clears. This is the cross-device axis the per-host root-cause folding on the Alerts page doesn't cover. Off by default.
The device-count threshold lives in Settings → Alert parameters.
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.
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.
Enable or disable each event type. Disabled events are recorded as "disabled" in the webhook log so you can see what was suppressed.
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.
✓ Password is currently being read from RP_SMTP_PASSWORD. The field above is ignored.
| Time | Event | Status | Detail | |
|---|---|---|---|---|
| No webhook deliveries yet. | ||||
Permanently-failed webhook deliveries are kept here so they aren't lost when the log scrolls. Retry re-sends the exact event to its destination.
| Time | Event | Destination | Error | Tries |
|---|
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.
Every connector type above, built-in or third-party. A third-party connector is a *.py file dropped into connectors.d/ on the server (root-owned, filesystem-only — there's deliberately no upload-from-browser path). After adding or updating a file there, reload to pick it up without restarting the service.
Pull cloud instances into the fleet as agentless device records (tagged cloud / provider / region). Read-only — AWS uses an IAM access key with ec2:DescribeInstances; Hetzner Cloud and DigitalOcean use a read API token (paste it in the token field). Re-running updates in place. Documentation
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. A ready-made Grafana dashboard for this exposition ships in contrib/grafana.
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 →
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.
A shareable, read-only status page at /status.html?token=… — group your devices and monitors into named components and show recent incident history. No login required. It uses the status token above; generate one if you haven't. Documentation
Each component groups one or more devices/monitors under a public name. A component's status is the worst state among its members.
Post an incident (or planned maintenance) that shows on the public page above the component list — with a running update log. Optionally email subscribers when one opens or resolves.
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 unitsyslog; 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. - SNMP trap receiver — POST decoded traps as JSON (
{traps:[{oid,value,agent}]}) to/api/snmp/trap/<token>from ansnmptrapdhandler script. Traps attach to the pinned device, show on its SNMP view, and raise a coalescedsnmp_trap_receivedalert. Must be pinned to a device.
| Label | Type | Scope | Token | Hits | Last seen | Status | |
|---|---|---|---|---|---|---|---|
| No inbound tokens yet. | |||||||
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. Documentation
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. Documentation
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. Documentation
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. Documentation
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. Documentation
✓ Bind password is currently being read from RP_LDAP_BIND_PASSWORD. The field above is ignored.
Stream every fleet event and alert to a SIEM in its native ingest format. Distinct from audit-log forwarding (Settings → Security), which streams the audit trail. Best-effort and non-blocking. Documentation
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. Documentation
Also export a distributed-tracing span per HTTP request (method, path template, status, duration, joined to the same W3C traceparent trace-id already in the logs/webhooks) to the same collector's /v1/traces endpoint. Separate opt-in from the metrics above — higher volume, per-request path data.
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.
How long OSV.dev vulnerability details are cached before being re-fetched. Higher = fewer external requests, lower = newer descriptions on existing CVEs.
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.
When enabled, the selected command kinds are parked as a pending approval instead of executing immediately. A second admin approves them on the Confirmations page.
When a device's monitored UPS crosses the critical-battery threshold below, any OTHER device marked as powered by that UPS (device drawer → UPS dependency) is automatically queued a graceful shutdown — bypassing change-approval above, since this is an unattended safety action, not an operator-initiated one. Off by default — a device still needs its own UPS dependency mapping for anything to happen. Documentation
The critical battery and runtime thresholds live in Settings → Alert parameters.
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.
Watches certificate files your services actually use on each host and warns before one expires. One coalesced alert per host; the system CA trust store is never touched. Documentation
Point RemotePower at an offline GeoLite2 database to enrich login sources with country and ASN, and optionally flag one account signing in from two countries inside a short window. Everything is read from the local file — no lookup ever leaves the box. Documentation
Fills each asset's warranty expiry in the CMDB from the vendor, using the serial the agent already inventoried. A date you typed by hand is never overwritten, and results are cached for about 30 days. Documentation
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.
Disk-fill forecasting tells you when a mount runs out; this tells you what to delete. When enabled, agents run a bounded du over the paths below (~12h cadence, never crossing a filesystem boundary) and report the biggest space consumers. The results appear in each host's System Info drawer panel, under the mounts table, with a Scan disk usage button for an on-demand run. Off by default — it walks the filesystem.
Answers the GDPR/PCI question no amount of monitoring does: where is our regulated data? Agents walk the paths below (~24h cadence) and report which files contain emails, card numbers (Luhn-checked, so a long order id isn't mistaken for a card), national IDs, IBANs or phone numbers — by kind and count only. The matched values are never sent, stored, or even hashed: hashing does not anonymise a national ID, because the number of possible values is small enough to reverse. A scanner that shipped your PII into its own database would be a second breach, not a control. Results appear on the Compliance page. Off by default — it walks the filesystem. Documentation
Turns standing credential access into active, justified, expiring access. When enabled, revealing a CMDB credential first requires checking it out with a reason; the grant lasts a bounded window (15 min – 24 h) and lapses on its own. Who currently holds live access — and why — is visible to admins and auditors. This is a floor, not a ceiling: a credential flagged break_glass still needs its two-person approval as well. Off by default — switching it on immediately requires every admin to check out before revealing anything. Documentation
Agents plant a decoy file at each absolute path below (never over an existing file) with realistic-but-fake credentials, then watch it. A change or deletion — what ransomware does — raises a critical canary_accessed alert on every platform; a plain read is also detected wherever the filesystem records access times, which excludes most Windows hosts (NTFS last-access updates are off by default). Linux, Windows and macOS. Each decoy alerts once, not on every heartbeat. Decoys are removed when the agent uninstalls on Linux and Windows; on macOS remove them by hand, since there is no uninstall command. One path per line; blank = off. Documentation
Scan the images of running containers for known vulnerabilities with trivy. Findings feed the CVE views alongside package CVEs. Off by default; the feature is invisible on hosts without trivy installed.
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.
Applied to new users and password changes (existing passwords are never invalidated). Opt-in — leave length at 0 to keep the current behaviour.
The compliance evidence pack and the audit-log archive download are signed (HMAC-SHA256) with a per-install key so a tampered export is detectable. Rotate the key if it may be compromised — new exports use the new key; already-issued exports keep their original signature.
Download your operator-authored configuration — monitors, checks, alert/automation rules, integrations, webhook destinations, maintenance windows, backup monitors, TLS/DMARC/resolver targets and more — as one versioned JSON document. Secrets are shown as (redacted) and webhook URLs are collapsed to host-only, so the file is safe to commit to git for review, diffing and off-box backup.
Import previews the changes first (a per-collection add/change/remove count) — nothing is written until you confirm Apply. Redacted secrets are kept from the current config by id; webhook destinations are re-entered manually.
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. Documentation
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). Documentation
devices roster at the database via RLS, so a tenant's rows are unreachable cross-tenant even if an application scope check is missed. Postgres backend only; requires "Enforce tenant isolation" above. Applied on next start.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.
How long a session lasts. Short by default; "remember me" extends to long.
Require every agent to present a client certificate signed by your RemotePower CA — defence-in-depth on top of the per-device token, so a stolen token alone can't impersonate a host. Enable the nginx ssl_verify_client optional block first (see deploy/nginx/remotepower.conf) and run agents with RP_CLIENT_CERT/RP_CLIENT_KEY, or healthy agents will be locked out. Documentation
The drift engine can watch any file, but you had to know each path and add it by hand, per host — while the agent already discovers every compose file on the box (that's how the Containers page offers up/down/pull against them). The two halves were never connected, so a hand-edited docker-compose.yml — the most common "why did this stack change?" — drifted unwatched. Turn this on to fold each host's discovered compose files into its drift watch list. Appended, never replacing what you chose to watch. Documentation
A unit crash-looping under Restart=always is active every time we sample it — it comes back before the next heartbeat — so service_down never fires and the host looks perfectly healthy while a service restarts all day. systemd's restart counter is the only thing that reveals it. Set how many restarts between two heartbeats count as flapping (unit_flapping). 0 = off; a unit that legitimately bounces now and then shouldn't page anyone.
Polls a public IP-echo service on the monitor cadence. It gives you three things a residential/self-hosted setup can't otherwise see: your public IP changed (a dynamic-IP lease renewal silently breaks every port-forward, VPN endpoint and DNS record pointing home), the internet is down as distinct from a host being down, and an outage log with 30-day uptime — the evidence you need when you call the ISP. Off by default; it makes an outbound request.
Dynamic DNS. With a Cloudflare zone configured, a detected IP change can update an A record automatically, so your hostname follows the new lease. The API token is read from the vault at ddns/cloudflare — but note that only works while the vault is unsealed; a sealed vault means the update is skipped and logged, never silently wrong. The wan_ip_changed event fires either way, so you always find out.
Asks agents to run avahi-browse and report what's advertising itself on their segment — printers, Chromecasts, AirPlay, HomeKit bridges, NAS boxes. These are the devices you'll never install an agent on, so without this they're just unlabelled IPs on the network map. Results appear under Network map → LAN services. Off by default: it's a broadcast query, and it names things on your LAN.
Pause new agent command dispatch during a controller upgrade — heartbeats and read-only browsing keep working, so devices don't flip offline. In-flight commands drain normally; new exec/reboot/install attempts are refused with a clear message and a banner is shown to everyone.
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.
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.
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.
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.
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.
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.Every settings save that changed something keeps the previous state here (last 10). Restore swaps the live configuration for a snapshot — the replaced state becomes a revision itself, so a restore can always be undone. Documentation
Turn off what you don't use. A disabled module disappears from the sidebar and its API stops responding — it isn't merely hidden. Nothing is deleted: switch it back on and your data is exactly where you left it.
Provisioning itself (render-only blueprints) is always available. This switch additionally lets admins run Terraform on the server with your cloud credentials.
Send connected agents a "poll now" nudge over a companion WebSocket daemon instead of always waiting for the next scheduled poll — cuts worst-case command-dispatch latency, but never carries commands itself; the agent's normal poll cycle stays authoritative. Requires server/push/remotepower-push.py installed + running separately. Off by default — the feature is invisible unless both this is on and the daemon is actually reachable. Documentation
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.)
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).
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).
Stored in storage_backend.json so the server reconnects on restart. The target database must exist and be empty; the migration creates the schema and copies your data in.
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. The age sweep never purges open alerts — only resolved ones past their limit; the 5000-entry safety cap also evicts oldest resolved alerts first.
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.
Suspends ALL age-based data purging above (command history, fleet events, webhook log, monitor history, resolved alerts, metric samples) while active — the retention settings are ignored until the hold is lifted. Manual delete actions (a device, a ticket, a user) are not affected.
Mailbox, threading and auto-reply for the ticket system above. Only relevant when Tickets is enabled.
A self-service portal at /portal where your site contacts sign in with an emailed magic link to view & submit support tickets for their own site only — no operator account, a separate session. Enable a contact for the portal (and set its site) from the Contacts directory. Off by default.
https://host the sign-in email links to. Set this so the magic link can't be pointed at another origin via a forged Host header. Blank = use the request host.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.
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.
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).
Connect read-only to other virtualization platforms — VMware vSphere / ESXi / vCenter, Red Hat OpenShift, and VMware Cloud Director. Their status + inventory feed Alerts and the dashboard, the same way Proxmox does. Pick a platform, fill its URL + credentials, Save, then Test.
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.
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.
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.
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.
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).
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.
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.
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.
When enabled, RemotePower runs the same agentic Triage the alert inbox offers — read-only evidence tools, strict tool budget — on new open alerts (one per cadence tick) and stores the verdict on the alert (the “AI verdict” badge). Each run makes several AI-provider calls; the daily cap bounds spend. Requires the out-of-band scheduler — it never runs on the request path (so it can't stall a heartbeat). Unlike the manual Triage button, this sends alert evidence automatically: the affected host’s recent journal, hostname and IP go to your configured AI provider for every matching alert (across all tenants), without a per-alert click. If that provider is off-box, prefer a local model (Ollama/LocalAI) or leave this off and triage manually. Documentation
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.
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.
Counts failed login attempts per source IP in a rolling window. Fires a webhook and shows in Needs Attention when the threshold is exceeded.
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).
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 on the business days + within the window below; anything outside counts as after-hours.
Watch every declared depends_on edge for a silent break: a link that was carrying observed traffic (agent peer-connections or the NetFlow/IPFIX receiver) and then went quiet while both hosts stayed online — a firewall, route or service failure that the device-offline alert never catches. Off by default; only edges that were seen live can ever fire, so nothing false-alarms on a fleet with no flow visibility. Review link status under Network → Dependency link health.
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. Documentation
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.
backup_size_anomaly when a fresh backup drops below this fraction of its trailing median size — catches a truncated/half-written backup that's still recent.Verification runs the backup tool's own integrity check (tar -tf, restic check, borg check) at most weekly, time-bounded. tar needs nothing; restic/borg need their passphrase in the agent's environment (e.g. RESTIC_PASSWORD_FILE / BORG_PASSPHRASE in the agent unit). A failed check fires backup_verify_failed. A restore drill goes further — it actually restores the given sample path from the latest archive into a throwaway sandbox (never over live paths), checks it's non-empty, then deletes it; a failure fires restore_drill_failed.
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.
Regex patterns (case-insensitive). Any log line matching a pattern is silently dropped before storage and alerting — for harmless kernel notes, vendor noise, etc.
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.
How many consecutive failures (or how stale) before a monitor pages. Higher values ride out brief blips; lower values page sooner.
Failed SNMP polls before snmp_unreachable, then snmp_dead (critical); breaches before a metric alert; and seconds without a container report before containers_stale.
Interface error and clock-drift thresholds.
New errors/drops on one interface in a single heartbeat before nic_errors; NTP offset before clock_skew.
Temperature, UPS and controller disk headroom.
Sensor temperature fires temp_high; UPS charge/runtime below these are critical; the controller's own data-dir fill % fires server_disk_low.
Pending-update and cross-device incident thresholds.
Pending updates on a host before patch_alert; devices hit by the same alert before a status-page incident auto-opens.
Pool-scrub and snapshot-age thresholds.
Time since the last scrub before scrub_overdue; newest pool/Proxmox snapshot age before snapshot_stale; newest per-guest Proxmox backup age before the stale-backup NA item.
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. Set to 0 to disable.
The health-score boundaries that decide a device's grade and the colour of the dashboard score — good (green), fair (amber), poor (orange); anything below poor is critical (red). A score at or above each value takes that grade. Keep them descending.
The per-asset security/posture risk score boundaries that decide an asset's level and badge colour on the Risk Assessment page — critical (red), high (amber), medium; anything below medium is low (green). A score at or above each value takes that level. Keep them descending.
The failure-likelihood reliability score boundaries that decide a host's predicted-failure level — critical, high, medium; below medium a host is not flagged. A host crossing the medium cutoff raises the "likely to fail" Needs-Attention card and a reliability alert, so a low bar here becomes noise. Keep them descending.
Fullness percentages that fire metric_warning/metric_critical for inode, file-descriptor and conntrack-table exhaustion. A per-device threshold override still wins over these fleet defaults.
Flap-dampening confirm counts before a host, resolver or IP-reputation signal pages. Higher rides out transient blips; lower pages sooner.
Missed poll intervals before device_offline; consecutive down scans before resolver_unhealthy; consecutive listed scans before ip_blacklisted.
Certificate-expiry windows (days). TLS warn/crit are the fleet defaults for monitored TLS targets that don't set their own; cert-file is the local x509 inventory window.
Consecutive crt.sh certificate-transparency poll failures for a watched domain before it circuit-breaks for 24h.
Warn/soon windows (days) for contract expiry, OS end-of-life and AV/Defender signature staleness — the date-based Needs-Attention verdicts.
Defender signature age: the Checks engine warns at the warn value and is critical at the AV-signature-stale value above — so all Defender-staleness surfaces agree. The CPU busy % bands apply to Windows/macOS hosts (which report a busy percentage); Linux hosts use per-device load-ratio thresholds in the device Thresholds modal.
Temperature cutoffs (°C) for the Thermal and GPU pages. Hot flags a host/GPU and drives the "hot" count and the amber cell colour; critical marks it critical (red) and feeds the overheating risk/reliability factors. Keep critical above hot.
Predictive disk-health thresholds. Wear warn/high percentages colour the SSD/NVMe wear cell and raise its risk; realloc/pending critical is the bad-sector count treated as critical and the ETA target; medium-risk ETA suppresses a disk_predict_fail for a medium-risk disk unless it's within that many days; ECC min delta is the floor a per-beat correctable/uncorrectable increase must exceed to fire ecc_errors (0 = any increase fires). Keep wear high above warn.
Points deducted from a device's 0-100 health score per Needs-Attention item, by severity. Higher = a bigger hit to the score (and the fleet average). 0 disables that severity's deduction. Blank uses the default.
Points each posture/security signal adds to a device's 0-100 risk score. Per-occurrence factors are marked (each) and may be capped. Higher = more impact on the score. 0 disables the factor. Blank uses the default.
Points each signal adds to a host's 0-100 failure-likelihood (reliability) score. Higher = more impact on the predicted-failure score. Some factors are capped internally. 0 disables the factor. Blank uses the default.
Disk-fill ETA (days-to-full) cutoffs drive the SAME verdict everywhere — the Needs-Attention digest, the Checks engine row and the disk-health cell colour. Pending-update count fires an NA warning (below it, informational). OOM window is how long after an OOM kill a host still counts as recently-OOM'd.
Container restart-delta and "restarting" thresholds, plus the fleet-default SNMP CPU cutoffs (a per-device threshold override still wins).
Transient-event NA lifetime, after-hours activity window, agentless ping-fail debounce, per-poll GitHub-issue cap, metric-recovered hysteresis buffer, and the online-TTL flap floor.
Compliance TLS-expiry and recent-events windows, and the CIS disk/swap fullness ceilings and DMARC minimum pass percentage.
The control plane's OWN health pill (top bar). High-load = 5-minute load average above cores × this ratio; memory and fleet-online percentages below feed the pill's reasons.
Unstable-host detection (returns-to-online in a window) and the reboot-churn and high-wear thresholds that feed the failure-likelihood score.
Monitor checks kept is the window the Live Monitor sparkline, the latency percentiles and SLO availability are all computed over — at a 60-second cadence, 300 checks is about five hours. Raising it costs storage proportionally; the retention sweep on Settings → Data still prunes by age on top.
Float thresholds: the R² floor below which a disk-fill date is not projected, the disk/health reliability trend cutoffs, and the CVSS base-score bands that classify a CVE as critical / high / medium. Blank uses the built-in default.
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.
Click Generate IaC to begin.
| Time | Actor | Device | Command |
|---|---|---|---|
| Device | Command | Scheduled for | By | |
|---|---|---|---|---|
| No scheduled jobs. | ||||
What's new — v6.4.2 “Qu1etMatters” — two things about containers that were quietly unfinished. You can now silence one container without silencing its host — the restart loop you already know about, the sidecar that exits by design, the stack you are mid-rebuild on — while its nineteen neighbours keep alerting exactly as before. And the Logs button, which used to queue a command and show you a toast, now opens a real log window: it waits for the agent and says how long it has been waiting, fetches 100 to 2000 lines instead of a fixed 50, filters as you type, colours errors, and offers Copy, Download and Explain logs. Also: the Windows agent can finally run container actions — it has reported containers since v6.2.0, so the page has been drawing Start/Stop/Restart/Logs buttons for Windows hosts ever since and every one came back unsupported command — plus a cross-tenant leak fixed in the Monitoring → Tuning mute list.
Mute everything about one container. Every container in Fleet → Containers → View gains a Mute button that silences every alert naming that container on that host — stopped, disappeared, restart loop and the matching recovery events — while the other containers on the same host keep alerting. Previously the only granularity was the whole host: mute container_restarting and you lose it for all twenty containers.
A mute is a paging decision, not an erasure. No inbox rows, no webhook, e-mail or push, and the container stops counting toward needs-attention and the health score — but fleet-event history still records it and the SIEM stream still receives it, so Monitoring → Tuning can still show you what you are silencing and how often it fires. The Containers page keeps counting muted containers in its stopped/restarting totals and adds an N muted note beside them: it is an inventory view, so it shows everything and flags what is suppressed. Open alerts for that container are resolved the moment you mute, so the row that prompted the mute cannot sit open forever with its recovery event now silenced. Mutes share the existing alert-mute store, so they appear in the Tuning mute list labelled with the container name and lift from either place — and muting is undoable from the topbar arrows.
A log window that says what is happening. Logs now waits for the agent instead of returning immediately, showing a progress bar and a live elapsed count while it does, so “still going” and “broken” stop looking identical. If the agent has not checked in within the wait window it keeps watching the device's command output and says so, in seconds, until it gives up after five minutes with an explanation rather than an empty box. You get 100 to 2000 lines instead of a fixed 50, an as-you-type line filter, error and warning colouring, Copy, Download and Explain logs — the last three always acting on the whole log, never the filtered view — and optional 30-second auto-refresh. When the agent's 32 KB per-command output cap bites it keeps the newest lines — a tail is a tail — and marks where older ones were dropped. The same window opens from the device drawer's container table, so there is one container-log view in the product rather than two. The wait is matched to the exact command queued, so a logs request sitting behind a queued restart can never render the restart's output as your logs, and a container whose name is a prefix of another's (web / web2) can never show the wrong one.
Windows container actions. Start, stop, restart, pause, unpause and logs now run through docker on Windows exactly as they do on Linux, argv-only with the same container-id validation. Update (pull and recreate) is deliberately not implemented there and refuses with a message saying so, rather than half-working.
Fixed. A cross-tenant leak on Monitoring → Tuning: the noisy-events timeline on that page is scope- and tenant-filtered, the mute list one line below it was not, so a tenant-scoped administrator could read every other tenant's muted alerts and the hostnames attached to them. Found while adding container mutes; nothing was reachable without authentication. And the device drawer's container Logs button passed the container name through the dispatcher's numeric coercion, so a container called 0x10 was requested as 16.
See docs/v6.4.2.md. Older releases → CHANGELOG.md.
What's new — v6.4.1 “Cust0dyMatters” — key custody. A built-in KMIP key server so a Synology NAS, TrueNAS box or vSphere cluster stops keeping its encryption keys on the same hardware that holds the encrypted data — off by default, a separate sandboxed sidecar, mutual TLS only, with an encrypted recovery bundle because key custody without a way back is a liability. Plus installer flags for the optional receivers, an INGEST & KEYS view in the CLI, two monitor fixes from the field, and a dead-signal sweep: CPU and board temperatures that were collected and stored but never rendered on Thermal Health, and four Security Advisory inputs — sshd posture, TLS expiry, brute-force pressure and the CVE ignore list — that were written against data nothing produced. Also an SNMP OID browser, dialogs that stop closing on a stray click, one dialog width scale, and monitor history five hours deep instead of fifty minutes. Windows and macOS reached full signal parity with Linux — watched services, file-path log rules, disk-usage scans and laptop battery/chassis all report now, so a closed lid stops paging like a dead server — and a file-path log rule finally matches on every platform, including Linux, where the units were being dropped at ingest. Plus a notification filter that never filtered, KMIP on Server status with a warning before its own certificates expire, device rename, firewall dry-run on the host, and an interface tidy-up: one body size, one icon size, and table action buttons that sit in a row instead of stacking.
KMIP key server. A built-in KMIP key server (remotepower-kmipd, tcp/5696, opt-in) so Synology DSM, TrueNAS and VMware vSphere store their encryption keys here instead of on the appliance holding the encrypted data. Mandatory mutual TLS with a private CA; a three-step wizard picks the appliance type, issues the certificate, hands you the three files and waits for the client’s first connection. Keys are AES-256-GCM at rest and scoped to the owning client; every connection, auth failure, key operation and admin action lands in an on-page activity log. A passphrase-encrypted recovery bundle holds the master key, CA and every key — and the master key is deliberately excluded from scheduled backups, so a stolen archive is ciphertext only. An appliance that unlocks against this server needs it reachable at boot — never run it on a machine that depends on it to unlock. Also: --with-kmip, --with-syslogd and --with-flowd installer flags (all off by default), and an INGEST & KEYS block in rp status / rp tui showing what the receivers actually ingested.
Monitors: an error you can act on. A rejected monitor target used to say only Invalid monitor target: <url>, which cannot tell a typo'd URL from a perfectly good one that this server's resolver answers with a blocked address — and since only http/https and tcp resolve the hostname, the failure looked type-specific and made no sense. The message now names the resolved IP, the rule that rejected it, and the setting that permits it (“resolves to 127.0.0.1 on this server … enable Settings → Allow monitoring of internal / loopback targets”). A filtering resolver answering 0.0.0.0 is called out by name. An unresolvable host is still allowed — “cannot classify” must not become “reject”.
One stale monitor no longer blocks the rest. The editor re-posts the whole monitor list, so a single pre-existing entry that no longer validates — a satellite since deleted, an older tcp entry without a port, a target whose DNS answer changed — used to reject the entire save and name the other monitor, making it impossible to add or even delete an unrelated one. Now only the entry you actually touched fails; an untouched broken one is kept as-is and reported as a warning so it cannot rot unseen.
Signals that were collected but never reached you. Thermal Health showed disks and GPUs but never CPU or board sensors: the agent collects them and the server stores them correctly, one level deeper in the record than SMART and GPU data, and three readers looked at the shallow key — so the overheating risk signal could only ever fire on a hot disk, never a cooking CPU. The Critical and Headroom columns were blank for a separate reason: the sanitizer dropped the sensor's critical threshold. And four Security Advisory inputs were written against keys nothing produced — sshd posture (so the whole identity layer was unreachable; the agent now runs sshd -T, which resolves Includes and Match blocks rather than reporting what the config file happens to say, and flags permitted empty passwords), TLS expiry (repointed at the TLS monitor's real results), brute-force pressure (repointed at the store the data is actually in, and the advice now states whether fail2ban is jailing rather than asking you to check), and the CVE ignore list — an accepted-risk CVE vanished from Risk and kept driving the advisory. KEV data is applied too, so a CVE known to be exploited outranks a critical nobody has weaponised. The advisory's data layer, declared since it shipped and empty ever since, now carries secret-scanner findings, stale backups, FileVault and BitLocker.
Risk scores what it already knew. docs/risk.md described CVEs weighted by KEV, container posture and backup freshness — the scorer implemented none of the three. Rather than trim the doc, the code now does what it claimed, plus three more signals collected and scored nowhere. Six new factors, each a tunable weight on Settings → Alert parameters (0 disables), each capped: CVEs on CISA’s KEV list rank above severity alone, because KEV means exploitation has been observed rather than predicted — though a CVE you accepted on the ignore list still doesn’t count; malware / AV posture (an active detection, or real-time protection switched off — a host with no AV record at all is not a finding, because absent data must not read as “infected”); CVEs in running container images at half a host package’s weight and capped, so one unpatched base image can’t swamp the score; and stale backups, exposed credentials and patch-SLA breaches, the last taken from the same evaluator the Patch SLA page uses so the two can never disagree. The Security Advisory gains OpenSCAP results — a parallel scoring silo with no route into “what should I fix”, despite every failed rule carrying a severity and a remediation id — and agent-binary tampering, which previously reached nothing but a badge on the device row, plus config files drifted from baseline (paths only — the captured diff can carry a credential, and the Drift page already shows it) and authorized SSH keys on deprecated algorithms. Underneath both, one shared reading of each store: Risk and the Advisory stay separate systems on purpose, but they no longer each have their own idea of which CVEs you have accepted.
macOS: custom checks and file-integrity watching were never running. The same shape, on a different surface. The macOS agent read 13 of the keys the server sends in its heartbeat response where the Linux agent reads 48, and two of the gaps were features you could switch on from the UI and get a success toast for. Custom checks assigned to a Mac reported unknown forever — the server pushed the definitions, the page showed them applied, and the agent never read the list. Watched files produced no drift report at all for the same reason. Both run now. A check type a Mac genuinely cannot evaluate reports unknown with the reason attached — a deliberate third answer, since OK would be a silent false green and critical would be an alert nobody can act on. New check type launchd_service, the macOS counterpart to systemd_unit and windows_service: a job that is loaded but idle reports warning, not critical, because that is normal for an on-demand launchd job. Ten macOS rows joined the check catalog, and the check-type dropdown is translated in all six languages.
SNMP OID browser. The SNMP poll reads the OIDs RemotePower knows how to interpret. When a device exposes something else — a vendor counter, a PDU's per-outlet draw, a UPS runtime estimate — the device drawer's SNMP tab can now walk any subtree with the device's stored credentials, from a preset or a typed OID. Well-known OIDs resolve to names; vendor-private ones stay numeric, because naming those needs a MIB we don't ship and a confident wrong name is worse than a blank. Admin-only, audited, capped per walk, read-only.
Dialogs, widths and small controls. A click beside a dialog no longer closes it on desktop — losing a half-filled form to a stray click is a real cost. Escape still closes, and every dialog now carries a × in its corner, injected centrally so a new dialog can't ship without one; touch and narrow viewports keep backdrop dismissal. Dialog widths were inconsistent enough that two opened from the same page looked different sizes — one scale now, anchored on the CMDB dialog. Bare toolbar selects, the alert-parameter number inputs and the small buttons and chips all got more room.
Monitor history, and quieter drift. Per-monitor check history held 50 entries — under an hour at the default cadence, and the same window behind the Live Monitor sparkline, the latency percentiles and SLO availability. It now holds 300, tunable to 5000 on Settings → Alert parameters. Separately, Snap puts the package revision in its unit filenames, so every snap refresh looked like files appearing and disappearing under /etc/systemd/system — a critical drift diff every few days on any Ubuntu host. Those patterns are excluded; everything else in that directory is still compared byte-for-byte.
See docs/v6.4.1.md. Older releases → CHANGELOG.md.
What's new — v6.4.0 “Sh1eldMatters” — the security-and-protection release. Integrity-guard and baseline checks that behave as expected — disable one and it stops evaluating on the host, not just in the UI; accept a legitimate change as the new baseline with one click — backed by a full public security review and pentest pass (nothing Critical, High or Medium ships). Plus agentic diagnosis used defensively (a bounded, secret-redacted log sweep and read-only alert triage that writes a verdict with its evidence trail), a data-binding sweep so everything the agent collects reaches the UI, RAG and AI, macOS security-posture alerts at Windows parity, SLA / SLO objects for remote probes (availability targets with error budgets, filterable and exported as Prometheus gauges), a WordPress connector showing the last logins with IP + geo, the client-side error beacon finally rendered on Server status, and a typography / box-overflow / performance polish wave.
Protection you can trust. Disabling an integrity-guard or baseline check now stops it everywhere — the agent stops evaluating (and, for guard checks, stops quarantining) it, not just the row hiding. Removing a check reaches the agent immediately. Baseline-holding checks get a Reset baseline button right on the Checks row, applied checks can be un-applied straight from the catalog card, and the protect-check tables and quarantine vault are filterable for big fleets. Failure text names the file and what to do about it.
Pentested for the public. A full security review and pentest pass (SAST clean across Bandit, gitleaks and CodeQL; adversarial code review; live probing of the maintainer's own instance) backs this release — the bar is no Critical, High or Medium, and nothing exploitable. See docs/security-review-6.4.0.md.
Everything the agent sees, the AI sees. Per-device hardware health (SMART wear, GPU/UPS/power, kernel-reboot, temperatures, privileged accounts) is now a RAG source, and macOS FileVault/Gatekeeper/SIP/firewall reach the alert path at Windows parity. The always-on AI fleet snapshot carries a health rollup instead of inventory alone.
Hail-mary log sweep. For the “something is wrong but I don't know where” moment: the agent snapshots /var/log/* and /var/log/*/* — only files modified in the last 24 h, compressed/binary/rotated skipped, ≤12 KB tail per file, ≤40 files, ≤256 KB total, ranked by error density + recency. The server re-caps everything and scrubs credential material (password=…, bearer tokens, URL credentials) before storage. Diagnose sends the excerpt to your configured AI provider (only when you click — the modal says so) and renders a verdict, per-file findings and conservative next steps. Windows sweeps the last 24 h of Error/Warning System/Application events instead.
Agentic alert triage. The alert inbox gains a Triage action: the model investigates the alert through a fixed menu of read-only, device-scoped tools — device summary, journal tail, services, the host's other open alerts, recent command output, a regex search over the 6 h log buffer, open CVEs, metric trends, and the latest sweep (self-provisioning when stale) — replying with strict JSON (one tool call or a verdict) each round, hard-capped at 4 tool calls. The stored verdict (root cause, confidence, evidence, recommended action, tools used) shows as an AI verdict badge on the row. The model never executes anything — acting on a verdict stays on the existing approval-gated paths.
Tiered autonomy. Settings → AI Assistant → Automatic alert triage (off by default) runs the same loop on new open alerts from the maintenance cadence — one per tick, severity floor, daily run cap — so alerts arrive pre-investigated (by: auto). Every verdict takes thumbs-up/down feedback (aggregated in AI stats), tickets opened from a triaged alert carry the verdict in their seeded note, and with the AI-executor module enabled, Propose fix (governed executor) turns a verdict into a human-approved remediation pick from your saved actions.
Guarded auto-remediation. Automation rules’ run-script fixes now carry a safety rig: a per-host cooldown and a max-hosts-per-hour blast cap, an opt-in verify window that fires a remediation_failed alert when the fix didn’t clear the triggering alert, auto-disable after consecutive failures, and a per-attempt ledger on the Automations page.
Agentless network flows. A new NetFlow/IPFIX receiver (remotepower-flowd, udp/2055) — the flow sibling of the syslog receiver. Routers, firewalls and L3 switches export flows; the receiver maps each exporter to its enrolled device and shows top talkers, top conversations and a protocol breakdown in the device drawer (Network flows). Parses NetFlow v5/v9 + IPFIX. Add a kind=flow inbound token and point the router at it.
Metrics incident-zoom band. A new 5-minute roll-up tier (kept ~8 days) fills the resolution gap between the raw 24-hour window and the hourly-30-day tier — the band you want when investigating an incident a few days old (hourly smooths away the spike; raw has rolled off). New “7 days (5-min avg)” option on the Trends range selector, and the agentic-triage evidence tool reads it too.
Compliance you can back up. After Assay’s “silence isn’t clearance” discipline: a control no longer reads Pass off an empty offenders list when the telemetry that would assess it never ran — patch/CVE/EOL/reboot/privileged-access controls return Not assessed (never a silent green) when no host reported the signal, and the score ignores Not-assessed so it can’t be inflated. Two frameworks join PCI/HIPAA/SOC 2: ACSC Essential Eight (process controls it can’t observe are honestly Not assessed) and SMB1001:2026. Triage verdicts can now carry proof-labelled MITRE ATT&CK techniques (observed/inferred/theoretical, validated server-side).
Signed command channel. The server now detach-signs every dispatched command with the release signing key, bound to the target device and a fresh timestamp. Pin release.pub and create the operator-owned require-signed-commands marker on a host and its agent refuses unsigned, tampered or replayed commands (reported, never silently dropped) — database or queue tampering alone can no longer execute anything on the fleet. All three agents enforce identically. And docs/ha.md is the new high-availability reference topology: Postgres streaming replication, a floating IP, the promote runbook, and a stated capacity target with a load-test recipe.
SLA / SLO objects. Define a named availability target (99.9% over 30 days) on the Monitoring page and tick it on each remote probe that should count toward it — the new SLA / SLO objects panel shows check-weighted availability, error budget remaining and burn rate per object, filterable by compliance, and the same numbers export as remotepower_slo_object_* Prometheus gauges. Paused probes also show again (they used to vanish from the Remote Checks table, stranding the Resume button).
WordPress logins. A new WordPress connector monitors the site's REST API and — with an Application password and the free Simple History plugin — shows the 5 most recent successful logins (time, account, source IP, and country when a GeoIP database is configured) on the Integrations page.
Client-side JS errors, finally visible. The browser error beacon has collected uncaught frontend errors since v5.4.1 with no UI ever showing them — the Server-status page now renders the ring with a Clear action. Behind the scenes, five new cross-reference test gates (UI wiring, JS undefined-globals, error-path AST checks, CSS parity, response contracts) plus a real-click e2e sweep ran a full error hunt and fixed every finding.
“Reboot if required” is finally conditional. Auto-patch used to reboot after every clean run; now Linux checks the reboot-required marker / needs-restarting / a newer installed kernel, Windows consults its pending-reboot state via a new reboot-if-required verb, and macOS honestly never reboots for brew. A patch window that changed nothing keeps the host up.
Every alert auto-resolves; every alert says more. The auto-heal gap list is empty (cve_cleared, patch_ok, tls_renewed, ecc_stable, secret_cleared), point-in-time alerts carry a confirm badge, every stored payload fact renders as a detail line, protect/baseline alerts link straight to Monitoring → Checks → Accept change, the AV mitigation AI is pinned to the tool that raised the alert, and every async button shows a working spinner + settle pulse.
Syslog receiver watcher. Server-status → Distributed subsystems now shows the agentless syslog receiver (sources, last intake, unit probe) as an informational row — never a warning; opt into alerting with the new rp_syslogd_running baseline-checks catalog row (tag the server host rp-server).
See docs/v6.4.0.md. Older releases → CHANGELOG.md.
Older releases — v6.3.0 and earlier
Per-release notes for the three 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:
| Metric | Warning | Critical |
|---|---|---|
| Disk usage (per mount) | 80% | 90% |
| Memory | 85% | 95% |
| Swap | 20% | 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 the main app server handles short request/response cycles, not the long-lived connections a terminal needs. 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 app-server user (www-data, nginx, http, etc.), installs Python deps, generates the daemon ↔ app 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). By default a dedicated remotepower-scheduler service runs them out-of-band; if you disable it the schedule falls back to piggybacking on incoming API requests, so as long as any agent is heartbeating or anyone's browsing, monitors still 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, underscores or hyphens, up to 40 characters) 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 the data directory /var/lib/remotepower/ — PostgreSQL by default since v6.1.0 (flat JSON files with --no-postgres, or a single SQLite database). 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 the app server 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 (default). Compact = small cards. Comfortable = larger cards. 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.
39 connectors (plus a Custom HTTP probe): Pi-hole, AdGuard, TrueNAS, Unraid, Kubernetes/k3s, VMware vSphere/ESXi/vCenter, Red Hat OpenShift, VMware Cloud Director, Proxmox Backup Server, UniFi, Traefik, Nginx Proxy Manager, Caddy, Netdata, Grafana, Uptime Kuma, Jellyfin, Plex, Home Assistant, Nextcloud, GitHub Issues (raises a github_new_issue alert when a new issue is opened on a watched repo), Immich, Paperless-ngx, Vaultwarden, Gitea/Forgejo, Syncthing, Frigate, OctoPrint, ESPHome, Homebridge, RemotePower (peer instance), the download clients (qBittorrent, Transmission, Deluge, SABnzbd, NZBGet), the *arr suite (one Servarr connector for Sonarr/Radarr/Prowlarr/Lidarr) + Bazarr, Overseerr/Jellyseerr, and a generic Custom HTTP probe for anything else.
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.
App catalog — one-click app deploys via Docker Compose
The App catalog deploys curated, self-contained apps to a host in one click. Pick an app, pick a target host, and RemotePower instantiates the bundled Docker Compose template as a stack on that device — redeploying an existing same-named stack is idempotent. The target device must have compose deploys enabled (a per-device opt-in in the Devices drawer).
Custom entries (admin): add your own app to the shared catalog by pasting a compose template — name it, give it a category and description, and it appears alongside the curated apps for everyone. Built-in entries can't be removed.
Gated on the containers permission, scope-checked and audited; the deploy itself rides the existing, proven compose-deploy command path — adding a catalog entry never runs anything on its own.
File manager — browse / view / edit host files, no SSH
The Files device action browses, views, and edits files on a host straight through the agent — no SSH session, no SFTP, no inbound ports. Open a path, read a file (size-capped), edit it in the browser, create folders, or delete a file.
Every operation is confined to an allowlisted set of browse roots (symlink-resolved, with /proc, /sys and /dev always off-limits), gated on the same command permission as remote exec, and fully audited. Reads stay available on quarantined / audit-mode hosts (useful for incident response); writes, folder creation, and delete do not.
The whole feature is opt-in per server under Settings → Advanced (off by default), since it is a powerful capability.
Cron & timers — manage crontabs and systemd timers
The Cron & timers page shows a fleet summary of scheduled work and, for a chosen host, its full crontabs, cron.d entries, and systemd timers (with failed-timer state). Edits run through the same audited, permission-gated command queue as remote exec, and quarantined / audit-mode hosts are skipped.
Crontab content is installed via a temporary file, never a shell, so its contents can't be interpreted as commands. Telemetry view: unmonitored hosts still appear, flagged.
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_upwebhooks. - 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.listandsources.list.d/(classic.list+ deb822.sources), or/etc/yum.repos.d/*.repo - Netplan — written to
/etc/netplan/01-remotepower.yaml, thennetplan 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 withvisudo -cbefore 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 proxy_read_timeout defaults to 60 s and will cut you off first — add a location /api/ai/ block with proxy_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):
- Settings → API keys → Generate a viewer token; copy the
rpk_...value. - Copy
remotepower-mcp.pyto your laptop (scpworks). - Edit
~/Library/Application Support/Claude/claude_desktop_config.json(macOS) or%APPDATA%\Claude\claude_desktop_config.json(Windows) — add anmcpServers.remotepowerentry with the command, args, and env (URL + token). - 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):
- One webhook for page-me-now events:
device_offline,service_down,monitor_down,metric_critical,cve_found. Point at ntfy / Pushover / your phone. - One webhook for FYI-during-business-hours events:
metric_warning,patch_alert,log_alert,container_stopped. Point at a Discord/Slack channel. - Email digest for the slow stuff (weekly CVE summary, patches pending) once
cron_email_digestis 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:
- Select a device, the categories of state you care about, and an output format.
- Click Generate IaC (full LLM flow) or Gather RAW JSON (collect only, download masked state).
- On the agent's next heartbeat (~60 seconds), it collects the requested categories and sends raw state back.
- 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. Categories tracked separately: Needs Attention, Stale containers, Devices, ignored CVEs, and cleared log lines.
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):
- Each incoming line is hashed (
sha1[:16]) and compared against the buffer. Duplicates are dropped at ingestion. - 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], syslogMon DD HH:MM:SS, ISOYYYY-MM-DDTHH:MM:SS. - 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_alertwebhook withseverity: "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 editable card per AI feature.
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/adminaccount hasmust_change_passwordset. A persistent banner in the UI nags until the password is changed. - Backup export: the
/api/backupexport 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|PRIVATEare 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:
- 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. - 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 betweenBEGIN_FIX/END_FIXmarkers. - 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 infailed(critical) orinactive/deactivating(warning). Carries the unit name astargetso the Investigate button can runsystemctl status+journalctl -u <unit>automatically.monitor_down— any monitor target whose latest probe came backok: false.custom_script_fail— any custom monitoring script reporting non-zerorcin 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.
| Group | Pages |
|---|---|
| Fleet | Devices, CMDB, Containers, Virtualization, Network |
| Monitoring | Targets, Device Metrics, Listening Ports, Custom Scripts, Services, Logs |
| Security | TLS/DNS, Patches, CVEs, Drift, Audit |
| Planning | Schedule, Calendar, Tasks, Maintenance, History |
| Admin | Settings, 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. Categories: Needs Attention (per-alert), Stale containers, Devices, ignored CVEs, and cleared log lines (from the Alerts inbox "Clear line" / "Silence rule").
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/remotepowerregardless of the 24h cadence. - Export backup — also triggers a snapshot before streaming the ZIP download.
- Clear backup archives — deletes all
remotepower_data_*.tar.gzand encrypted*.tar.gz.encarchives 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.
Working the interface — undo, notification center, drafts, tables, charts (v6.3.0)
Low-risk deletes are undoable instead of confirmed (the API call fires only when the toast expires); the topbar arrows and Ctrl-Z drive a global undo stack. The bell replays the session's toasts; editors autosave drafts; Settings keeps configuration history with rollback. Tables filter/sort/export everywhere; device selection supports shift-click ranges; charts have hover crosshairs and the drawer opens with a posture radar.
Full doc at docs/ux.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)
The load cache is request-scoped, so it lives only as long as one handler even on the persistent gunicorn/Flask server. 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.
Conversation history is kept in your browser (localStorage) — not on the server. Clearing the conversation clears only your view.
Each background maintenance sweep's last successful run and any recent error. A sweep that silently stops running or starts failing shows up here instead of quietly taking a feature down with it.
Uncaught browser-side errors reported by operators' sessions (window.onerror beacon). A JS failure dies silently in the user's console otherwise — anything listed here is a bug worth a look. Newest first, ring capped at 200.
Silence isn't clearance: a green dashboard proves the monitoring found nothing, not that it would. This verifies every alertable event type routes to at least one channel that reaches a human, and flags the silent gaps — an alert kind you've muted on every channel, sandbox mode left on, or a recover event that can never close its alert. Documentation
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). Debian — ssg-debian matching the release, then an ANSSI BP-028 profile. RHEL/Fedora — scap-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./tmp, /run, /dev/shm, …) are excluded, and a heavily-fluctuating mount shows fluctuating instead of a misleading date. Documentation.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.
Build a report from the sections you care about, download it, or schedule it to a specific audience. Saved per server.
Send the report to notification destinations instead of (or as well as) email — most homelabs never set up SMTP but always have ntfy or Discord, so an email-only report is one nobody reads. Configure destinations under Settings → Notifications. A report sent this way ignores the destination's event and priority filters: you chose it here on purpose.
| Host | Group | Check | Status | Output | |
|---|---|---|---|---|---|
| Loading… | |||||
The guard and verify fields apply to the run-script action: per-host cooldown and the hosts/hour cap bound the blast radius, and verification fires a remediation_failed alert — and eventually disables the rule — when the fix doesn't clear the triggering alert. Documentation
Every run-script firing lands here: queued, verified (the triggering alert cleared inside the verify window), failed (it didn't — a remediation_failed alert fired), or suppressed (a blast-radius guard stopped it).
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.
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.
Commands are signed with the same key (v6.4.0): every dispatched command carries a detached signature bound to the target device + a fresh timestamp. Hosts that also create /etc/remotepower/require-signed-commands refuse unsigned, tampered or replayed commands outright — database/queue tampering alone can no longer execute anything. Documentation

| Agent version | — |
| GitHub | github.com/tyxak/remotepower |
| License | MIT |
| Latest release | checking… |
| Report a bug |
A self-hosted fleet manager for Linux, Windows and macOS — far more than remote control. Real-time monitoring, metrics and forecasting; security posture (CVE/KEV scanning, patch management, config-drift, CIS/compliance, firewall & fail2ban, AV/rootkit, IP-reputation/DMARC); an AI assistant grounded in your own fleet (RAG) with per-subject advisors and a searchable knowledge base; a built-in helpdesk (tickets, SLAs, email threading) plus time-tracking & billing; DNS management, homelab integrations and a WireGuard access VPN; virtualization control across Proxmox, VMware (vSphere/vCenter, Cloud Director) and OpenShift; infrastructure provisioning with server-side Terraform, Ansible and cloud-init; staged rollouts, alerting with escalation and per-host tuning, audit & governance, optional hard multi-tenancy — and of course full remote control: shutdown, reboot, Wake-on-LAN, scheduled commands, custom scripts and agent self-update.
No inbound firewall rules on clients — agents poll the server over HTTPS. Runs on Nginx + Python (gunicorn + Flask); a single install provisions PostgreSQL, an out-of-band scheduler and a scanner satellite by default, with a lighter flat-JSON/SQLite backend available for constrained or dev installs. Deploy from source or the official multi-arch Docker image. No Node.js, no build step.
…
| Run a query to see results. |
| Name | Role | User | Rate limit | Created | Expires | |
|---|---|---|---|---|---|---|
| Name | Reach | Clients | Port | Expires |
|---|
| Name | Address | Status | Endpoint | Transfer | Expires |
|---|
Sites with coordinates plotted on a world map, colored by rolled-up device health (green all-online · amber some-offline · red all-offline). Set a site's latitude/longitude from its row. Click a dot to filter the table below.
| Name | Slug | Devices | Created | |
|---|---|---|---|---|
| Loading… | ||||
When a new device enrols, the first matching rule stamps its group / site / tags automatically — by hostname (regex) or source-IP range (CIDR). Enrolment-token defaults always win: a rule only fills a group left empty and merges extra tags. Rules never touch already-enrolled devices.
A named bundle of per-device settings — poll interval, watched systemd units, log watches, drift-watched files, metric thresholds. Applying a profile stamps those fields onto the devices you pick; it's a one-shot copy, so each device stays individually editable afterwards.
A saved fleet query whose membership is re-evaluated every ~60s. Use it as a targeting scope — reference it as smart:<name> in alert-routing, auto-patch, report and service-baseline scopes. It doesn't change a device's real group.
Model your racks and place assets in them (set rack, bottom U and height on an asset in the CMDB). Overlapping units are flagged. Front elevation view. Documentation
Define subnets; occupancy is derived from known device addresses (device IP + CMDB interfaces incl. NAT) plus static reservations. A duplicate IP across two devices raises an ip_conflict alert. Documentation
| Device | Group | OS | Status | Pkg Manager | Pending | Patch Status | Recent Patch Cmds | |
|---|---|---|---|---|---|---|---|---|
| Click Refresh to load patch report. | ||||||||
Flag hosts whose pending updates have gone unpatched too long. Set a maximum age (days) for security and/or all updates, scoped to a group, tag, or the whole fleet — first matching rule wins. Breaches raise a patch_sla_violation alert. Reporting only; nothing is auto-installed.
exec permission; honours quarantine and change-windows.| Device | Group | Ecosystem | KEV | Critical | High | Medium | Low | Last scan | |
|---|---|---|---|---|---|---|---|---|---|
| Click Refresh to load findings. | |||||||||
Vulnerabilities found in the images of running containers, grouped by image across the fleet. Enable per-fleet in Settings → Security (needs trivy on the hosts). Trivy re-scans every ~24h; Scan now triggers it on the next heartbeat.
Group CVEs into an owned, deadlined effort and track the affected-host burn-down. Scope by severity/KEV or an explicit CVE list. A campaign completes (and fires campaign_completed) when zero hosts remain affected. Burn-down is sampled daily.
| Target | Status | Crit | High | Med | Low | Info | Created | |
|---|---|---|---|---|---|---|---|---|
| No scans yet. Select an enrolled device and queue one. | ||||||||
| Device | Group | Watched | Up | Down | Last report | |
|---|---|---|---|---|---|---|
| Click Refresh to load. | ||||||
A baseline watches a default set of systemd units across every device its scope covers — merged with each host's own list, so you don't edit each host. Also reachable from a device's Configure watched services → Edit baselines.
log_alert webhook.| Device | Group | Unit | Pattern | Threshold | |
|---|---|---|---|---|---|
| No per-device rules configured. | |||||
* for the unit to match any unit on any device.
| Unit | Pattern | Exclude pattern | Threshold | Created | |
|---|---|---|---|---|---|
A rule matches a class of lines, so one routine message re-fires forever. Clearing a line stops it counting toward the rule's threshold — a genuinely different message still alerts. Un-clear one to hear about it again. Documentation
| Line | Scope | Unit | Caught since | Cleared | |
|---|---|---|---|---|---|
| Nothing cleared yet. | |||||
| Reason | Scope | Target | When | Events | Status | |
|---|---|---|---|---|---|---|
| Click Refresh. | ||||||
| When | Event | Device | Window | Reason |
|---|
| Name | Target | Schedule | Reboot | Enabled | |
|---|---|---|---|---|---|
| Loading… | |||||
| Name | Device | Schedule | Last run | Enabled | |
|---|---|---|---|---|---|
| Loading… | |||||
| Name | Last run | Result | |
|---|---|---|---|
| Loading… | |||
Attach a KB article to an alert type. When an alert of that type fires, operators see a one-click Runbook link on it in the Alerts inbox — straight to your response procedure.
Rolling reboot
Reboot a scope in dependency-ordered waves — devices nothing depends on first, upstreams last (from each device's declared depends_on). Each wave is health-gated and verified before the next, exactly like a rollout. Preview the waves, then create the rollout.
| Name | Asset ID | Function | OS | IP | Hypervisor | Docs | Creds | |
|---|---|---|---|---|---|---|---|---|
| Scope | Label | Username | Devices | |
|---|---|---|---|---|
| Loading… | ||||
| Device | OS | Total | Running | Stopped | Restarting (≥5) | Disk | Runtimes | Reported | |
|---|---|---|---|---|---|---|---|---|---|
| Image | Tag | Hosts | Status | Registry | Last checked | |
|---|---|---|---|---|---|---|
| Stack | Device | Status | Last action | |
|---|---|---|---|---|
connected_to links and tunnels (peer links). Drag nodes to reposition — positions persist across refresh. Add agentless devices on the Devices page. DocumentationJob check-ins (dead-man's switch)
For cron jobs on things that aren't in the fleet — the router's backup script, a VPS, a task on the NAS. Those fail silently and you find out months later. Give the job a URL, have it curl that URL when it finishes, and if a check-in doesn't arrive within its period + grace, RemotePower alerts. (This is the inverse of the outbound healthchecks.io pinger, which watches RemotePower.)
LAN services (mDNS)
The netscan finds hosts — it tells you an IP is alive, not what it is. mDNS is how the rest of a homelab announces itself: Chromecasts, AirPlay speakers, printers, HomeKit bridges, NAS boxes. Those are exactly the devices nobody enrols an agent on, so without this they're just anonymous IPs on the map. Enable under Settings → Security; needs avahi-browse on at least one agent per segment.
Edges inferred from actual outbound connections between your devices (private IPs only). Accept adds a real depends_on link (used for downstream alert suppression); dismiss hides it.
Verifies each declared depends_on edge against observed traffic (agent peer-conns and the NetFlow/IPFIX receiver). A Broken edge carried traffic before and went silent while both hosts stayed online — a firewall/route/service break the offline alert never catches. Enable alerting under Settings → Alerts.
Physical neighbor links discovered via LLDP (needs lldpd on the hosts). Accept sets a connected_to edge (a manual/physical link that always wins over inferred ones); dismiss hides it.
Hosts seen by agents that ran a LAN scan (device drawer → Health & Hardware → Scan LAN) and that aren't enrolled in RemotePower.
Per-device network throughput (RX/TX) from agent samples — fleet-wide, or rolled up by group, tag or site (a site represents a customer). Unmonitored and decommissioned hosts are shown but flagged.
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.
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.
| Device | Group | Files watched | Drift | Missing | Last check | |
|---|---|---|---|---|---|---|
Hardening and tamper-detection checks applied to this fleet. They evaluate exactly like any other check — results show per host on Monitoring → Checks and alert through your normal channels. A guard badge means auto-quarantine is enabled for that check. Agent-side results arrive on the next sysinfo report (up to ~10 min), so new rows read unknown until then. Documentation
| Name | Type | Param | Applies to | |
|---|---|---|---|---|
| Loading… | ||||
Restore returns a file to its original path — only if that path is still free, so a replacement is never overwritten. Delete removes it from the vault permanently. Both are applied by the agent on its next check-in. Quarantine is suppressed during an active maintenance window, and a mass change (a deploy) is reported rather than quarantined.
| Host | Original path | Quarantined | |
|---|---|---|---|
| Loading… | |||
| Device | Proto/Port | Process | Bind address | Scope | |
|---|---|---|---|---|---|
| Loading… | |||||
| Device | Type | Path | Preview | Line | |
|---|---|---|---|---|---|
| Loading… | |||||
| Name | Type | Size | Modified | Mode | |
|---|---|---|---|---|---|
| Pick a host, then Open a path. | |||||
| Unit | Activates | State | |
|---|---|---|---|
| — | |||
| Device | Backends | State | Rules | Drift fingerprint | |
|---|---|---|---|---|---|
| Loading… | |||||
| Device | Jails | Banned IPs | Status | |
|---|---|---|---|---|
| Loading… | ||||
The master key and every stored key travel ONLY in a passphrase-encrypted recovery bundle — scheduled backups deliberately hold ciphertext without the master key. Export a bundle after setup and whenever keys change, and keep it away from the appliances that depend on this server.
Destroys the master key, the CA, every client and every stored key on this server, so you can reinstall from scratch. Anything still relying on it for encryption keys becomes unrecoverable without a bundle exported beforehand.
Appliances allowed to talk to this KMIP server. Each holds a client certificate issued here; revoke to cut an appliance off, re-issue to replace a lost certificate without losing its keys.
| Name | Type | Certificate | Last seen | Keys | Status | |
|---|---|---|---|---|---|---|
| Loading… | ||||||
Managed objects held for the clients above — metadata only; key material is never shown. Destroying a key that an appliance still needs makes its encrypted data permanently unrecoverable. A destroyed key stays listed as a record until you remove it.
| ID | Name | Type | Algorithm | State | Client | Last access | |
|---|---|---|---|---|---|---|---|
| Loading… | |||||||
| Time | Event | Client | Operation | Object | Result | Detail |
|---|---|---|---|---|---|---|
| Loading… | ||||||
| Device | Risk | Level | Top factors |
|---|---|---|---|
| Loading… | |||
| Host | EDR | Protected by | Agent |
|---|
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.| Device | Pool | Type | State | Capacity | Last scrub | |
|---|---|---|---|---|---|---|
| Loading… | ||||||
Pools with a Maintain… button can run scrubs, trims/balances, status checks and snapshot cleanup directly — the command is built server-side and queued on the host (admin-only, audited). Output appears under Devices → the host.
| Device | Max temp | Hottest sensor | Type | Threshold | Headroom | Trend (~24h) | Sensors | |
|---|---|---|---|---|---|---|---|---|
| Loading… | ||||||||
authorized_keys entry across the fleet, with OpenSSH SHA256 fingerprints. Weak key types and keys reused across multiple hosts are listed first. Documentation.| Device | User | Type | Comment | Fingerprint | Hosts |
|---|---|---|---|---|---|
| Loading… | |||||
| Device | UPS status | Battery | Load | Runtime | Power |
|---|---|---|---|---|---|
| Loading… | |||||
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.
| Risk | Device | Disk | Wear | ETA | Signals |
|---|---|---|---|---|---|
| Loading… | |||||
| Device | Restarts (7d) | Last boot reason |
|---|---|---|
| — | ||
| Score | Device | Why |
|---|---|---|
| — | ||
| Device | Rule | Package | Expected | Found |
|---|---|---|---|---|
| Loading… | ||||
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.
| Name | Type | Content | TTL | Flags |
|---|
| Name | Type | Health | Latency | Resolvers | Checked |
|---|
| IP | Label | Status | Blocklists | Checked |
|---|
| Domain | Status | DMARC | SPF | DKIM | Findings | Checked |
|---|
| Reporter | Domain | Policy | Window | Messages | Pass | Fail |
|---|
| Source IP | Pass | Fail | From domains | Last seen |
|---|
| Status | Host | Port | Days left | Expires | Issuer | Last check | |
|---|---|---|---|---|---|---|---|
Watch Certificate-Transparency logs (via crt.sh) for certificates issued for your domains — catches certs you didn't request (compromised DNS/ACME, rogue issuance, shadow IT). One domain per line, empty = off. The first check per domain baselines silently; new issuance afterwards raises a ct_new_certificate alert. Re-checked ~6h; a domain that keeps failing (crt.sh is slow) backs off for a day.
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).
| Device | Domain | Challenge | Provider | Created | Next renewal | Status | Actions |
|---|---|---|---|---|---|---|---|
| Loading… | |||||||
| # | Subject | Type | Priority | Status | SLA | Assignee | Device | Updated | |
|---|---|---|---|---|---|---|---|---|---|
| Loading… | |||||||||
| # | Subject | Type | Priority | Status | SLA | Assignee | Device | Updated | |
|---|---|---|---|---|---|---|---|---|---|
| Loading… | |||||||||
| # | Subject | Type | Priority | Status | SLA | Assignee | Device | Updated | |
|---|---|---|---|---|---|---|---|---|---|
| Set your team under Profile to use this view. | |||||||||
| # | Subject | Type | Priority | Status | SLA | Assignee | Device | Updated | |
|---|---|---|---|---|---|---|---|---|---|
| Loading… | |||||||||
| Name | Role | Company | Phone | Actions | |
|---|---|---|---|---|---|
| Loading… | |||||
| Severity | Time | Title | Device | Ack by | ||
|---|---|---|---|---|---|---|
| Loading… | ||||||
Resolution timeline (MTTR)
| Resolved | Severity | Title | Host | MTTR | How | By |
|---|
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. Documentation| Status | Requested | Action | Device | AI host | Prompt | |
|---|---|---|---|---|---|---|
| Loading… | ||||||
| Time | Actor | Action | Detail | Source IP |
|---|---|---|---|---|
| Name | Command | Description | |
|---|---|---|---|
| No snippets yet. | |||
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. Documentation| Name | Description | Size | Updated | Flags | |
|---|---|---|---|---|---|