FAQ
Common questions about how Astrari works, the scanners, site monitoring, alerts, and billing.
Astrari is a security monitoring platform for agencies managing Linux servers and websites. A lightweight agent installs on each server, runs security scans locally, and reports findings to a central dashboard. Any website can be added for external monitoring — no plugin or server access required. WordPress sites get additional deep scanning: CVE matching across 12,250+ known vulnerabilities, plugin/theme version detection, and agent-assisted auto-fixes.
Primarily web agencies and managed service providers who manage Linux servers and websites on behalf of clients. It's also used by businesses managing their own infrastructure who want ongoing security visibility without dedicated security staff.
No. The agent is fully outbound-only. It connects to api.astrari.io over HTTPS (port 443) to check in and post results. No inbound connections are ever made to the server.
Yes. Agent tokens are stored as SHA-256 hashes — the plain token is shown once at creation and never stored. All communication is over HTTPS. Scan findings are stored per-organisation with strict multi-tenancy isolation.
Any Linux distribution running systemd on x86_64 or arm64 hardware. The agent binary is statically compiled (no GLIBC dependency), so it works on RHEL 7, CentOS 7, Ubuntu 18.04, Debian 9, Rocky Linux, AlmaLinux, and anything newer. The installer supports both Debian/Ubuntu (apt) and RHEL/CentOS/Fedora (dnf/yum) package managers.
Possibly — and the installer now asks you before doing anything. When ClamAV and rkhunter are installed via apt or dnf, your package manager may upgrade other packages that are pulled in as transitive dependencies. The most common case is RHEL-family servers where installing ClamAV 1.4.x bumps the rest of the ClamAV stack and pulls in a newer OpenSSL build from your distro's current security stream. Before making any changes the install script prints exactly what would be installed and upgraded (using 'dnf install --assumeno' or 'apt-get install --simulate') and asks you to choose: (y) install everything shown, (s) skip OS scanners and install only the agent, or (n) abort and install nothing. For unattended installs append --yes to confirm automatically, or --no-tools to install the agent without any OS scanners. The installer never runs 'dnf upgrade' or 'apt-get upgrade' — it only installs the two packages we ask for. Any other version changes are dependency resolution by your package manager, and they're shown in the preview before you confirm. After OpenSSL upgrades you may need to restart services that hold libssl in memory (nginx, php-fpm, mysqld) — 'needs-restarting -r' on RHEL family or 'checkrestart' on Debian will tell you which.
Open the server's detail page and you'll see the affected scan button is greyed out, with an Install button next to it. Click it, confirm the warning, and the agent will pick the install up on its next 30-second checkin. Why isn't it auto-installed? In earlier agent versions we did try to install ClamAV and rkhunter automatically during the agent install. We stopped doing that after a customer noticed the package manager had transitively upgraded openssl/libssl on production servers as a side-effect (this is normal apt/dnf behaviour but caught them off guard). Now we only install on explicit confirmation per server. ClamAV: pulled from your distro's apt/dnf repos. May upgrade libssl and related transitive packages — restart nginx/php-fpm/mysqld afterwards if you rely on a specific OpenSSL version. rkhunter: pulled from apt/dnf repos. Small, few dependencies. MalDet (Linux Malware Detect): not in standard repos. The agent downloads the upstream tarball from rfxn.com, extracts it, and runs its install.sh. No package manager dependencies are touched. Once installed, the SRV_SCAN_ERROR finding auto-resolves on the next scan and the scan button becomes available.
Because those CVEs are compiled INTO specific binaries — Node.js, Python, Teleport, Plesk, esbuild, the Astrari agent itself, and similar. The vulnerable code is part of the binary, not a shared library that apt/dnf can swap out. A fix requires the binary's own vendor to ship a new release. These findings stay OPEN and visible because they are real CVEs that need addressing — just not via your package manager. To stop them from tanking the score on otherwise well-maintained servers, we apply a light flat -5 score penalty (instead of the full -30 a CRITICAL finding would normally cost). So a server with one lang-runtime CVE finding caps out at 95, not 70. The practical fix is usually: bump Node.js / Python / Plesk / Teleport / etc. to its latest stable release using its own update mechanism (nvm, pyenv, plesk_installer, teleport-update, etc.), then re-scan. Once the binary's runtime version moves past the CVE's fixed version, the finding resolves automatically.
Yes. The agent installs and runs normally on servers managed by Plesk, cPanel, or WHM. These control panels use Apache as the web server, which means .htaccess-based auto-fixes for WordPress sites work correctly on those servers. MalDet also scans cPanel and Plesk account directories automatically. The agent also detects which panel is installed and surfaces it on the server detail page and in the servers list — handy when you manage many servers and need to recall at a glance which run cPanel/WHM vs Plesk vs bare. Detection is based on the standard install paths (/usr/local/cpanel, /usr/local/psa) and the version is read from each panel's own version file.
A systemd timer fires every 30 seconds (with up to 20 seconds of randomised jitter to spread load across many servers). Each fire starts the agent as a oneshot service — it checks in with the API, processes any queued actions (forced scans, package updates, .htaccess fixes), and exits. Between runs it consumes no resources whatsoever. The frequent heartbeat means dashboard-triggered actions apply within seconds rather than minutes.
Yes. On every run the agent checks for a newer version. If one is available it downloads the new binary, verifies its SHA-256 hash and Ed25519 cryptographic signature against a key baked into the binary, then replaces itself atomically and re-executes — all within the same timer fire. No manual action is required. Updates are refused if the signature does not match, protecting against tampered binaries.
The agent handles outages gracefully. If the API is unreachable: check-ins fail silently, scans still run on their normal schedule, and results are cached locally in /var/lib/astrari/pending_results.json. When the server comes back the cached results are posted automatically on the next heartbeat. The agent will never repeat an expensive scan just because posting failed.
You can cancel a queued scan from the dashboard — this is effective if the agent hasn't started it yet. Since the agent checks in every 30 seconds, you typically have only a brief window to cancel. If a scan is already running on the server it must complete naturally. To force-stop a running scan: run 'systemctl stop astrari-agent.service' on the server. The scan will be cleanly terminated.
Lightweight runtime state captured by the agent on every 30-second checkin: 1-minute load average, percentage of root filesystem used, percentage of memory used (using MemAvailable, the same number 'free -m' shows under available). Values colour to amber when concerning (load > 2, disk > 80%, mem > 85%) and red when critical (load > 5, disk > 90%, mem > 95%). It's the at-a-glance pair to the server's security score — a server can have a perfect score and still be 95% disk-full, which is its own problem because logs stop writing and scanners can't run. We deliberately don't keep history or build trend graphs — that's monitoring-tool territory (Datadog, Grafana, etc.) and we're not trying to be that. The strip is point-in-time current state from the last checkin, refreshed every 30s. If you need historical trend data on a host, pair us with a real ops monitoring tool.
A summary of any actionable issues, condensed to a short list of pills. Each pill represents one signal — agent offline, malware detected, backup failed, EOL OS, scanner install failed, reboot required, vault verification failed, critical/high CVE counts, package updates available — colour-coded by urgency (red = blocking, amber = act soon, info = good to know). Clicking a pill jumps to the relevant tab on the page. When nothing's wrong you see one green pill: 'All checks healthy · last scan Xh ago'. We render the green pill rather than hiding the card entirely so an empty card never reads as 'still loading'. If more than 5 issues fire at once, the lowest-priority ones collapse into a '+ N more' link.
Trivy: CVE vulnerabilities in installed OS packages (matched against NVD/OSV). ClamAV: known malware and virus signatures across high-risk directories — auto-detected if already installed; not auto-installed by the agent installer to avoid touching your system packages. rkhunter: rootkits, backdoors, suspicious binaries, and modified system commands. MalDet: PHP shells, obfuscated backdoors, and web-specific malware in web directories (/var/www, public_html, etc.), including cPanel and Plesk accounts. SSL certs: expired or soon-to-expire TLS certificates detected via Let's Encrypt cert files and TLS probes on port 443/8443. SSH hardening: unsafe sshd_config settings (root login, password auth, empty passwords). Firewall: checks whether ufw or iptables rules are active. File integrity: compares current file hashes against a baseline taken on first run and reports any changes.
The agent fires every 30 seconds for fast heartbeats and queued action delivery, but scans are throttled separately so the server stays idle most of the time. A full scan (SSH config, SSL certs, firewall, package list, Trivy CVE) runs every 6 hours. ClamAV, rkhunter, and MalDet are heavier — they self-throttle and only run if more than 6 days have passed since their last run, and only as part of a full scan. Forced scans triggered from the dashboard bypass this throttle and start within seconds on the next agent fire.
No. All scan tools run under 'nice -n 19 ionice -c 3' — the lowest possible CPU and I/O scheduling priority. They only get resources when the server is otherwise idle. In practice, the scans are invisible to live workloads. The agent itself exits completely between runs, consuming zero resources.
Yes. The server detail page has individual scan buttons for Trivy, ClamAV, rkhunter, and MalDet. Clicking one queues a targeted scan — only that scanner runs on the next agent fire (within ~30 seconds), bypassing the weekly throttle. Use Trivy after applying package updates to confirm patches took effect. Use MalDet if you suspect a web directory compromise. Use rkhunter if you notice suspicious system behaviour.
Yes — for two common SSH hardening findings, Astrari can apply the fix automatically via the agent: • Disable root login — sets PermitRootLogin to 'no' in /etc/ssh/sshd_config and restarts the SSH service. The agent first checks that at least one non-root user with sudo or wheel group membership exists — if none is found, the fix is skipped to prevent lockout. • Disable password authentication — sets PasswordAuthentication to 'no' and restarts the SSH service. The agent first checks that at least one SSH authorized_keys file exists for any user — if none is found, the fix is skipped to prevent complete lockout. To apply: expand the relevant finding in the 'Access & SSH' section, then click 'Fix now'. A confirmation modal explains the change and requires you to confirm you have an alternative way into the server. The fix is queued in the dashboard and applied on the next agent check-in (within ~30 seconds). Your current SSH session is not affected — only new connections change behaviour.
Clicking Apply updates queues apt-get upgrade -y (Debian/Ubuntu) or dnf upgrade -y (RHEL/CentOS/Rocky) to run on the server at the next agent check-in — typically within 30 seconds. After the upgrade completes the agent automatically re-runs a Trivy CVE scan and any patched vulnerabilities are resolved in the dashboard automatically. For targeted control, each CVE finding that corresponds to an OS package has a checkbox. Tick the packages you want to update and click 'Update N packages' — this queues a selective upgrade of only those packages rather than a full system upgrade. Useful when you want to patch a critical CVE without rolling out all pending updates. Update lifecycle: once queued the finding badge changes to 'update queued' (green). When the agent picks up the update and starts applying it, the badge changes to 'verifying…' (amber). After the Trivy scan confirms the package was patched, the finding resolves automatically. Note: kernel package CVEs and CVEs in compiled binaries show a 'requires reboot' or 'requires rebuild' badge instead of a checkbox — these cannot be patched in-place by apt/dnf.
These panels manage their own pinned package set, so a blanket apt-get/yum upgrade can corrupt the panel — cPanel loses its accounts DB, Plesk's PSA disconnects from MariaDB, EasyApache's PHP/Apache combinations break. Astrari handles this automatically: Apply OS updates (warning-orange) — runs the OS package manager with panel-managed packages excluded: • cPanel: yum upgrade with --exclude=cpanel-*,ea-*,whm-*,MariaDB*,mysql-community-* • Plesk on Debian/Ubuntu: apt-mark hold plesk-*, psa-*, sw-*, mariadb-* → apt-get upgrade → apt-mark unhold • Plesk on RHEL/AlmaLinux/Rocky: yum upgrade with --exclude=plesk-*,psa-*,sw-*,MariaDB-*,mariadb-* Run cPanel update / Run Plesk update (brass) — invokes the panel's own auto-updater on the host: • cPanel/WHM: /scripts/upcp --force • Plesk: plesk installer update Both buttons appear on the server detail page only when the agent has detected the panel. Selective per-package updates are guarded too — the API rejects an attempt to update a panel-namespaced package and points you at the panel update action instead. After either path completes, Trivy auto-rescans on the next agent check-in and matched CVE findings resolve automatically.
Yes, for six common services where the standard fix is 'change the bind address back to localhost and restart'. When the agent's exposure scanner flags one of these as bound to a public interface, the finding gets a Fix now button: • MySQL/MariaDB → bind-address = 127.0.0.1 in my.cnf • PostgreSQL → listen_addresses = 'localhost' in postgresql.conf • Redis → bind 127.0.0.1 in redis.conf • Memcached → -l 127.0.0.1 in memcached.conf (or OPTIONS on RHEL) • MongoDB → bindIp: 127.0.0.1 in mongod.conf • Elasticsearch → network.host: 127.0.0.1 in elasticsearch.yml Before touching anything, the agent runs preflight checks specific to the service: • Active connections — refuses if any remote (non-loopback) clients are currently connected to the port. • MySQL panel checks — refuses if WHM's 'Allow remote MySQL connections' allowlist has entries, or if Plesk's Database Hosting feature is enabled. (These features intentionally expose MySQL; rebinding to localhost would break customer-database access.) • Container check — refuses inside Docker / containerd because container networking is too varied to reason about safely. If preflight passes, the agent backs up the existing config to <path>.astrari-bak.<unix-timestamp>, edits the bind setting in place, restarts the service via systemctl, and waits up to 30 seconds (60 for Elasticsearch) for the unit to report active. After restart it re-checks the listening ports — if the bind didn't actually move to localhost, the original config is restored automatically and the failure is surfaced as a finding with the diagnostic detail. The exposure scanner re-runs immediately after a successful fix so the finding auto-resolves. What the auto-fix doesn't do: open up legitimate remote access patterns. If you have applications that need to connect from another host, the right tool is firewall allowlisting at the network layer — not changing the bind address. Use the Network tab to manage UFW/iptables rules instead.
On CloudLinux servers running KernelCare, kernel CVEs are patched live in memory — uname -r doesn't change because the running kernel image stays the same, but the vulnerable code paths are replaced. Trivy can't tell the difference, so it keeps reporting kernel CVEs that are actually fixed. Astrari closes that gap by reading kcarectl on every agent check-in: • kcarectl --info reports auto-update status and the 'effective kernel version' (what you'd be running if patches were activated by reboot rather than live). • kcarectl --patch-info lists every CVE the loaded patch covers. Matching open Trivy kernel-CVE findings on that host get acknowledged with a note recording the effective kernel version, so you can see at a glance that the host is genuinely protected. The system info table shows the live-patch state — including a clear warning if auto-update is off, in which case CloudLinux advisories should not be considered automatically applied.
Each server detail page has a 'Scan history' section at the bottom. It shows a table of completed scans with the date, scan type, who triggered it, the security score after that scan, how many new findings were opened, and how many were resolved. A sparkline graph shows how the score has changed across the last 20 scans. The score after each scan is recorded at completion time — it reflects all open findings on the server at that point. Use this to confirm a score improved after applying updates, or to spot when a new vulnerability was introduced.
Each scanner has a specific scope. Trivy only checks installed OS packages — not files in your web directory. ClamAV detects known signatures — novel or obfuscated malware may not be in its database. MalDet is the most effective for web-specific threats like PHP shells. For a WordPress infection, run a MalDet scan and also check for recently modified PHP files manually: find /var/www -name '*.php' -mtime -30
Yes. Expand any finding on the server or site detail page to reveal suppress options: • Acknowledge — marks the finding as known and reviewed. It still counts towards the security score (you've accepted the risk) but is visually distinguished from unreviewed findings. • False positive — hides the finding from view and excludes it from the score entirely. Use this when a scanner reports something that doesn't apply to your environment (e.g. rkhunter flagging a legitimate custom binary). Both options accept a free-text note explaining the decision. If circumstances change, use Reopen to return the finding to Open status.
No. Suppression survives rescans. The agent uses a fingerprint hash to identify each unique finding — if the same issue is reported again the existing record is updated but its status (Acknowledged or False Positive) is preserved. Only a Reopen action will change it back to Open.
After each scan, findings that were not reported by the scanner are automatically resolved. This keeps the list accurate: if a package was patched by a system update outside of Astrari, its CVE finding will be resolved on the next scan without any manual action. Findings you've marked Acknowledged or False Positive are never auto-resolved — only Open ones.
The Global Findings page (linked from the sidebar) shows all open findings across every site and server in your organisation, in one list. You can filter by severity, type, and status. This is the fastest way to triage your most critical issues without clicking into individual assets.
Five distinct paths can auto-acknowledge a CVE finding, each with a different rationale stamped in the acknowledgement note: • Backport-patched — the agent ran an update, the package version didn't change, but the distro has backported the fix to the existing version. Common on Debian/Ubuntu and RHEL where security fixes are backported rather than version-bumped. • No upstream patch available — Trivy reports the CVE has no known fix anywhere. Auto-acked unless the OS is end-of-life (in which case it stays open with an OS-upgrade note, because 'no fix' on an EOL distro means upgrade, not 'live with it'). • Vendor advisory superseded — we'd previously emitted a manual finding from a CloudLinux/RHSA/USN/DSA/ALSA/CISA-KEV advisory; once Trivy itself starts reporting the same CVE, the manual one is redundant and we ack it in favour of the agent's organic detection. • Live-patched by KernelCare — only on CloudLinux hosts with kcarectl. The kernel CVE is loaded as a live-patch in memory, so the host is genuinely fixed even though Trivy still reports it (uname -r doesn't change). The note records the effective kernel version. • Reboot required (kernel) — not strictly an acknowledgement; the finding stays open but is annotated. Kernel updates land on disk but the running kernel doesn't change until reboot. We surface a server-wide reboot banner instead.
On CloudLinux servers, the agent reads kcarectl --info and kcarectl --patch-info on every check-in. Two things flow back into the dashboard: • Live-patched CVE list — every CVE the running kernel has loaded as a live-patch. Any matching open Trivy finding is acknowledged with a note recording the effective kernel version. • Auto-update state — the dashboard's system info table shows 'KernelCare auto-update on' (genuinely protected within hours of CloudLinux publishing a patch) or 'KernelCare auto-update off — run kcarectl --update' (the host has the kcarectl tool but isn't pulling patches automatically; suppression of CloudLinux advisories would be premature). This means Trivy can keep reporting kernel CVEs based on uname -r, but if KernelCare has the fix loaded the dashboard correctly shows 'live-patched on this kernel' rather than 'reboot required' — because no reboot is required.
Each server and site has its own alert configuration: enable alerts, pick a severity threshold (CRITICAL only, HIGH+, MEDIUM+, LOW+, or all), and select which contacts and channels should fire. When a new finding lands at or above that threshold, Astrari dispatches the alert to every recipient on the asset. Findings that already exist (just being re-seen by a scan) don't re-trigger — only newly opened or reopened findings do.
Out of the box: email (delivered via Resend), Slack (Incoming Webhooks), Microsoft Teams (Incoming Webhooks), PagerDuty (Events API v2), and a generic JSON webhook with optional HMAC-SHA256 signature for custom integrations. PagerDuty alerts include a stable dedup_key so re-fires for the same finding group into one ongoing incident rather than spamming pages.
Go to Alerts → Alert contacts → '+ Add contact'. Provide a name, email, and optionally a phone number. Admin users can scope the contact to a specific client (so it only appears on that client's assets) or leave it org-wide. After adding, click 'Test' to send a sample email to verify delivery.
Go to Alerts → Alert integrations → '+ Add integration'. Pick the type (Slack, Teams, PagerDuty, or generic webhook), give it a name (e.g. '#security-alerts'), and paste the webhook URL or PagerDuty routing key. Each integration has a 'Test' button that sends a sample alert so you can verify it before relying on it. Webhook URL hints: • Slack: workspace → Apps → Incoming Webhooks → Add to Slack → copy URL. • Teams: channel → ⋯ → Connectors → Incoming Webhook → Configure → copy URL. • PagerDuty: service → Integrations → add 'Events API v2' integration → copy routing key.
Open the server or site detail page and find the Alerts card. Toggle 'Enable alerts on this asset', set the severity threshold, then tick the contacts and channels you want to fire. Save. From this point on, any new finding meeting the threshold dispatches to those recipients. Multi-tenant note: contacts and integrations scoped to a specific client only appear in pickers for that client's assets. Org-wide contacts/integrations appear everywhere.
No. Each (finding, recipient) pair is dispatched at most once. Subsequent scans that re-see the same finding only bump its 'last seen' timestamp — they don't re-fire alerts. Reopening a previously resolved finding does re-fire (so you know it came back).
No — alert delivery is suppressed on the first-ever scan of an asset. The first scan establishes a baseline of what's currently on the box (which on most production servers includes a lot of pre-existing CVEs); those aren't 'new issues' from your perspective, they're the starting state. The first-scan welcome email summarises the count and severity breakdown, and you can browse all findings in the dashboard at any time. From the second scan onwards alerts fire normally — only for findings that genuinely represent a *change* in security posture (new CVE published, new service installed, drift, regression, etc.). This means you'll never get a 50-email blast of HIGH-severity package alerts the moment you install the agent on a busy production server.
Every dispatch — successful or failed — is recorded as an AlertEvent with the channel, status, recipient, finding, and any error message. Surfacing this as a UI is on the roadmap; for now you can query the database or contact support.
If the platform's RESEND_API_KEY isn't set, email contacts will record a failed AlertEvent with the reason 'Email not configured (RESEND_API_KEY unset)'. Slack/Teams/PagerDuty integrations are unaffected — they POST directly to their respective webhook endpoints.
The forensic diagnostic is an on-demand snapshot you can run on any server (or site linked to a server) when investigating downtime, slowness, or unusual behaviour. It collects: panel detection (Plesk / cPanel / bare), boot/uptime/load/memory, recent out-of-memory killer events, failed systemd units, disks at ≥85% utilisation, and the last 200 error/warn lines from nginx, Apache, PHP-FPM, MySQL/MariaDB and the system journal. The whole snapshot runs in 1–2 seconds on the server and produces a payload of around 50–100 KB. Use it when: a site is throwing 5xx errors, a service has gone down, a server reboot happened unexpectedly, or you simply want to see what the recent error logs say without SSHing in.
Server-wide: open the server detail page and click 'Run diagnostic' in the Forensic diagnostic card. The agent picks it up on its next 30-second check-in, runs the collector, and posts results back. The dashboard polls and auto-expands the latest result. Site-scoped: open the site detail page (the site must be linked to a server with the Astrari agent online). Click 'Run diagnostic' — the collector will narrow log collection to that domain by parsing nginx/Apache vhost configs (or Plesk/cPanel per-domain log paths) for domain-specific error_log entries. If no per-vhost log is configured the global log is used as a fallback.
The collector detects whether the server is running Plesk, cPanel/WHM, or is a bare system, then reads only the paths relevant to that layout: • Bare server — /var/log/nginx/error.log, /var/log/apache2/error.log (Debian) or /var/log/httpd/error_log (RHEL), /var/log/mysql/error.log or /var/log/mariadb/*, /var/log/php*-fpm.log. • Plesk — /var/www/vhosts/system/<domain>/logs/{error_log,proxy_error_log} for each vhost, plus /var/log/plesk-php*-fpm/error.log. • cPanel/WHM — /etc/apache2/logs/error_log, /usr/local/apache/logs/error_log, /opt/cpanel/ea-php*/root/usr/var/log/php-fpm/error.log, and /home/<user>/logs/<domain>.error.log when a site-scoped diagnostic runs. • Always included — journalctl -p err for the same time window.
Very light. Each log read seeks to the last 1 MB of the file (so it doesn't scan multi-GB files from the start), filters to error/warn-level lines only, and is bounded by both a per-source line cap (200) and a total payload cap (~256 KB). Files larger than 50 MB are skipped entirely. The whole run is sequential, mostly file reads, and finishes in 1–2 seconds. There is no continuous log shipping — the diagnostic only runs when you click the button.
By default the collector filters to lines from the last 30 minutes to keep the snapshot small and relevant to the issue you're investigating. The API accepts a wider lookback (up to 24 hours) — if you need a longer window we can expose this in the UI as a follow-up. Lines from older runs are still kept on disk on the server itself; the diagnostic just doesn't include them in the snapshot.
In your Astrari account, in a dedicated Diagnostic table. Each diagnostic includes the panel detected, the agent version that produced it, the requested-by user, the lookback window, and the full JSON payload. They appear in the Forensic diagnostic card on each server or site detail page, sorted newest first, and persist for the duration of your account.
Any website — not just WordPress. Simply add the domain and Astrari scans it externally with no plugin or server access required. Every site gets these checks: • SSL certificate — valid, days until expiry, alerts at 30 / 14 / 7 days. • Domain expiry — queries the RDAP registry to find when the domain itself expires. • Security headers — HSTS, X-Frame-Options, Content-Security-Policy, X-Content-Type-Options, Referrer-Policy. • Cookie security — HttpOnly, Secure, and SameSite flags. • Email security (SPF / DMARC) — checks DNS for SPF and DMARC records. • Blacklist check — Spamhaus DBL and SURBL. • SEO spam and cloaking — HTML scan for spam keywords, CSS-hidden links, and Googlebot content comparison (a difference indicates an SEO hack). • External scripts from suspicious IPs. WordPress sites additionally get: • Plugin, theme, and WordPress core version detection. • CVE matching against 12,250+ known vulnerabilities across 7,600+ components (Wordfence Intelligence). • Outdated plugin, theme, and WordPress core versions flagged with available fix versions. • Sensitive file exposure — wp-config.php, debug.log, xmlrpc.php, readme.txt, .env, .git/config, and more. • User enumeration detection (?author=N redirect probing). • Directory listing on /wp-content/. • Agent-assisted database scan and .htaccess auto-fixes (when linked to an Astrari-monitored server).
Partially. The scanner connects from a fixed IP address. If a WAF or CDN serves a challenge page to that IP, some checks may be inaccurate — for example, header findings reflect what the WAF returns, not the origin server, and WordPress detection may fail if the WAF blocks the probe. For the most accurate results, whitelist the Astrari scanner IP in your WAF settings. Contact support to get the current scanner IP address.
Domain expiry is looked up via RDAP (the registry's public API). Some registrars or TLDs don't publish expiry data through RDAP, or rate-limit the lookup. When data isn't available the tile shows 'no data' rather than guessing — check expiry directly with your registrar for those domains.
Yes, if the site is linked to a server that has the Astrari agent installed. On the site detail page, open the 'Hosting server' card and select the server that hosts the site. Once linked, any finding that involves a specific plugin will show a 'wp update' button. Clicking it queues a wp-cli update for that plugin on the linked server. The update runs on the next agent check-in (within ~30 seconds), and the finding automatically resolves after the next scan confirms the fix.
Yes — when a site is linked to an Astrari-monitored server, you can trigger a WordPress database scan from the site detail page. Click 'Scan database' in the Hosting server card (requires the agent to be online). The agent uses wp-cli to run SQL queries directly against the WordPress database. It checks: • wp_options — CSS-hidden injected links, external script and iframe injections. • wp_options — obfuscated PHP payloads (base64-decoded scripts, rot13, gzinflate patterns). • wp_posts — hidden spam links in published post content. Results appear as WP_DB_INJECTION findings on the site. wp-cli must be installed on the server — the agent will attempt to auto-install it if not found.
Yes — for several common WordPress hardening findings, Astrari can write a fix directly to the site's .htaccess file via the linked server agent. When a supported finding is expanded, an 'Apply fix via agent' button appears. Supported auto-fixes: • XML-RPC enabled — blocks access to xmlrpc.php. • User enumeration — blocks the ?author= query string. • Directory listing on /wp-content/ — adds Options -Indexes. • Missing X-Frame-Options — adds the header via mod_headers. • Missing X-Content-Type-Options — adds nosniff via mod_headers. • Missing Referrer-Policy — adds the header via mod_headers. • Missing Content-Security-Policy — adds a default-src CSP via mod_headers. All fixes are written with Astrari markers so they can be cleanly reverted. Once applied, a 'Revert fix' button replaces the apply button, and the site is automatically rescanned to confirm the finding resolves. Important: these fixes use Apache .htaccess directives. If the site is served by nginx (and does not use Apache), the dashboard will display the equivalent nginx server block directives instead, and the auto-fix button will not appear. Apply those directives manually in your nginx site configuration.
We check two DNS-based blacklists on every scan — no API key or registration required: • Spamhaus DBL (dbl.spamhaus.org) — tracks domains used for spam, phishing, and malware distribution. • SURBL (multi.surbl.org) — tracks domains appearing in spam and malware URLs. A blacklisted result is flagged CRITICAL — search engines and browsers warn visitors when a site is listed, so prompt action is essential.
No. External scanning runs without credentials. For deeper coverage — specifically to enumerate the complete list of installed plugins and themes rather than probing file paths — you can optionally add WordPress Application Password credentials per-site. These use the WP REST API and require a user with at least Editor role.
Vault is the optional backup add-on. The agent runs restic on each server you enable it for, encrypts the snapshot client-side, and pushes it to a Backblaze B2 bucket that Astrari provisions on your behalf. It's append-only by design: even if a server is compromised, the agent's key cannot delete prior snapshots, so ransomware can't wipe your backup history. Vault is currently files-only (Phase 1) — database dumps and in-place restores arrive in subsequent phases.
Pay-as-you-store: £0.05 per GB stored per month. No per-server fee, no minimum, no annual lock-in. Restores incur an egress fee of £0.02 per GB above 10 GB included free each month — so restoring a small site or single subpath is free, and restoring a 50 GB tree costs about £0.80. The dashboard shows a live monthly bill estimate based on your current bucket size; storage is metered after each successful snapshot.
Snapshots are pushed to a Backblaze B2 bucket Astrari provisions for you (region-selectable: EU Amsterdam, US-West, US-East — EU is the default). Restic encrypts the data on your server before it leaves the host using a recovery passphrase shown to you once at setup. We keep an encrypted escrow copy of that passphrase so we can help if you lose it, but we cannot read your data — only restic with your passphrase can decrypt the snapshots. The agent's B2 application key is append-only (write + list + read, no delete) for the same reason.
On the server's detail page, scroll to the Vault panel and click 'Install restic →' (the agent needs the restic binary; it asks for your consent before touching system packages). Once installed, click 'Enable backups →' — pick what to back up (e.g. /etc and /var/www), pick a retention preset (Tight/Balanced/Long), choose a region and daily backup time, and Astrari handles the rest: bucket creation, key provisioning, recovery passphrase generation. You'll see the passphrase once — save it.
Three presets: Tight (last 3 / daily 7 / weekly 4 / monthly 3 — minimises B2 cost), Balanced (last 7 / daily 14 / weekly 8 / monthly 12 — recommended default), and Long (last 14 / daily 30 / weekly 12 / monthly 36 — ~3 years of history, compliance-friendly). The prune cycle runs every Sunday at 04:00 UTC and enforces whichever policy is current; switching to a tighter policy lets the next prune reclaim B2 space, switching to a longer one applies immediately to new snapshots but won't recover already-pruned history.
Yes. Click 'Run backup now' on the Vault panel — the agent picks it up on its next 30-second checkin and runs the snapshot regardless of the schedule. The button is disabled while a backup is already in flight to prevent concurrent restic runs on the same target.
Click 'Restore from snapshot' on the Vault panel, pick a snapshot from the dropdown, and optionally type a single sub-path (like /var/www/example.com) to restore only that subtree. The agent pulls the data into /var/lib/astrari/restore/<jobId>/ on your server with the original directory structure preserved underneath. Nothing is overwritten — once it's down, you copy what you need wherever you need it (cp, rsync). In-place restore that overwrites originals is intentionally Phase 2b: it lives behind a 2FA gate because a careless restore can make a bad day worse.
Yes. The agent discovers MySQL/MariaDB and PostgreSQL databases on each fire and reports them to the dashboard. You opt-in per database — open Edit configuration on the Vault panel and tick the databases you want to back up. Selected databases are dumped via mariadb-dump (or pg_dump) on each backup fire and streamed straight to restic, so each database becomes its own snapshot tagged db:type:name. Discovery covers four sources: cPanel (whmapi1 + uapi per account), Plesk (plesk db), bare MySQL/MariaDB via root socket auth, and PostgreSQL via peer auth as the postgres user. Default is 'no databases selected' — opt-in by design so a multi-tenant cPanel box doesn't enrol 50 customer databases by accident.
On cPanel hosts, the dashboard groups databases by the owning cPanel account ('cPanel: clientuser ([email protected])'). On Plesk hosts, by subscription/domain. Each row shows the database name and engine. This way, when you have an agency-style cPanel box with 30 customer accounts, you can see at a glance which databases belong to whom and tick selectively — back up everything for premium clients, skip caches and dev sandboxes for others.
Open Restore from snapshot on the Vault panel — the snapshot dropdown groups by Files and per-database. Pick the snapshot for the database you want and Restore now. The agent pulls the dump into /var/lib/astrari/restore/<jobId>/db/<type>/<name>.sql.gz on your server (sandbox-only, like file restores). You then load it with mysql < name.sql or psql < name.sql against whichever database you want to restore into. Direct in-place database restore (point at a live database, agent re-imports for you) is Phase 3b — same reasoning as in-place file restore, behind a 2FA gate to prevent accidental wipes of production.
Consistent. mariadb-dump runs with --single-transaction --quick --routines --triggers --events: a single MVCC transaction snapshot of every InnoDB table, no write locks on the database, stored procedures and triggers preserved. pg_dump uses its own consistent-snapshot mode by default. The dump streams through gzip into restic's --stdin so we don't double the disk footprint while it runs.
Not yet — discovery currently relies on socket auth and panel APIs available to root on the host filesystem, which means Docker-isolated databases, AWS RDS, and other network-attached databases are invisible to the agent. We're planning a 'manual database connection' flow next — you'll add a connection in the dashboard (host, port, user, password) and the agent will dump it via TCP, working for any database the host can reach. Until that ships, your options are: back up the volume directory directly (works but risky on a live database — restic snapshots the raw files, which can corrupt under writes), or wait for the manual-connection feature.
Same nice -n 19 ionice -c 3 wrapper as file backups, plus mariadb-dump's --single-transaction means no write locks on InnoDB. PostgreSQL pg_dump is non-blocking by design. On well-tuned hardware a 1 GB database dumps in seconds; on contended boxes the scheduler de-prioritises it under live traffic. The dump is streamed to restic without touching disk, so there's no scratch-space cost beyond the database server's own buffer pool.
The agent picks it up automatically. Discovery runs on every 30-second checkin, so a new database created on the server will appear in the Edit configuration panel within ~30 seconds. The dashboard shows the discovered list with checkboxes — you tick the new database to enable it for backup. Existing selections are preserved; you don't have to re-pick everything every time something changes on the host.
The agent's B2 key is append-only — an attacker on the host cannot delete or modify prior snapshots, only add new ones. The full-permission pruner key that runs the weekly forget+prune is held only on Astrari's API infrastructure and never touches your server. Combined with restic's content-addressed encryption, this means a compromised host can't take your backups down with it. To recover, queue a restore against the most recent snapshot from before the compromise, copy what you need to a clean host, and rebuild.
Backups run under nice -n 19 ionice -c 3 — the lowest CPU and I/O priority Linux exposes. On idle hardware they're invisible; under heavy load the kernel scheduler will starve restic before touching real workloads. Restic also de-duplicates client-side, so a daily snapshot of a 50 GB tree typically only ships a few hundred MB after the first run.
Yes. The server's detail page shows a banner at the top while a vault op is in flight ('Backup running' / 'Restore running'), and the servers list shows a coloured pill alongside the scan-status pill. The Vault panel itself shows snapshot counts, last backup time, recovery score, and a 'Recent restores' feed below the action row. Both the banner and pills clear automatically within ~30s of the agent reporting completion.
Astrari Vault verifies your repo on two layers, both visible on the Vault panel. (1) Integrity check — runs every 7 days on every active target regardless of plan. The agent runs `restic check` against your B2 bucket, validating every snapshot's pack files and index are intact and decryptable. Every fourth run is a deep check that re-reads 5% of pack contents to catch bit-rot. (2) Restore test — runs at the cadence you choose: monthly on the free tier, weekly on paid plans, or off. The agent actually restores the latest snapshot to a sandbox path on the server (`/var/lib/astrari/attestation/<jobId>/`), validates a sample of files materialised correctly, then cleans up. This proves the whole restore pipeline works end-to-end — egress from B2, sandbox creation, file write, file read — not just that bits in B2 are valid. Both kinds also have on-demand 'Verify integrity' and 'Test restore' buttons that bypass cadence and always work regardless of plan. Failures route through your normal alert channels. The on-demand buttons are useful before scheduling risky work — pre-rebuild verification, pre-migration check, or just compliance evidence.
Skipped means the verification couldn't run — usually because preconditions aren't met: restic isn't installed, the agent's vault.env credentials are missing, or B2 returned an authentication error (typically a rotated key). It does NOT mean your backups are corrupt — it means we can't tell yet. Fix the precondition (install restic, re-provision credentials, or rotate the B2 key) and click 'Verify integrity' to retry. We deliberately distinguish 'skipped' from 'failed' so the dashboard never shows a false-positive 'passed' when verification couldn't actually run.
Astrari reads your Cloudflare zone state and surfaces it alongside the rest of your security posture. With a scoped read-only API token connected, we poll every 10 minutes and pull: • SSL/TLS mode (off / flexible / full / strict / origin-pull) — flexible and off are flagged as findings because they leave traffic unencrypted between Cloudflare and your origin. • Always Use HTTPS — flagged when off. • DNS records — we hash the canonical record set and fire a HIGH finding when it changes between polls (early detection of unauthorised DNS edits). • Edge certificate expiry — feeds the existing 'SSL certificate expiring' tile, with severity ramping from MEDIUM (60d) → HIGH (30d) → CRITICAL (7d). • Aggregate firewall event count — last 24h, available on all Cloudflare plans. • Per-event firewall detail (top attackers, rule, country, time, request URI) — Pro plan or higher only; Free plan zones gracefully degrade to the aggregate count. We never write back. Astrari is read-only by design — we don't push WAF rules, change DNS, or sit in your request path. Use the Cloudflare dashboard for management; Astrari just gives you one place to see what's happening across all your assets.
Go to Settings → Integrations → Connect a Cloudflare account. You'll need a scoped Cloudflare API token (not a Global API Key). Create one at dash.cloudflare.com → My Profile → API Tokens with these read-only permissions: • Account · Account Settings:Read — used to label the connection. • Zone · Zone:Read — list your zones. • Zone · Zone Settings:Read — SSL mode, Bot Fight, Always-HTTPS, Under-attack mode. • Zone · Zone WAF:Read — firewall events (Pro plan or higher). • Zone · DNS:Read — DNS record list, for change detection. • Zone · SSL and Certificates:Read — edge cert expiry. • Zone · Analytics:Read — aggregate threat counts (works on all plans). Important: pick the DNS:Read scope from under the Zone permission group. There's a separate top-level 'DNS' permission group used for the DNS Firewall product — that one won't grant the access we need. The connection form calls this trap out explicitly. Paste the token, optionally label the connection, click Connect. Astrari verifies the token against Cloudflare's API, lists your zones, and stores the token AES-256-GCM encrypted at rest. Only the last four characters are shown back in the UI.
Linking a zone is two steps. After connecting the token we list every zone in your Cloudflare account, but none are polled until you opt them in: 1. Click 'Manage zones' on the connection card. 2. Tick the Monitor box next to each zone you want polled. 3. Pick a Site from the dropdown to surface that zone's WAF data on the Site detail page. Linking a zone to a Site auto-enables monitoring (so you don't have to tick both). Use the 'Poll now' button at the top of the connection card to trigger an immediate fresh poll instead of waiting up to 10 minutes for the next cron tick — handy right after you change scopes or enable a zone. If the Manage Zones panel shows a 'Flexible SSL' or 'Always-HTTPS off' chip on a row, that's working as designed — those are findings, not errors.
Three consecutive Cloudflare API failures flips the connection status to 'error' and halts polling until either the next cron tick succeeds or you click 'Poll now'. The most common causes: • Token expired or revoked — rotate it in Cloudflare and reconnect. • Token scope removed — Cloudflare lets you edit a token's permissions; if you narrow them after connecting, polls fail. Check the connection card's last-error line for the missing scope name. • Cloudflare-side rate limit (1200 requests / 5 min) — extremely rare under normal use, but possible if you have hundreds of monitored zones. Contact support if you hit this. While a connection is in 'error' state we don't auto-resolve any existing Cloudflare findings — your last-known good state is preserved until polling is healthy again.
Two independent flags: • Monitored — the zone is included in the 10-minute poll cycle. Without this we don't fetch settings, DNS, or events for that zone. • Linked to a Site — the polled data is surfaced on a specific Site's detail page (Edge protection panel, the ☁ CF badge, attached findings). A monitored zone with no linked Site still produces findings, but they appear org-wide rather than tied to a specific Site. A linked-but-unmonitored zone shows nothing because we have no data for it. The 'auto-monitor on link' shortcut in the UI keeps the common case (link a zone → start polling it now) one click instead of two.
No. Removing a connection from Astrari deletes our local copy of the zone list, snapshot data, and any Cloudflare-derived findings. It does NOT touch anything inside Cloudflare itself, and it does NOT revoke the API token — for safety, you should revoke the token yourself in dash.cloudflare.com → API Tokens once the connection is gone from our side. Future tokens for the same zones will repopulate cleanly.
Yes. Go to Settings → Team members and click '+ Add member'. Enter their name, email address, and a temporary password they can change after logging in. You can assign them one of two roles: • Member — can view and manage sites and servers, run scans, and mark findings. • Admin — full access including settings, team management, and API key rotation. The account owner (ORG_OWNER) cannot be removed. You cannot remove yourself.
Go to Settings → Team members and click Remove next to the person you want to remove. This immediately revokes their access. The action cannot be undone — if you need to restore their access, re-invite them.
API keys let you integrate Astrari findings into your own tools or scripts. Generate a key in Settings → API keys. Each key has the prefix 'iw_live_' followed by a random string. The full key is shown only once at creation — copy it before closing the dialog. After that, only the first 12 characters (the prefix) are stored for identification. Keys can be revoked at any time from the API keys page. API keys are available on Professional and Agency plans.
We deliberately don't proxy SSH ourselves — Astrari is monitoring, not access management, and we never want shell on your customers' servers. But if your team already uses Teleport, Tailscale SSH, AWS SSM Session Manager, or any similar tool, you can wire it up so an "Open in…" button appears on each server's detail page. Go to Settings → Remote access link, paste a URL template that uses {hostname} as a placeholder, and pick a button label. We substitute the agent-reported hostname into the template and open the result in a new tab — your access tool handles authentication, MFA, and session recording. Examples: • Teleport: https://teleport.example.com/web/cluster/main/nodes?search={hostname} • Tailscale: https://login.tailscale.com/admin/machines?q={hostname} Leave the field empty to hide the button. The setting is per-organisation and only admins can change it.
Enable it from the Uptime card on any site's detail page. We probe the URL every 5 minutes via HTTPS GET (10-second timeout). Each probe records latency, HTTP status, and any error. Three consecutive failed probes open a HIGH `Site is unreachable` finding that fires through your normal alert channels (email, Slack, Teams, PagerDuty, generic webhook); two consecutive successful probes auto-resolve it. The Uptime card on the site detail page shows: current status pill, last-probe latency, 24-hour uptime percentage, the last failure timestamp + error reason, and a 24-hour hourly sparkline of success ratios. Historical data: raw probes are kept 7 days, then rolled up to 5-minute aggregates for 30 days, then to hourly aggregates indefinitely. If your homepage isn't a meaningful health check (e.g. a static landing page in front of a dynamic backend), you can change the probe path to point at /api/health or similar via the site's PATCH endpoint.
Yes — when a report includes only websites and no servers, the layout adapts. The cover swaps the generic asset/scan stats for `Sites monitored / Portfolio uptime % / Issues found / Issues fixed`. The executive-summary copy is rewritten to lead on monitoring outcomes (uptime probes, content-change fingerprinting, supply-chain detection, TLS audits, subdomain-takeover sweeps, email-security hygiene) rather than scan counts. And every site card carries a `Monitoring at a glance` strip showing six tiles — uptime %, defacement paths monitored, external-script count, discovered subdomains (with any flagged in danger tone), open email-security findings, open TLS findings — colour-coded by health. The rest of the card (findings opened / resolved / currently open) is unchanged. Server-only and mixed reports keep the original layout.
The original SITE_EMAIL_SEC checks just looked for record presence — "do you have an SPF record at all? Do you have DMARC?". That misses the most common real-world failure mode, which is having a record that doesn't actually do anything. We now parse the records and flag: • **SPF with a permissive `+all` or `?all` mechanism** — a record that effectively says "accept mail from anywhere claiming to be us". Same end result as no SPF for any sending source not listed before the all-mechanism. • **DMARC with `p=none`** — monitor-only policy. Reports come in but spoofs aren't blocked. Common because orgs ship `p=none` for the rua reporting and never tighten. • **DMARC with `pct=` < 100** — staged-rollout marker that's been forgotten, so only a fraction of forged mail gets the configured action. • **DMARC with no `rua=`** — no aggregate reporting destination, so you're flying blind on policy effectiveness. • **DNSSEC not enabled** — DNS records aren't cryptographically signed. We probe via Cloudflare's DoH AD bit, which validates the chain. Severity is LOW because most domains still don't run DNSSEC, but enabling it is one click on most modern DNS providers and free. These join the existing presence checks (no SPF / no DMARC at all) under the SITE_EMAIL_SEC category. Severity is LOW for the strength findings — these are hardening rather than active compromise — but they tell the customer how to move from "I have a record" to "my email is actually protected".
Subdomain takeover is when a DNS record on your domain (typically a CNAME) points at a third-party service that's been decommissioned, but the record is still in place. The classic example: `promo.example.com CNAME example-promo-2018.s3.amazonaws.com`. Marketing deletes the S3 bucket two years later, the DNS record stays. An attacker creates a new S3 bucket with that name (free, no auth needed) and now serves arbitrary content under `promo.example.com` — including phishing pages, cookie-scoped exfiltration of session data on the parent domain, OAuth callback hijacking, and a fresh Let's Encrypt cert that browsers fully trust. **How we detect it:** once a week per site, we enumerate your subdomains via Certificate Transparency logs (free, public, passive — no scraping or active recon). For each discovered subdomain we resolve the DNS chain. When a CNAME points at a known-vulnerable service (S3, GitHub Pages, Heroku, Azure, Shopify, Statuspage, Fastly, Webflow, Tumblr, Pantheon, Squarespace, Zendesk, and others), we fetch the URL and check the response body for the service's specific 'this resource doesn't exist' fingerprint (e.g. AWS's `<Code>NoSuchBucket</Code>`). Both the DNS-target match AND the response-fingerprint match are required before we fire a finding — keeps false positives near zero. **Remediation when flagged:** either delete the dangling DNS record (if you don't need the resource) or re-create the third-party resource using the original target name so you own it before someone else does. The Subdomain audit card on each site's Monitoring tab shows everything we found, with takeover-risk subdomains called out in danger tone at the top.
On every site scan we run a TLS audit beyond the basic cert-expiry check. It probes whether the server still accepts deprecated TLS 1.0 / 1.1 (HIGH finding if so — both deprecated by RFC 8996 in 2020, removed from all major browsers). It inspects the leaf certificate for self-signed status (CRITICAL), weak RSA keys below 2048 bits (HIGH), and deprecated signature algorithms like SHA-1 / MD5 (HIGH). It also checks HSTS posture: missing Strict-Transport-Security header (LOW), max-age below 6 months (LOW). **Cloudflare-fronted sites:** when we detect Cloudflare (via CF-Ray header or cert issuer), the audit measures CF's edge — not your origin. CF Universal SSL is generally well-configured (TLS 1.3, modern ciphers), so the audit passing on a CF site means edge is healthy. Origin posture is covered by the Cloudflare integration's Edge protection panel separately. The audit surfaces the CF detection as informational so you know what was tested. **Let's Encrypt:** 90-day cert validity is by design. We do NOT flag short remaining validity as a TLS finding — the existing SSL-expiry check (under 30 days) handles absolute renewal alerts, and short-by-design LE certs would otherwise generate false alarms on every healthy LE site every couple of months. The audit runs as part of the regular site scan (no separate cron), so findings appear in your normal Findings list under the **TLS** category.
Enable it from the Content monitoring card on any site's detail page. We fetch your configured paths every 6 hours (default just `/`, up to 5 paths per site), strip all script/style/meta blocks and known dynamic-noise patterns (CSRF tokens, nonces, cache-bust query strings, ISO timestamps), then SHA-256 the result. The first check captures the agreed-good baseline silently. From the second check onwards, any path whose hash drifts opens a HIGH `Page content changed: /path` finding (category SITE_INTEGRITY) that fires through your normal alert channels. The normalisation strips the dynamic noise that legitimately changes every page-load — so a different ad, a randomised CSRF token, or a CDN cache-buster won't fire. What it does catch: actual content swaps (defacement, malicious banner injection, unauthorised content edits, redirect-injection from a compromised plugin). False positives are still possible on highly-dynamic sites — that's why the Content monitoring card has a one-click `Re-capture baseline` button: when you legitimately change a page, click that and the new content becomes the agreed-good (any open findings auto-resolve). Use `Check now` to trigger an out-of-cycle check after suspicious activity without losing the existing baseline. The card surfaces every monitored path with its current state (matching, drift detected, or capturing) and the time it was last verified.
Every site scan extracts the full set of external `<script src>` URLs from the homepage along with their Subresource Integrity (SRI) hash if present. The first scan establishes a baseline; from the second scan onwards we fire findings on changes: • A new external script appearing → HIGH finding. This catches Magecart-style supply-chain compromises (attacker injects a tag manager or CDN reference that exfiltrates checkout data), unauthorised analytics injection, or legitimate-but-unannounced scope creep on the site. • SRI hash changing on an existing script → MEDIUM finding. Could be a planned third-party version bump or a sign that something changed without your knowledge. Same-domain scripts are excluded (they're a different risk class, covered by the WordPress + exposure scanners). The Third-party JavaScript card on the site detail page lists every external script we currently observe along with whether it has an SRI hash pinned — scripts loaded without SRI are highlighted because the browser will execute whatever the third-party origin returns, including a future malicious update.
Enable it from the Performance card on any site's detail page. Once a week (Mondays 06:00 UTC) we run a synthetic mobile audit through Google PageSpeed Insights and store four numbers: overall PSI score, Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS), and Interaction to Next Paint (INP). No script gets added to your site — the measurement runs in Google's lab against your public URL. There is also a `Check now` button for ad-hoc runs after a deploy. **It is deliberately not a performance dashboard.** We don't draw charts. We don't show percentiles. We don't pretend to be Datadog or New Relic — those are real-user-monitoring (RUM) tools that ingest every visitor's experience and grow expensively with your traffic. We do one thing: tell you when something measurably regressed. The thresholds are simple — score dropped 15+ points vs the previous successful run, or LCP grew over 50% AND is now above 2,500 ms. Either of those opens a SITE_PERFORMANCE finding. **The differentiation:** when we fire a regression alert, we surface what else changed at the same time on the same site — newly-added third-party scripts, TLS cert switched, redirect chains introduced. So you can tell whether the regression is your dev team's deploy or whether it lines up with something less benign (a hacked plugin pulling in tracker bloat, a CDN misroute). Performance becomes a security-and-integrity signal, not just a speed report. The weekly cadence is intentional — daily would burn API quota and produce more noise than signal at this resolution. If you need higher resolution after a specific deploy, the `Check now` button covers it.
Go to Settings → Two-factor authentication → click Enable. Astrari shows a QR code; scan it with any TOTP-compatible authenticator (Google Authenticator, 1Password, Authy, Microsoft Authenticator, etc.). Type the 6-digit code your app shows to confirm, and we'll show you 8 single-use backup codes — save these somewhere safe (password manager or printed and locked away). From this point on, every sign-in asks for both your password AND a 6-digit code from your authenticator. Active sessions stay logged in; you'll only be prompted at the next fresh sign-in. 2FA is per-user — each team member enables it on their own account. We don't currently force it organisation-wide, but get in touch if that's useful for your compliance posture.
Use one of your 8 backup codes at the verification prompt. Each code works once and consumes itself; the dashboard will warn you when you're running low. Once you're back in, go to Settings → Two-factor authentication and either disable 2FA (if you don't want it any more) or re-enable it on your new device. If you've lost your authenticator AND all backup codes, contact [email protected] from the email on the account. We'll verify your identity and reset the second factor manually — there's no way to recover it without that human-in-the-loop step (which is the whole point of having a second factor).
TOTP secrets are AES-256-GCM-encrypted at rest under a dedicated key-encryption-key (`MFA_KEK`) that's separate from the database, separate from the JWT signing key, and separate from any other credential we encrypt. Backup codes are hashed (SHA-256) — we can verify them at login but can't recover them, which is why we show them once and never again. The second factor isn't bypassed by the refresh-token flow either: each Session row carries an `mfaVerified` flag set when you completed the 2FA challenge, and we propagate that forward through token rotation. A stolen refresh token alone can't issue access tokens for an account where 2FA was active at login.
Yes — when we detect cPanel/WHM or Plesk on a server (via the agent's panel detector), the server detail page shows an 'Open WHM' or 'Open Plesk' button next to the remote-access link. It opens the panel's own login page in a new tab — you log in directly with your panel credentials. We don't store panel passwords or mint SSO URLs; this is a bookmark-style shortcut that saves you remembering the port (cPanel/WHM uses 2087, Plesk uses 8443). For WordPress sites, the site detail page has an 'Open wp-admin' button — same idea, opens {site-url}/wp-admin/ in a new tab. You log in with your normal WordPress credentials. If you want true single-sign-on (no second login prompt), that needs us to store credentials, which we've deliberately avoided for blast-radius reasons. Get in touch if it would be valuable for your workflow and we'll look at it as an opt-in integration.
Four plans, each with its own caps: • Starter — Free. 1 site, 1 server, 24h scan schedule, full scan suite, 7-day data retention. • Basic — £25 / €29 / $35 per month. 5 sites, 2 servers, 24h schedule, email alerts, 30-day retention, email support. • Professional — £65 / €75 / $89 per month. 25 sites, 5 servers, 12h schedule, alerts via email/Slack/Teams/PagerDuty/webhook, API keys, 90-day retention, priority email support. • Agency — £149 / €175 / $199 per month. 125 sites, 25 servers, 6h schedule, all integrations, client sub-accounts, per-client API keys, 1-year retention, priority support. All plans include: Linux server monitoring (Trivy, ClamAV, rkhunter, MalDet, SSH hardening, file integrity), site monitoring (SSL, headers, domain/SSL expiry, SPF/DMARC, blacklists, SEO spam), WordPress CVE matching, on-demand scans, forensic diagnostics, and agent auto-updates. Vault — the optional backup add-on — is billed separately on usage: £0.05 per GB stored per month, with a 10 GB/month free egress allowance for restores (£0.02/GB above that). No per-server fee.
Starter is permanently free — not a trial. 1 monitored site, 1 Linux server with the full scan suite, on-demand scans, forensic diagnostics, 7-day data retention. It's a real plan, not a gimped preview, and you can stay on it forever if it covers your needs.
Sign up for any paid plan and you get 14 days of full access — no credit card required. After 14 days, mutating actions (creating new scans, adding sites/servers, changing alerts) are paused until you choose a plan; existing data and dashboard browsing remain available so you can subscribe at any time. The countdown shows in a banner at the top of every dashboard page from day 7 onwards.
Your dashboard becomes read-only — you can still view all your sites, servers, findings, and scan history, but agent-triggered actions and configuration changes are blocked. Click any 'Choose a plan' button to go to billing and subscribe. Your data is preserved indefinitely; once you subscribe, full functionality returns immediately.
Yes — annual billing saves 20% compared to monthly. For example, Professional is £65/mo monthly or £624/yr annual (£52/mo equivalent). Switch interval at any time from the Stripe customer portal we link to from your billing page.
Yes — you pick your billing currency at checkout (GBP, EUR, or USD). Prices are set per currency rather than direct FX conversion, so what you see on the pricing page is what you pay. The currency is locked for that subscription; to switch currency, cancel and re-subscribe in the new one.
From your dashboard, go to Settings → Billing. Click 'Manage in Stripe' to change plan, change interval, update payment details, or cancel. Cancellation takes effect at the end of the current billing period. Annual plans are non-refundable after the 14-day trial but can be cancelled to prevent renewal.
Agency plan customers can create separate client sub-accounts. Each client account contains its own sites, servers, findings, and team members — isolated from other clients. Useful for agencies that manage infrastructure for multiple clients and want each client to have their own login (or stay fully managed without one).
Yes, but separately. Astrari is the monitoring product. Our parent company Incus Technologies (incustech.co.uk) handles the hands-on side: managed Linux server administration, WordPress and bespoke website development, hosting migrations, performance work, and remediation when something on your Astrari dashboard needs an actual human to fix it. Same UK team, separate engagement model. If you'd like a quote or to chat about taking server work off your hands, head to https://www.incustech.co.uk or email [email protected].
Click the 'Get help' button on any server or site detail page (also from the Support page in your dashboard). Fill in a short message describing what you need and submit — your message goes directly to our support team and a confirmation email is sent to you. To follow up just reply to that email; your reply lands in the same support queue. For urgent issues you can email [email protected] directly.
Interpreting scan findings, planning remediation, agent installation issues, integrating Astrari with Slack/Teams/PagerDuty, configuring alerts, decoding forensic diagnostics, and general security advice for your servers and sites. We won't perform invasive changes on your servers without your authorisation, and we won't access your servers unless you explicitly ask us to.
Within one business day for non-urgent questions. Urgent active-incident issues are best raised at [email protected] directly with 'URGENT' in the subject — these are triaged ahead of regular requests during UK business hours.
Yes. The first time a server or site completes a scan, Astrari emails the org owner a short summary: the security score, finding counts, what happens next, and a link to view findings. It's a one-off — subsequent scans don't send this email. If you want ongoing notifications, configure Alerts (Slack/Teams/PagerDuty/email/webhook).