A cPanel server running LiteSpeed and Imunify360 already has several places where abusive automation can be controlled. Adding another large regular expression to every site’s .htaccess is rarely the cleanest option. A small, server-wide ModSecurity rule backed by an external phrase file is easier to audit and update.
That design still has limits. A User-Agent is self-declared and trivial to forge. LiteSpeed can also serve a cache hit before the request reaches ModSecurity. A reliable bot-control policy therefore uses the User-Agent list as a cheap first filter, then relies on throttling, behavioral detection, and logs for clients that change their identity.
This guide is based on a real deployment where the rule initially failed because the phrase files were stored under /root, the WAF state was unclear, cached requests complicated testing, and an attempted first-hit autoban became more fragile than the original filter.
Choose a Path the WAF Can Actually Read
Do not put the phrase files in /root. On a typical Linux server, /root is mode 0700. Giving /root/blacklist.txt mode 0644 does not help if the LiteSpeed or ModSecurity worker cannot traverse the parent directory.
Use a dedicated directory outside every document root instead:
install -d -o root -g root -m 0755 /home/botlists
install -o root -g root -m 0644 /dev/null /home/botlists/allowlist.txt
install -o root -g root -m 0644 /dev/null /home/botlists/blacklist.txt
The files remain root-owned and are not web-accessible. The directory is traversable and the files are readable by the WAF. If local policy requires tighter permissions, identify the actual LiteSpeed worker identity and grant access with a dedicated group or ACL; do not guess the process user.
Keep one phrase per line. Blank lines and lines beginning with # can be used for spacing and comments. The ModSecurity reference describes @pmFromFile as a case-insensitive, set-based phrase matcher using the Aho-Corasick algorithm, which is well suited to a list of many fixed fragments.
Example:
# /home/botlists/blacklist.txt
ahrefsbot
semrushbot
mj12bot
python-requests
Avoid broad entries such as bot, python, curl, or mozilla. They create false positives and are easy for an abusive client to evade.
Use Two Small ModSecurity Rules
cPanel’s current ModSecurity Tools documentation identifies WHM’s Rules interface and modsec2.user.conf as the supported locations for custom rules. On a cPanel-managed LiteSpeed server, configure the rules through the Apache/cPanel configuration path. LiteSpeed explicitly warns that rules entered only in its native WebAdmin rule area do not protect virtual hosts generated from Apache configuration.
Use unique rule IDs that do not overlap a vendor ruleset:
SecRule REQUEST_HEADERS:User-Agent "@pmFromFile /home/botlists/allowlist.txt" \
"id:777776,phase:1,pass,nolog,ctl:ruleRemoveById=777777"
SecRule REQUEST_HEADERS:User-Agent "@pmFromFile /home/botlists/blacklist.txt" \
"id:777777,phase:1,deny,status:403,log,auditlog,tag:'local-bot-list',msg:'User-Agent matched local bot list'"
The allow rule removes rule 777777 for the current transaction. The deny rule runs in phase 1, where the request headers are already available and the body does not need to be read.
Start with deny,status:403, not a silent connection drop. A 403 is easy to reproduce, appears in access and WAF logs, and gives monitoring systems a clear result. Optimize response behavior only after the rule is proven and after confirming which disruptive actions the LiteSpeed ModSecurity engine supports in the installed version.
Deploy through WHM and perform the requested graceful restart. cPanel notes that staged rule changes do not take effect until they are deployed.
Verify That LiteSpeed Is Loading the cPanel Rules
LiteSpeed’s cPanel ModSecurity guidance says that its engine is compatible with common rulesets, but that cPanel-managed virtual hosts must receive rules through the Apache configuration. The checks should therefore cover both configuration and execution:
- Confirm ModSecurity is installed and enabled in WHM.
- Confirm the custom rule is enabled in WHM > Security Center > ModSecurity Tools.
- Deploy the configuration and gracefully restart LiteSpeed.
- Search the LiteSpeed server error log for rule-loading errors or unreadable phrase files.
- Reproduce one request and find rule ID
777777in the ModSecurity hit or audit log.
For short diagnostic windows, LiteSpeed documents increasing SecDebugLogLevel and reading the LiteSpeed server error log. Do not leave verbose WAF logging enabled indefinitely on a busy host.
Test Without Your Own Allowlist Hiding the Result
A test from a trusted administrator address can produce a misleading 200 if that address is exempted elsewhere. Before declaring the custom rule broken, identify all bypass layers:
- Imunify360 IP allowlists or trusted networks.
- CDN or reverse-proxy allow rules.
- Domain-level ModSecurity disablement.
- A matching phrase in
allowlist.txt. - LiteSpeed cache behavior.
Use a controlled source address that is not trusted and request an uncached URL:
curl -sS -D - -o /dev/null \
-A 'AhrefsBot' \
'https://example.com/?bot-filter-test=20260808'
Then run a control request with a neutral User-Agent. A successful test consists of three pieces of evidence: the expected HTTP result, the corresponding rule hit, and no rule-loading errors after the restart.
Do not test by sending attack payloads to a production application. A synthetic User-Agent entry created specifically for the test is safer:
vpnwp-modsec-filter-test
Account for LiteSpeed Cache Hits
This is the most important limitation in this design. LiteSpeed’s security documentation states that its cache engine takes precedence over ModSecurity: a cached page may be served without another WAF scan. A phase-1 User-Agent rule can therefore block an uncached request and still appear ineffective for a hot cached page.
Do not try to solve that discrepancy by adding more ModSecurity rules. Decide where the requirement belongs:
| Requirement | Better control point |
|---|---|
| Reject a named crawler on uncached dynamic requests | ModSecurity phrase list |
| Limit aggressive request volume | LiteSpeed per-client throttling |
| Block traffic before it reaches the server | Upstream firewall or CDN/WAF |
| Identify automation that impersonates a browser | Behavioral rules and rate analysis |
| Remove a confirmed hostile IP temporarily | Imunify360 or upstream firewall policy |
If the business requirement is “this User-Agent must never receive even cached HTML,” enforce it at a layer evaluated before LiteSpeed cache delivery. Test that behavior explicitly after every configuration change.
Do Not Turn One User-Agent Hit into an Automatic IP Ban
The original deployment evolved toward a systemd service that parsed the ModSecurity audit log and added an IP to Imunify360 after the first hit. The approach repeatedly failed because LiteSpeed audit formats differed, the parser associated the wrong lines, and Imunify360 command syntax varied by installed version.
Even a perfectly parsed event is weak evidence for an IP ban:
- User-Agents can be spoofed.
- Shared NAT addresses can represent many legitimate people.
- Search crawlers and monitoring systems change addresses.
- A phrase match can be a false positive.
- Log formats and rotation can break an external watcher silently.
Use Imunify360’s current command-line documentation for any manual or automated IP action supported by the installed version. Before automating, verify the subcommand with imunify360-agent --help, use a threshold across a time window, exclude local and trusted networks, deduplicate events, record an expiry, and test log rotation.
A safer first version alerts on repeated rule hits. Promote an address to a temporary block only when the evidence combines rate, request pattern, and reputation—not merely a declared User-Agent.
Operational Checklist
Before deployment:
- Store root-owned phrase files in a traversable, non-web directory.
- Use narrow phrases and a small allowlist.
- Reserve unique rule IDs and document their owner.
- Confirm whether cached responses are in scope.
After deployment:
- Test from a non-trusted source address.
- Use a cache-busting URL for the WAF test.
- Verify the rule ID in the hit or audit log.
- Check LiteSpeed’s error log for file-access or parser errors.
- Monitor false positives before adding any IP automation.
During maintenance:
- Edit the temporary file, validate it, then replace the active list atomically.
- Retest one blocked and one allowed synthetic identity.
- Review allowlist entries and custom rules on a schedule.
- Keep behavioral controls active because the User-Agent layer is not authentication.
Conclusion
For a cPanel server using LiteSpeed and Imunify360, a ModSecurity @pmFromFile rule is a practical low-complexity filter for known User-Agent fragments. Its success depends more on placement and verification than on the length of the list: the WAF must be able to read the files, the rule must be loaded through cPanel’s configuration, the test must avoid trusted-IP and cache bypasses, and the logs must confirm the transaction.
Treat the list as a first-pass filter. LiteSpeed throttling, Imunify360, and an upstream WAF handle the more important problem: clients whose behavior is abusive even when their User-Agent looks ordinary.