How to install ModSecurity

ModSecurity is a toolkit for real-time web application monitoring, logging, and access control.

CustomBuild allows you to install ModSecurity together with desired rulesets. The comodo ruleset will also install a plugin where you may manage rules from the DirectAdmin panel itself. The owasp is another rule provider available for automatic installation.

cd /usr/local/directadmin/custombuild
./build set modsecurity yes
./build set modsecurity_ruleset "comodo"
./build modsecurity
./build modsecurity_rules
./build rewrite_confs

ModSecurity Log Locations


Log files contained therein include:

  • modsec_audit.log
  • modsec_debug.log

The following directadmin.conf default setting specifies the modsecurity audit log location like so:


User controlled per-domain ModSecurity flags

This featureopen in new window enables Users to skip some mod_security rules, or fully disable them when needed. Users can also view the per-domain logs via this interface and/or completely disable ModSecurity altogether.

How to disable the User's ability to use per-domain ModSecurity feature

Disabling the feature for all Users globally

Should you want to disable all Users' ability to use this feature, use the never commands featureopen in new window, eg:

/usr/local/directadmin/direcadmin set never_commands CMD_MODSECURITY
service directadmin restart

Disabling the feature for a Single User

Should you want to disable only one single User's ability to use this feature, use commands.denyopen in new window like so, but replace USERNAME with the actual username to be denied access to CMD_MODSECURITY:

echo 'CMD_MODSECURITY' >> /usr/local/directadmin/data/users/USERNAME/commands.deny

Customizing ModSecurity Rules

A User or Admin can fully disable ModSecurity rules as needed via SecRuleRemoveById.

Syntax rules for SecRuleRemoveById include:

  • must be a positive integer
  • ranges are allowed, as long as they're "quoted", eg:

The following describes how to use this with DirectAdmin.

Globally - The Old Method

To customize ModSecurity Rules globally, you can add custom rules to /usr/local/directadmin/custombuild/custom/modsecurity/conf/, and they'll be added automatically to /etc/modsecurity.d after ./build modsecurity or ./build modsecurity_rules is ran. This method still works in addition to the new method.

An example for "MYCUSTOMRULES":

cd /usr/local/directadmin/custombuild
mkdir -p custom/modsecurity/conf
nano -w /usr/local/directadmin/custombuild/custom/modsecurity/conf/MYCUSTOMRULES.conf
./build modsecurity_rules

Building the custom rules with CustomBuild will result in a copy of them being placed in /etc/modsecurity.d/, which is included in the webserver configs via a series of Includes dependent on the type of webserver you use.

Globally - The New Method

