Server, hosting and website monitoring, check by check
Four host types, each with its own checks: what we measure, how often, and why it matters. Plus what stays out of sight, said upfront.
Every check, by host type
VPS with agent
A server with root access, running the full agent. The agent pushes a signed report, every 5 minutes by default (anywhere from 1 to 60, your choice). We open no connections to the server, apart from site probes when the host address is a domain.
from the report
- CPU, as load per core (every 5 min): Load normalized per core, not true utilization: that is what a shell script can compute cheaply. It can exceed 100% when a run queue forms.
- Memory and disk space (every 5 min): A warning from 85% memory and 80% disk, not at 100%: the point of the number is to give you days in which to clear logs calmly, not a reboot at three in the morning.
- Load average and uptime (every 5 min): A reboot you did not know about shows up as uptime reset between two reports, even when nothing else changed.
what the agent watches
- SSH logins, accepted and failed (every 5 min): Source, user and method. The signal that matters is not the wave of failures but one success with a key we do not know.
- Firewall blocks and fail2ban (every 5 min): We count from the rule counters, not from the log: firewalld ships with logging off, so on most RHEL servers the log is empty while the counters climb. The log is used only to say who was blocked.
- Firewall rules, as a baseline (every 5 min): We read the ruleset straight from nftables, firewalld, ufw or iptables and diff it against the previous one. A deleted rule is the half that matters: that is how a door opens. And if we find no firewall with rules at all, we say so - a server without one produces no blocks, so under the old probe it looked exactly like a well-defended server.
- Suspicious processes, by behavior (every 5 min): Not signatures: a process with no binary on disk, a masked name, an abnormal parent. That is how the miner posing as a system process was caught.
- Connections to mining ports (every 5 min): Known destinations and pools, plus the steady traffic pattern that accompanies them even when the port is changed.
- New listening ports (every 5 min): A diff against the previous state, with the process that owns them. A port that appears without you installing anything is the question of the day.
- New executables in volatile directories (every 5 min): /tmp, /var/tmp and /dev/shm, with a fingerprint and the moment of appearance. That is where almost every payload lands first.
- Cron jobs added or removed (every 5 min): Per user, with the whole command. Persistence is set up through cron more often than through anything else.
- SSH keys and sudo, opens a critical incident (every 5 min): A key appearing in authorized_keys or a new sudo rule opens an incident at once, with no threshold and no waiting.
- Backdoor patterns in the webroot (every 5 min): Webshells, obfuscated eval, uploaders. It looks at new and changed files, not at the whole tree every time.
system health
- Disk and inodes, on every filesystem (every 5 min): Not only /: a full /var stops the database and the logs while / still looks fine. Warning from 90%, critical from 97%.
- Failed systemd units (every 5 min): Every service systemd has marked as failed, by name. A certbot that died at three in the morning shows up here before the certificate expires.
- Processes killed by the kernel for lack of memory (every 5 min): What the OOM killer stopped since the last report. A database killed overnight leaves only this trace.
- Pending updates and required reboot (every 6 h): How many updates are available and how many are security fixes, simulated from the package lists already on the server: the agent installs nothing. A reboot pending for over 7 days becomes a warning.
- SSH password logins (every 6 h): From the effective sshd configuration, not the file. Root with a password is a warning; passwords for other accounts are noted.
- Operating system out of support (every 5 min): A release out of support no longer receives security updates, however often you upgrade. We warn 90 days ahead.
from outside, if the address is a domain
- HTTP availability (every 5 min): The site this server serves, seen as a visitor sees it. A failure is confirmed by a second probe before alerting.
- DNS records (every hour): A, NS and MX against the baseline, from public resolvers.
- TLS certificate and blocklists (every 6 h): The certificate actually served and whether the IP is on the lists that affect mail.
- Domain registration expiry (every 12 h): Through RDAP, with whois as a fallback. For .ro the registry publishes no date, so we watch the domain status.
remediation, only with your approval
- Block an address in the firewall (on request): The rule expires by itself after 24 hours, on every backend: if the dashboard dies, your server unblocks without us. The agent refuses the server’s own address, the gateway, the DNS resolvers, your SSH session address and the dashboard’s address - blocking any of them would sever the very channel that could undo it.
- Stop a process (on request): Before sending the signal the agent re-checks that the pid still belongs to the same program - name, executable and the kernel’s generation counter. A pid recycled between proposal and approval is refused, not killed. systemd, sshd and the rest of what keeps the server administrable are never touched.
- Move a file to quarantine (on request): It is moved, never deleted or rewritten: the file stays as evidence and goes back with one click. Only from volatile directories, never through a symlink, and only if the fingerprint still matches the one at the moment of the decision.
from our side
- Agent silence opens a critical incident (always on): If the report does not arrive we treat the absence as a signal, not as quiet. Either the server is off or the agent was stopped, and the second is what a successful compromise looks like.
- A wrongly signed command is a critical incident (always on): Every command is signed with your server’s secret, over a random number the agent generated seconds earlier - so a recorded reply cannot be replayed later, by anyone. If the signature does not verify, the agent refuses and reports it: someone is trying to command the server.
What it cannot see: How the site looks from outside, when the host address is just an IP. With a domain as the address, the outside checks above start on their own; headers, page content and exposed ports stay with an externally probed host.
Shared hosting
An account with no root. The agent runs inside the account while the site is probed from outside in parallel. Two angles, because neither one is enough alone.
from inside the account
- sha256 fingerprints of the webroot files (every 5 min): We compare fingerprint against fingerprint, not the modified date, which can be forged. Only files whose size, date or inode changed are re-read - on a site nobody touched, a run reads no files at all. Up to 40,000 files per account; past that cap the dashboard says plainly that the inventory is truncated. Besides PHP, HTML and JS, it watches .htaccess, .user.ini, php.ini and the rarer extensions (.php7, .pht, .phar, .shtml) that backdoors rely on.
- Injection patterns inside the files (every 5 min): Until now the patterns were only searched in the access logs: you saw who requested ?cmd=, not what was written into index.php - so a backdoor injected into a site with no traffic was invisible. Now the content is read too, but only for files that are being re-read anyway, so the cost is near zero. The content never leaves the server: you get the signature family and the line number.
- The account access logs (every 5 min): Brute-force patterns, path scanning and POST requests to the root, read from the account domlogs.
- The account crontab (every 5 min): Any job added or removed, with the whole command. It is the only form of persistence an account without root can use.
- One-click cleanup, with your approval (on request): You tick the infected files and quarantine them in one click - which proposes the batch, it does not run it: every move is approved in the dashboard, with all paths visible. Files move outside the webroot, so they are no longer reachable from the web, but they stay as evidence and go back with one click too. We never rewrite a file’s contents. wp-config.php and .htaccess are refused: if one of them is infected, the fix is to edit it, not remove it - otherwise an infection becomes a total outage.
from outside
- HTTP availability (every 5 min): Code, response time and redirects, from a server unrelated to yours. An apex pointing at another domain stays a warning, not green. A failure is confirmed by a second probe before alerting.
- DNS records and delegation (every hour): A, NS and MX against the baseline. We query public resolvers, not the server’s own, so a local outage cannot read as a vanished domain.
- TLS certificate (every 6 h): Issuer, chain and days left. Warning at 21 days, critical at 7, so the renewal does not land on a weekend.
- Security headers (every 6 h): HSTS, CSP, X-Frame-Options, Referrer-Policy. Measured on the final page, not on the redirect, or the verdict is about something else.
- Blocklists (every 6 h): Three lists that genuinely affect mail delivery. A query the list refuses is “unknown”, not “clean”.
- Third-party scripts and cookies (every 6 h): What loads from outside and what is written without protection. A new script nobody on the team added is the first sign the page was compromised.
- SPF, DMARC, DKIM, CAA, DNSSEC (every 12 h): Syntax, duplicates and over-permissive policies, including the case of two SPF records where the standard allows exactly one.
- Exposed sensitive files (every 12 h): .git, .env, backups and dumps. A control probe with a random name first establishes what “not found” looks like, so a site that redirects everything does not read as full of exposed files.
- TLS quality: protocols and ciphers (every 12 h): Outdated versions still accepted and weak ciphers, tested with a real handshake rather than inferred from a banner.
- Domain registration expiry (every 12 h): Through RDAP, with whois as a fallback. Warning at 30 days, critical at 7. For .ro the registry publishes no date, so we watch the domain status: on hold or expired is critical.
What it cannot see: Processes, ports, CPU and memory. They belong to the server, not to the account, and reporting them as yours would be disinformation, not data. No port scan either: every account leaves through the same server.
Probed from outside
Nothing gets installed. The site is probed from outside the network, like any visitor would, from a server unrelated to yours.
availability
- HTTP code and response time (every 2 min): Thresholds on response time, not just on the code: a site that answers in five seconds is down for the visitor, even when it returns 200. A failure is confirmed by a second probe 15 seconds later, before alerting. Optionally, the page must contain a text you choose: that also catches a suspended-account page or a defaced site, which still answer 200.
- DNS records, alerting on change (every 15 min): A change of A or NS is critical and points you at the registrar: that is what a domain hijack looks like before anyone notices.
certificate and content
- TLS certificate, days left (every hour): Issuer, full chain and name match, wildcards included. A change of certificate authority is reported separately.
- Security headers (every hour): What is missing and what is set too permissively. The incident reopens when the list changes, so a partial fix cannot pass as a resolution.
- Third-party scripts, cookies, structural drift (every hour): External origins the page loads, unprotected cookies, and structural changes against the last read.
posture
- Blocklists for your addresses (every 6 h): Listing and reason, on the lists that matter for mail and web. We check up to four addresses of the domain.
- SPF, DMARC, DKIM, CAA, DNSSEC (every 6 h): Syntax, duplicates and over-permissive policies. Without DMARC, anyone can send mail in your domain’s name.
- Exposed sensitive files: .git, .env, backups (every 12 h): Paths checked directly, as from the internet, with a control against sites that return the home page for any missing path.
- TLS quality: protocols, ciphers, keys (every 12 h): A real handshake per protocol version. TLS 1.0 and 1.1 still accepted are a warning, not a footnote.
- Ports exposed to the internet (every 12 h): What answers publicly on the domain’s address. A database reachable from the internet is critical at once; CDN ranges are skipped, because they are not yours.
- Domain registration expiry (every 12 h): Through RDAP, with whois as a fallback. Warning at 30 days, critical at 7. For .ro the registry publishes no date, so we watch the domain status: on hold or expired is critical.
What it cannot see: Nothing from the inside: no processes, no files, no logs. In exchange it is the only angle that sees exactly what your customer sees.
cPanel reseller
Not a server, an index. We query WHM with the credentials you save in the dashboard and add one host per account we find, including the ones that appeared without you knowing.
the server
- cPanel version and load average (every 10 min): A version left behind and sustained load, as a signal of noisy neighbors on the server you resell.
- API tokens and the 2FA policy (every 6 h): A new API token is critical: it is the key with which someone can do from outside everything you do from WHM.
the accounts
- Accounts added, removed or suspended (every 30 min): A diff against the previous inventory. You cannot protect what you do not know exists, and an account that appeared without you knowing is exactly that. A deleted or suspended account pauses its site probes, and they start again when it is reactivated.
- Enrolling the agent on new accounts (every 30 min): You can install the agent on every unenrolled account with one command, or let new accounts enroll themselves as they appear. The window between an account being created and a human first looking at it is exactly when it is most vulnerable: fresh WordPress, default passwords, nobody watching. Accounts already reporting are skipped rather than reinstalled - installing rotates the key, and rotating over a working agent would kill it.
- Disk and inode quotas, per account (every 30 min): Quotas come from WHM as suffixed text, “698M” or “1.2G”. We convert them explicitly, because naive parsing reports a full account at 0.13% usage.
- Shell, plan, IP and mail hold (every 30 min): cPanel sets the hold flag itself when an account exceeds its mail rate. It is the verdict of the server that sees the send queue: there is no more direct signal of a compromised WordPress.
the domains
- Expired domain or withdrawn delegation (every hour): The account stays on the server, with files and mail, but the domain no longer resolves anywhere. From WHM it is invisible: the listing shows it as healthy as any other.
- Domain answering from another server (every hour): The delegation moved, but the account is still yours. You can mark it “not mine anymore”: the probes stop, the account stays monitored, because it still takes up space.
What it cannot see: What happens inside the accounts. For that you install the agent in the account itself, and the account becomes a shared hosting host.