# How to Scan a Server for Malware Without Slowing Down Your Sites

> Why malware scans make hosting servers slow, how to measure the real cause, what nice, ionice and CPU quotas actually do, and measured numbers from a scanner built around a hard CPU limit.

Source: https://www.pyxsoft.com/blog/scan-server-malware-without-slowing-sites
Published: 2026-10-30
Tags: malware, cpanel, performance, linux, security

---

![A plane of light scans a row of servers without slowing their sites and marks one infected file](https://www.pyxsoft.com/_astro/cover.CHK9E5YB.jpg)

Every hosting operator knows this ticket: *"My site was slow last night."* You check the graphs, and there's the nightly malware scan, sitting right on top of the slowdown. The tempting fix is to scan less often, or to turn the scanner off. Either way, you've traded a slow night for a longer window in which an infection can go unnoticed.

There's a better option. Most of the damage comes from a few specific causes, and each one has its own fix.

<!--truncate-->

## What actually slows the server down

A scanner reads every file and analyzes its content. That creates pressure in three places:

- **CPU:** a scanner running one thread per core competes with PHP and MySQL for every one of them. Visitors feel this as slower page generation.
- **Disk:** reading millions of small files means a lot of seeks and a busy queue. On shared storage or slower disks, this is often worse than the CPU load, and it's easy to miss because `top` shows the CPU as idle while everything waits.
- **Page cache:** the kernel keeps recently read files in memory. A full scan reads a lot of files that nobody has asked for, which can push out the ones your sites actually use. The slowdown can then outlast the scan, until the cache warms up again.

Which one hurts depends on the server, so measure before changing anything.

## Measure it first

Run these while a scan is active, and compare with a quiet period. `pidstat` and `iostat` come from the `sysstat` package.

```bash
# Is the CPU busy, or is it waiting on disk? Watch the "wa" column.
vmstat 5

# How busy are the disks? Watch %util and the await columns.
iostat -x 5

# What is the scanner itself using? CPU, memory and disk, every 5 seconds.
pidstat -u -r -d -p SCANNER_PID 5
```

Then measure what visitors feel. Take a real page on the server and time it during a quiet period and during a scan:

```bash
curl -o /dev/null -s -w '%{time_starttransfer}\n' https://example.com/
```

How to read the results:

| What you see | The problem is probably | Start with |
|---|---|---|
| High CPU use, low `wa` | CPU contention | A hard CPU limit |
| High `wa`, disks near 100% | Disk I/O | I/O priority, fewer files scanned |
| Page times stay high after the scan ends | Page cache eviction | Fewer files scanned |
| Page times don't change | Nothing | Leave it alone |

A high load average on its own proves little, because on Linux it also counts tasks waiting on disk.

## What each setting really does

These work with any scanner. They are often mixed up, and the difference matters.

**`nice` sets priority, not a limit.** A process with `nice -n 19` gives way when something else needs the CPU, but it will happily use every core on an idle machine. That protects your sites reasonably well, yet the graphs still show 100%, and a customer on a VPS or a metered plan may still object.

**`ionice` sets disk priority, and it depends on the kernel's I/O scheduler.** Check which one is active. The one in brackets is in use:

```bash
cat /sys/block/sda/queue/scheduler
```

The priority classes are honored by schedulers like `bfq`. With `mq-deadline` or `none`, which are common on virtual machines and NVMe, they may do little or nothing, so measure again instead of assuming it worked.

**A CPU quota is a hard limit.** With systemd, the kernel enforces it through cgroups, whatever the process wants:

```bash
systemd-run --scope -p CPUQuota=50% nice -n 19 ionice -c 2 -n 7 YOUR_SCANNER /home
```

Here, 50% means half of one core, and `ionice -c 2 -n 7` is the lowest normal disk priority. The `idle` class (`-c 3`) looks tempting, but under `bfq` it only gets disk time when nothing else wants it, which can stall a scan on a busy server. The scan takes longer, but the ceiling is real. Set the limit too low on a server with many accounts, though, and a nightly scan may still be running the next morning.

## Scan fewer files

The cheapest read is the one you don't do.

**Exclude with care.** Mail stores and rotated logs are usually reasonable to skip if your scanner only targets web content. Don't exclude `wp-content/uploads` or cache folders because they are large. Those are favorite hiding places for malware.

**Stagger schedules.** If 50 servers sit on the same storage or hypervisor, don't start them all at 03:00.

**Scan by change.** A full daily scan mostly re-reads files that haven't changed since yesterday. Between full scans, you can target recent changes:

```bash
find /home/*/public_html -type f -name '*.php' -ctime -1
```

This is a good incremental pass, but keep running full scans too. New signatures can catch a file that was already there and that nothing has touched.

## How we built this into our scanner

Customers told us our own server-wide scan was showing 100–400% in `top`. They were right to complain, so we rebuilt how [Pyxsoft Anti Malware](https://www.pyxsoft.com/anti-malware) uses the machine. Here's what it does now.

**A CPU limit that counts the whole process.** Before each unit of work, the scan workers check the CPU time the entire process has actually used, as reported by the kernel, and pause if it is over budget. Since it counts the whole process, indirect work like garbage collection is included too, which is why the number matches what you see in `top`.

**Low priority by default.** The service runs with `Nice=10` and a low I/O priority, on top of the limit, so it gives way to your sites.

**No repeated work.** A file that hasn't changed since it was last checked isn't analyzed again, and a file that changes is.

## The numbers

Measured on a modest server with other services running: 2 vCPU Xeon, 3.5 GB RAM, a virtual disk and production signatures. "Cold" means the first scan, with none of the files in the system's page cache. "Warm" means a second scan with nothing changed. Each value is the median of three runs.

| Site | Files | Cold | Warm |
|---|---:|---:|---:|
| WordPress with 7 plugins (231 MB) | 9,229 | **12 s** | **0.5 s** |
| WordPress with 15 popular plugins and a theme (596 MB) | 30,466 | **32 s** | **0.9 s** |

And here's what the CPU limit costs in scan time, cold:

| CPU limit | 9,229 files | 30,466 files | Average CPU observed |
|---|---:|---:|---:|
| No limit | 6 s | 16.7 s | 150% (2 threads) |
| 100% (default) | 12 s | 32 s | 80% |
| 50% | 20 s | 52 s | 50% |
| 25% | 44 s | 120 s | 25% |

Memory during a scan was 150–200 MB cold with the default limit, and 90–115 MB warm. At rest, the service used 75 MB and averaged 0.3% CPU.

### What these numbers don't promise

- **They are from one server and two sites.** Yours will differ, especially on disk speed.
- **They measure the scanning library with the product's settings,** not the entire service. Reports and emails add some work.
- **Half a second applies to files already checked with the same signatures.** After a signature update, files are checked against the new part only, so that scan takes longer.
- **A second account with the same WordPress saves little.** In our test, it went from 4.4 s to 2.8 s.
- **This isn't a comparison.** We haven't tested other products on this hardware.

## Check it yourself

You don't need to take our numbers on trust. Install it on a test server, start a server-wide scan and watch it:

```bash
curl -s https://www.pyxsoft.com/install-anti-malware | bash
top -p "$(pidof pyxsoft)"
```

Change the CPU limit in the settings in WHM, and the number in `top` should follow. Run the `curl` timing from above while it scans, too. That's the number your customers notice.

It is licensed per server, whatever the number of accounts, and you can try it free for 7 days without a credit card.

If a scan does turn something up, our [cleanup guide for cPanel servers](https://www.pyxsoft.com/blog/find-clean-malware-cpanel-server) covers what to do next.