Log into DirectAdmin and use the global ModSecurity interface located at Server Manager >> ModSecurity (https://hostname:2222/admin/modsecurity) to manage the status of ModSecurity, customize rules, and view logs.

Adding rule IDs in this interface will add them to the following global file:


This file is included by directly by the webserver configs.

Per domain

You can modify the per domain ModSecurity rules either via CustomBuild as described above, or as the Admin or User as described below.

As Admin

Log into DirectAdmin and use the global ModSecurity interface located at Server Manager >> ModSecurity (https://hostname:2222/admin/modsecurity)

If an Admin is making a call to CMD_MODSECURITY, they are allowed to either pass the domain of some other User, or no domain at all. Admin can view rules and logs as well as manage rules for a User via CMD_MODSECURITY by passing the domain=DOMAIN parameter. Without this, the global rules will be returned.

As the User

Log into DirectAdmin and use the User ModSecurity interface located at Advanced Features >> ModSecurity (https://hostname:2222/user/modsecurity)

The rules will be stored in the following files:

  • for domains:
  • for subdomains:

Based off of the following template:


Customizing the ModSecurity Configuration

Methods exist in CustomBuild to permit one to customize the ModSecurity configuration as described below. We will use a common example requiring ModSecurity config changes.

Request body no files data length is larger than the configured limit

If you see the following error in the Apache error log, you can increase the limit via the Apache configuration, however, you must do so in a manner that will allow CustomBuild to preserve the change:

ModSecurity: Request body no files data length is larger than the configured limit (131072).

This limit (SecRequestBodyNoFilesLimit) is set via the following files:

  • /usr/local/directadmin/custombuild/configure/ap2/conf/extra/httpd-modsecurity.conf
  • /usr/local/directadmin/custombuild/configure/openlitespeed/conf/httpd-modsecurity.conf
  • /usr/local/directadmin/custombuild/configure/nginx_reverse/conf/nginx-modsecurity.conf
  • /usr/local/directadmin/custombuild/configure/nginx/conf/nginx-modsecurity.conf

Steps for adjusting this value so that it is not overwritten with the next CustomBuild rebuild of your webserver configuration are defined below. Alternatively, you might try specifying a new setting via the /etc/httpd/conf/extra/httpd-includes.conf file (or the includes file for your chosen webserver) since it is not touched by CustomBuild.


  1. Make sure the custom Apache directory exists:
mkdir -p /usr/local/directadmin/custombuild/custom/ap2/conf/extra
cp -a /usr/local/directadmin/custombuild/configure/ap2/conf/extra/httpd-modsecurity.conf /usr/local/directadmin/custombuild/custom/ap2/conf/extra/httpd-modsecurity.conf 
  1. Edit the value in the custom file as desired:
nano /usr/local/directadmin/custombuild/custom/ap2/conf/extra/httpd-modsecurity.conf


vim /usr/local/directadmin/custombuild/custom/ap2/conf/extra/httpd-modsecurity.conf

or use whatever your preferred editor happens to be.

  1. Rebuild the configuration:
/usr/local/directadmin/custombuild/build rewrite_confs


The process is quite similar for other webservers.


mkdir -p /usr/local/directadmin/custombuild/custom/openlitespeed/conf/
cp -a /usr/local/directadmin/custombuild/configure/openlitespeed/conf/httpd-modsecurity.conf /usr/local/directadmin/custombuild/custom/openlitespeed/conf/httpd-modsecurity.conf
nano /usr/local/directadmin/custombuild/custom/openlitespeed/conf/httpd-modsecurity.conf
/usr/local/directadmin/custombuild/build rewrite_confs

Nginx Reverse Proxy

mkdir -p /usr/local/directadmin/custombuild/custom/nginx_reverse/conf/
cp -a /usr/local/directadmin/custombuild/configure/nginx_reverse/conf/nginx-modsecurity.conf /usr/local/directadmin/custombuild/custom/nginx_reverse/conf/nginx-modsecurity.conf
nano /usr/local/directadmin/custombuild/custom/nginx_reverse/conf/nginx-modsecurity.conf
/usr/local/directadmin/custombuild/build rewrite_confs


mkdir -p /usr/local/directadmin/custombuild/custom/nginx/conf/
cp -a /usr/local/directadmin/custombuild/configure/nginx/conf/nginx-modsecurity.conf /usr/local/directadmin/custombuild/custom/nginx/conf/nginx-modsecurity.conf
nano /usr/local/directadmin/custombuild/custom/nginx/conf/nginx-modsecurity.conf
/usr/local/directadmin/custombuild/build rewrite_confs

Enabling ModSecurity Uploadscan

This feature requires ClamAV, so ensure this is enabled first or at least set to 'yes' in the CustomBuild options.conf. Then, run the following CustomBuild commands:

cd /usr/local/directadmin/custombuild
./build set modsecurity_uploadscan yes
./build modsecurity
./build rewrite_confs

How can I confirm that ModSecurity is working

Testing browser-based requests to the site

Just load your domain like so in the browser:

And then check the domain's error logs. This should trigger File Inclusion protections in ModSecurity and result in an error. You should see something like this logged:

ModSecurity: Access denied with code 406 (phase 2). Matched "Operator `Rx' with parameter `(?i)(?:\x5c|(?:%(?:c(?:0%(?:[2aq]f|5c|9v)|1%(?:[19p]c|8s|af))|2(?:5(?:c(?:0%25af|1%259c)|2f|5c)|%46|f)|(?:(?:f(?:8%8)?0%8|e)0%80%a|bg%q)f|%3(?:2(?:%(?:%6|4)6|F)|5%%63)|u(?:221[56]|002f|EFC8|F025)|1u|5 (400 characters omitted)' against variable `ARGS:page' (Value: `../../etc/passwd' ) [file "/etc/modsecurity.d/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] [line "29"] [id "930100"] [rev ""] [msg "Path Traversal Attack (/../)"] [data "Matched Data: /../ found within ARGS:page: ../../etc/passwd"] [severity "2"] [ver "OWASP_CRS/3.3.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-lfi"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/255/153/126"] [hostname ""] [uri "/"] [unique_id "161575949767.714205"] [ref "o9,4v4,23o2,4v11,16"], client: X.X.X.X, server:, request: "GET /?page=../../etc/passwd HTTP/1.1", host: ""

Error logs are located here, depending on webserver and domain, respectively:


Testing ModSecurity Uploadscan

If you need to test ModSecurity Uploadscan, you can try uploading the EICAR test files located at the following links to ensure that the upload is blocked: in new window


This section describes the CMD_MODSECURITY command and required/optional GET/POST parameters.


Viewing global rules as admin
Viewing a User's per-domain rules
Viewing a User's per-subdomain rules
Viewing json output

The following:


returns 2 arrays, one for On/Off flags, and the other for skip IDs, eg:

	"SecRuleRemoveById" :
		"SecFilterScanPOST": "On",
		"SecRuleEngine": "On"

Viewing the options.conf Modsecurity setting value

You can learn if modsecurity=yes is set in the options.conf via:


with the added value:


When called by an Admin, absence of the domain will return the global modsecurity_rules file.

You'll also get a "subdomain_select" array, which is a standard select-box for the available subdomains.

Save flags

  • method: POST
  • action=save
  • SecFilterScanPOST=On|Off
  • SecRuleEngine=On|Off
  • optional, can also include to save a call if saving and skipping in 1 request: SecRuleRemoveById=<ID>

When called by an Admin, absence of the domain will save to the global modsecurity_rules file. This also applies to the rule skips below.

Add rule skip

  • method: POST
  • action=add
  • SecRuleRemoveById=<ID>

Remove rule skip

  • method: POST
  • action=select
    • SecRuleRemoveById=<ID>AND/OR
    • select0=<ID>
    • (select1)=<ID>

View logs

JSON output is only of the modsec_audit.log. This requires the modsec_audit.log to use the new one-json-per-line format.


Only show entries matching this domain.
For Users, the domain must be in the domains.list.
For Admins, can be any host value they want.
Sub-domains will be included in the output.
Blank hosts are not included.


Shows entries with any Host value (or no Host).
To reduce the log output, you should include the following, specifying your desired value:


DA starts from the end of the log, parsing lines backwards.
It stops after this number of ENTRIES has been added to the log (was a tail, but it's now entries).
There is also an internal max_time=15 (which is dynamic, timeout / 4, assuming timeout=60).
You can pass &max_time=5 or any other number of seconds, to have the parser stop after this number of seconds, that is if you wish to speed up the display at the cost of losing some older entries.
For very large logs, there is no point in parsing the entire thing if a timeout will happen.
The logs will be output in a "logs" array, filled with a list of transaction arrays.
The top-level json also includes a "summary" array, giving info on how the parser actually went, eg:

		"max_time": "15",
		"requested_lines": "500",
		"returned_lines": "375",
		"time_abort": "yes"

If you see "time_abort" ; "yes", it would mean that time ran out before actually finding that number of lines/entries.

ModSecurity Templates and Skins



Where flags are stored into |FLAGS| and the multi-line SecRuleRemoveById values are saved into |DISABLEDRULES|

There template starts with |CUSTOM1| and ends with |CUSTOM2|, but these tokens are currently blank for possible future expansion.

In the virtual_host2*.conf, we've added a new token:


within the <Directory> context.

Also, this token is available in the nginx_server*.conf and the openlitespeed_vhost.conf.


New file:




to include a button when:

|*if HAS_MOD_SECURITY="yes"|

pointing to:

Last Updated: