Why ModSecurity Collection Files Grow Without Limit, and How to Compact Them
This guide explains a maintenance job that almost nobody knows about until it bites: the files ModSecurity uses to count requests grow without limit and never shrink on their own. You will learn what those files are, how to check whether yours have a problem, and how to compact them safely.
It matters if any of your ModSecurity rules do rate limiting, which means any rule that counts how often a single visitor hits your site. On a busy server the counter file can reach hundreds of megabytes while holding only a few dozen live entries.
Last reviewed: 3 August 2026, against ModSecurity 2.9.13 as packaged for Plesk on Debian 12. This guide is written for Noiz hosting and is kept current against ModSecurity. It complements, and does not replace, the official ModSecurity documentation linked below.
Official Documentation Reference
- ModSecurity Reference Manual (v2.x), for the
SecDataDirdirective and theinitcol,setvarandexpirevaractions - modsec-sdbm-util, the maintenance tool for these files
Prerequisites
Section titled “Prerequisites”- Root access to a Plesk server running Apache with ModSecurity 2
- A maintenance window, because the safe procedure stops the web server briefly
- ModSecurity rules that use persistent collections. If no rule in your set uses
initcol, this does not apply to you
What these files actually are
Section titled “What these files actually are”Some ModSecurity rules work by counting. A rate-limiting rule asks a question like “how many times has this address requested a page in the last sixty seconds?”, and to answer it, ModSecurity has to write the running tally down somewhere.
That somewhere is a set of files in the directory named by the SecDataDir directive. On Plesk this is normally /var/cache/modsecurity, and the files look like this:
www-data-ip.dirwww-data-ip.pagwww-data-session.dirwww-data-session.pagwww-data-global.dirwww-data-global.pagThe prefix is the user Apache runs as. The name after it is the collection: ip for per-address counters, session for per-session ones, global for server-wide ones. The .pag file holds the data and the .dir file is its index.
Nothing created these deliberately. ModSecurity makes them the first time a rule calls initcol, and then uses them for as long as the server runs.
The problem
Section titled “The problem”These are SDBM files, an old and deliberately simple database format. Simplicity is why ModSecurity uses it, and it is also the catch: SDBM never reclaims space.
When a counter expires, and they expire constantly because rate-limit windows are measured in seconds, the entry stops being valid but the space it occupied is not returned for reuse. The file grows, leaves a hole, grows again past the hole, and repeats. Over months, on a server counting requests across hundreds of sites, the result is a file that is almost entirely empty space.
There is no automatic cleanup. No log warns you. Nothing fails loudly. The file simply gets bigger every day until somebody looks.
Why it is worth fixing, in proportion
Section titled “Why it is worth fixing, in proportion”Be careful here, because it is easy to overstate. The honest case is narrower than “your server is slow because of this file”.
Disk space is usually not the problem, for the sparse-file reason explained in Step 1. A file reporting hundreds of megabytes may be using a few megabytes.
The real cost is lookup efficiency, and it scales with fragmentation, not size. Every request a counting rule inspects performs a read and a write against the file, inside the request path. When most of what the file addresses is dead, those lookups traverse more to find less. On a heavily fragmented collection across a busy server this is measurable. On a lightly fragmented one it is noise.
The reliability angle is the one worth keeping in mind, though treat it as a suspect rather than a conclusion. SDBM degrades as it fragments, and if counter writes are lost the symptom is not an error. It is a rate-limiting rule that quietly undercounts: deployed, correctly configured, syntax check passing, and the flood gets through anyway. If you have ever been unable to explain why a rate limit failed to hold, check the fragmentation rate before you rewrite the rule.
The practical position: this is routine maintenance, not an emergency. Schedule it, do not panic about it, and let the fragmentation rate decide the urgency.
Step 1: Check whether you have the problem
Section titled “Step 1: Check whether you have the problem”Do not judge by file size alone
Section titled “Do not judge by file size alone”This is the trap, and it catches people who go looking for this problem after reading about it.
ls -l /var/cache/modsecurity/total 10656-rw-r----- 1 www-data www-data 226693120 Aug 3 19:50 www-data-ip.pagThat file reports 226 MB. It occupies about 10 MB on disk. Read the total line: SDBM writes a sparse file, meaning it addresses a large space but only the pages actually written consume any disk. The apparent size is the address space, not the storage.
So a huge ls -l figure on its own proves nothing, and du -h is the honest measure of disk use:
du -h /var/cache/modsecurity/Measure fragmentation instead
Section titled “Measure fragmentation instead”The number that actually tells you whether to act is the fragmentation rate. The -s flag reports status and changes nothing:
/opt/alt/modsec-sdbm-util/bin/modsec-sdbm-util -s /var/cache/modsecurity/www-data-ipNote that the path you pass has no extension. The tool opens the .dir and .pag pair for you.
The output ends with a summary:
Total of 74 elements processed.0 elements removed.Expired elements: 4, inconsistent items: 0Fragmentation rate: 4.30% of the database is/was dirty data.That last line is the one to act on. Two real examples measured on the same server on the same day:
www-data-ip: 226 MB apparent, 74 live entries, 4.30% dirty. Large-looking, barely fragmented, not urgent.www-data-session: 25 MB apparent, 83.33% dirty. Far smaller, and the one that genuinely needs rebuilding.
A rough guide: below about 20% is normal wear and can wait for the next scheduled window. Above 50% is worth acting on. Above 80% means most of what the file addresses is dead, and lookups are paying for it.
Where is the tool? Some server security suites bundle it, commonly at /opt/alt/modsec-sdbm-util/bin/modsec-sdbm-util, so check whether it is already present before installing anything. If it is not, build it from the upstream source linked above.
Step 2: Understand which repair you need
Section titled “Step 2: Understand which repair you need”The tool offers two repairs and they do different jobs. Choosing wrongly wastes a maintenance window.
-k(shrink) removes expired and malformed entries. If the status report showed zero expired and zero inconsistent items, this reclaims nothing. The bloat is structural dead space, not stale records.-n(new) reads the valid entries and writes them into a fresh database. This is what actually recovers the space, because the new file is built compactly from scratch.
For a file that is large but reports no expired entries, -n is the one you want. Run -s first so you know which case you are in.
Step 3: Compact the files
Section titled “Step 3: Compact the files”Apache holds these files open, so the safe order stops it first. Downtime is seconds, but choose a quiet window regardless.
Take a backup before touching anything:
cp -a /var/cache/modsecurity /root/modsec-collections-backup-$(date +%F)Stop the web server, rebuild each collection into a new database, and put it in place:
systemctl stop apache2
/opt/alt/modsec-sdbm-util/bin/modsec-sdbm-util -n -D /tmp \ /var/cache/modsecurity/www-data-ipmv /tmp/new_db.dir /var/cache/modsecurity/www-data-ip.dirmv /tmp/new_db.pag /var/cache/modsecurity/www-data-ip.pag
chown www-data:www-data /var/cache/modsecurity/www-data-*chmod 640 /var/cache/modsecurity/www-data-*
systemctl start apache2Repeat the middle block for www-data-session and any other collection that is oversized.
Ownership is not optional. The files must be owned by the user Apache runs as, or ModSecurity cannot write to them and every counting rule silently stops counting. This is the single most common way to turn a maintenance job into an outage. Check ownership before starting Apache, not after.
Step 4: Verify
Section titled “Step 4: Verify”Confirm the file shrank, the entries survived, and the server is serving:
ls -lh /var/cache/modsecurity//opt/alt/modsec-sdbm-util/bin/modsec-sdbm-util -s /var/cache/modsecurity/www-data-ipsystemctl is-active apache2curl -sk -o /dev/null -w "HTTP %{http_code} in %{time_total}s\n" https://yourdomain.example/The entry count should be close to what it was before. A large drop means valid records were lost, and that is when the backup earns its place.
Then watch that the counters are working again. Within a few minutes of live traffic the .pag file should start growing again, gently. A file that stays at exactly its new size is a file nothing is writing to, which usually means the ownership step was missed.
Step 5: Make it recurring
Section titled “Step 5: Make it recurring”Compacting once solves today and nothing else. The file starts growing again immediately, at the same rate as before.
Add it to whatever maintenance schedule the server already has, monthly is generally sufficient, and keep it in the same window as any other job that briefly restarts the web server. Record the before and after sizes each time so the growth rate becomes visible.
Troubleshooting
Section titled “Troubleshooting”Symptom: modsec-sdbm-util reports the file cannot be opened. Check that you passed the path without the .dir or .pag extension, and that you are running as root.
Symptom: the file is compacted but rate-limiting rules stop firing afterwards. Almost always ownership or permissions. Confirm the files are owned by the Apache user with mode 640, then reload Apache.
Symptom: -k ran and the file is the same size. Expected, if the status report showed zero expired entries. Use -n instead, as described in Step 2.
Symptom: the file grows very quickly after compaction, megabytes per hour. That is a sign a rule is counting far more than intended, often a counter with no expirevar or an expiry window that is too long. Review the rules that call setvar against a collection.
Symptom: no collection files exist at all. Then no rule in the set uses persistent collections, and there is nothing here to maintain. Confirm with grep -r initcol against the rule directories.
A note on the global collection
Section titled “A note on the global collection”Worth knowing if you write your own rules. ModSecurity initialises one instance of each collection per request, so if two separate rules both call initcol:global with different keys, only the first to run takes effect and the second is silently ignored. Rules from different sources, a vendor rule set and a custom one for example, can collide this way without any warning.
If you need an aggregate counter of your own and the global collection is already claimed, check which collections are unused on your server before choosing one:
grep -rhoE "initcol:[a-zA-Z]+" /etc/apache2/ | sort | uniq -cPick a collection with no existing references. Different collections coexist without conflict, so the constraint is only ever within one collection.
Need a hand?
Section titled “Need a hand?”Noiz manages this as part of routine server maintenance on managed plans, including the compaction schedule and monitoring for abnormal growth. If your site is on a managed Noiz plan and you would like the collection files checked, open a ticket and the team will take it from there.

