geneav
All posts
Economics· 6 min read

What it actually costs to self-host ClamAV

ClamAV is free software, which is why the cost question usually stops there. But nobody deploys an antivirus engine — they deploy a scanning service, and the difference between those two things is where the money goes. Here is the whole model, with every assumption stated, so you can substitute your own numbers.

We run ClamAV in production. The infrastructure figures below are our actual bill, not an estimate, which is the only part of this we can be precise about. The engineering figures are explicitly a model, and they are labelled as such every time they appear.

What “self-hosting ClamAV” actually means

ClamAV gives you clamd, a long-running daemon that listens on a socket and speaks a binary protocol. It is not an HTTP API. To scan a file you open a TCP connection, send the literal bytes zINSTREAM\0, then a sequence of length-prefixed chunks, then a zero-length chunk to terminate, and read back a line of text:

the actual clamd wire protocol
> zINSTREAM\0
> \x00\x00\x08\x00   (chunk length, 4-byte big-endian)
> ...2048 bytes of file...
> \x00\x00\x00\x00   (zero-length chunk = end of stream)
< stream: Eicar-Test-Signature FOUND

That is the entire interface. There is no authentication, no rate limiting, no request logging, no metering, no TLS, and no notion of a user. Everything you would need to put this in front of an application, you write.

Line one: infrastructure

This is the line everyone estimates, and it is the smallest of the three. Ours, on Azure in East US, at list price:

Line itemSpecMonthly
Virtual machineStandard_B2ms — 2 vCPU / 8 GiB, Linux, pay-as-you-go at $0.0832/hr$60.74
Static public IPStandard SKU, $0.005/hr$3.65
OS disk30 GB provisioned, Premium SSD~$5.00
EgressScanning is inbound; the response is a few hundred bytes of JSON$0.00
TotalOne box, running 24/7~$70

The disk figure is approximate — Azure renders managed-disk prices dynamically and you should confirm it in the calculator. It is under 10% of the line and changes no conclusion.

Why 8 GiB and not 2

The instinct is to run this on the smallest box available. You cannot. clamd loads the entire signature database into memory and keeps it resident. On our production instance that is 974 MB resident, peaking at 987 MB — call it a gigabyte, measured rather than estimated. That is not a cache you can trim; it is how the daemon works.

A 1 GB instance is therefore out, and a 2 GiB one leaves very little for an operating system, your application and a database. Our whole stack — scanner, API, web frontend, Postgres, reverse proxy — sits at about 2 GB of the 8 GiB box it runs on, so 4 GiB is a realistic floor if you are running more than the scanner.

Worse, steady state is not the peak. When freshclam pulls new signatures, clamd can load the new database while the old one is still resident — transiently doubling its memory. If you have not set ConcurrentDatabaseReload no, a routine signature update is capable of OOM-killing your scanner in the middle of the working day. This is the single most common way a self-hosted ClamAV falls over, and it is invisible until it happens.

Line two: the integration build

This is the real number, and it is the one that never appears in a comparison table because it is paid once, in salary, before anything works. Between a socket that speaks INSTREAM and something an application team can call, you are writing:

LayerWhat raw ClamAV gives you
HTTP interfaceNothing. You write the multipart handling, streaming, and the response contract.
AuthenticationNothing. No users, no keys, no sessions.
API keysNothing. Issuing, hashing at rest, rotation, revocation.
Quotas and meteringNothing. No counters, no periods, no enforcement.
Rate limitingNone whatsoever — see below.
TLSNothing. Certificate issuance and renewal are yours.
DeploymentNothing. CI/CD, rollback, signature-volume persistence.
GPL positionYour counsel’s problem, before you ship commercially.

Call it two to four weeks of a senior engineer to build this properly, including the tests and the runbook. At a fully-loaded rate of $75–$150/hour, that is $6,000–$24,000, once.

The rate limiting deserves its own paragraph

ClamAV has no request throttling of any kind. None. If you expose clamd to application traffic without putting a governor in front of it, a single client — malicious, or just a retry loop with no backoff — can saturate the daemon and exhaust the box. Every other scan on that host queues behind it.

The fix is not one thing, it is three: a per-IP limit at the proxy, a per-account limit in the application, and a global cap on concurrent scans to protect the memory footprint. Ours is set to four concurrent scans. That number is not from documentation; it is from finding out.

Line three: keeping it running

Once it is built it does not stop costing. Signature updates need watching, memory needs tuning, certificates renew, the base image needs patching, and the daemon occasionally needs restarting for reasons you will investigate at the time.

In our experience this is two to four hours a month once things are stable, which at the same rate is $150–$600/month. It is lumpy rather than steady — several quiet months, then an afternoon gone to a reload that OOM-killed the daemon.

Adding it up

BasisInfrastructureEngineeringTotal
Per month, ongoing~$70$150–$600 of operations time$220–$670
Year one, including the build~$840$6,000–$24,000 once, plus $1,800–$7,200 of operations$8,640–$32,040

The headline is that infrastructure is almost never the expensive part. At the low end it is under a third of the monthly cost and under a tenth of year one. If you budgeted for a $70 VM and called that the cost of self-hosting, you were off by 3–10x comparing month to month, or 10–38x across year one. Both are true; they measure different things. Divide a year-one total by a monthly bill and you can manufacture a much larger number, which is exactly why you should distrust one when you see it.

When self-hosting is the right answer anyway

Cost is one input and frequently not the deciding one. Run it yourself if:

  • Files cannot leave your environment. Data residency rules, a regulated perimeter, or a customer contract that forbids it. This is a hard constraint and no amount of arithmetic moves it.
  • You are air-gapped or on-premises. Then a hosted API is not a candidate at all.
  • Your volume is genuinely large. Cost per scan on a fixed box falls forever. At millions of scans a month, running your own hardware wins on price and it is not close.
  • You need detection beyond ClamAV. Self-hosting lets you chain engines, add YARA rules, or layer commercial scanners. A single-engine API cannot.
  • You already run ClamAV. The build cost — the dominant term above — is already sunk. Your marginal cost is the operations line and nothing else.

That last one matters more than it looks. Most of this post’s cost model is a one-time charge. If you paid it two years ago, the calculation is completely different, and switching to anything is mostly a migration cost with no offsetting saving.

The comparison, since you can do the arithmetic anyway

We sell this as a hosted API. Our Pro tier is $39/month for 100,000 scans, so against the model above: roughly 6–17x on ongoing monthly cost, or 18–68x across year one, where the integration build you never do is counted. Two different numbers measuring two different things, and anyone quoting the larger one at you without saying which is being careless or worse.

We should be equally clear about what that does not buy. The detection is identical, because it is the same ClamAV — no additional engines, no YARA, no content disarm and reconstruction, no hash reputation. If you are self-hosting today and happy with it, the honest recommendation is to set ConcurrentDatabaseReload no, put a concurrency cap in front of clamd, and carry on.