Configure LibModsecurity with Nginx on CentOS 8

Last Updated:

In this guide, we are going to learn how to configure LibModsecurity with Nginx on CentOS 8. LibMosecurity is the newest version of ModSecurity version 2.9 and below. It is therefore known as ModSecurity version 3.

Configuring LibModsecurity with Nginx on CentOS 8

Run System Update

Begin by updating your system packages.

dnf update

Install Required Build Tools and Dependencies

Both Nginx and LibModsecurity are going to be compiled from the source and thus a number of build tools and dependencies are required. Run the command below to install them.

dnf install gcc-c++ flex bison yajl curl-devel curl zlib-devel pcre-devel autoconf automake git curl make libxml2-devel pkgconfig libtool httpd-devel redhat-rpm-config git wget openssl openssl-devel vim
dnf --enablerepo=PowerTools install doxygen yajl-devel

Install GeoIP Libraries

dnf install
dnf install
dnf --enablerepo=remi install GeoIP-devel

Download LibModsecurity Source Code

Create a temporary directory to store the source tarballs.

mkdir /tmp/modsec

You can choose to use /opt instead.

Run the command below to  clone the latest LibModsecurity GitHub repository.

cd /tmp/modsec
git clone --depth 1 -b v3/master --single-branch

Compile and Install LibModsecurity

Navigate to the LibModsecurity source directory, configure, compile and install it

cd ModSecurity

Download libInjection code which is available as part of ModSecurity source code in a format of a git-submodule

git submodule init
git submodule update

Configure LibModsecurity to adapt it to your system and check if any required dependency is missing.


The fatal: No names found, cannot describe anything can be safely ignored. Fix any dependency issue just in case there is any.

Compile and install LibModSecurity.

make install

Install Nginx with LibModsecurity Support

To setup Nginx with LibModsecurity, you need to compile Nginx with support for LibModsecurity.

Therefore, download the ModSecurity-nginx connector which provides a communication channel between Nginx and LibModsecurity by cloning its git repository.

cd /tmp/modsec
git clone

Next, download the latest staple version of Nginx from Nginx downloads. The latest version as of this writing is version nginx-1.17.6.tar.gz.


Extract the archive.

tar xzf nginx-1.17.6.tar.gz

Create a non-privileged Nginx system user and group.

useradd -r -M -s /sbin/nologin -d /usr/local/nginx nginx

Navigate to Nginx source directory and configure it.

cd nginx-1.17.6
./configure --user=nginx --group=nginx --with-pcre-jit --with-debug --with-http_ssl_module --with-http_realip_module --add-module=/tmp/modsec/ModSecurity-nginx

Compile and install Nginx.

make install

Confgure Nginx with ModSecurity

To begin with, copy the sample ModSecurity configuration file on the source directory to Nginx configuration directory.

cp /tmp/modsec/ModSecurity/modsecurity.conf-recommended /usr/local/nginx/conf/modsecurity.conf

Copy the unicode.mapping file from ModSecurity source directory to Nginx configuration directory.

cp /tmp/modsec/ModSecurity/unicode.mapping /usr/local/nginx/conf/

Next, edit Nginx configuration file and make the changes as shown below.

Create a backup of the Nginx configuration file.

cp /usr/local/nginx/conf/nginx.conf /usr/local/nginx/conf/nginx.conf.bak

Open the configuration file for editing.

vim /usr/local/nginx/conf/nginx.conf

Configure Nginx such that your configuration may look like;

user  nginx;
worker_processes  1;
pid        /run/;
events {
    worker_connections  1024;
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        modsecurity  on;
        modsecurity_rules_file  /usr/local/nginx/conf/modsecurity.conf;
        access_log  /var/log/nginx/access_kifarunix-demo.log;
        error_log  /var/log/nginx/error_kifarunix-demo.log;
        location / {
            root   html;
            index  index.html index.htm;
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;

Note that the line;

modsecurity  on;
modsecurity_rules_file  /usr/local/nginx/conf/modsecurity.conf;

Turns on Modsecurity and specifies the location of the Modsecurity rules.

Note that ModSecurity 3 can be turned on per directory basis.

Create Nginx log directory.

mkdir /var/log/nginx

Create Nginx Systemd Service

To be able to run Nginx as a service, create a systemd service as shown below;

vim /etc/systemd/system/nginx.service
Description=The nginx HTTP and reverse proxy server

ExecStartPre=/usr/bin/rm -f /run/
ExecStartPre=/usr/sbin/nginx -t
ExecReload=/bin/kill -s HUP $MAINPID


Create a symbolic link of Nginx binary to /usr/sbin/ path.

ln -s /usr/local/nginx/sbin/nginx /usr/sbin/

Reload systemd configurations.

systemctl daemon-reload

Run Nginx configuration syntax error verification.

nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

If all is well, start and enable Nginx to run on system boot.

systemctl enable --now nginx

Check the status;

systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/etc/systemd/system/nginx.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2019-11-30 09:52:05 EAT; 9s ago
  Process: 2679 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 2678 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 2676 ExecStartPre=/usr/bin/rm -f /run/ (code=exited, status=0/SUCCESS)
 Main PID: 2681 (nginx)
    Tasks: 2 (limit: 11524)
   Memory: 3.5M
   CGroup: /system.slice/nginx.service
           ├─2681 nginx: master process /usr/sbin/nginx
           └─2682 nginx: worker process

Turn on ModSecurity Rule Engine

By default, ModSecurity is set on detection only mode where it only logs the requests based on the triggered rules without blocking anything. This can be changed by setting the value of SecRuleEngine to On.

sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /usr/local/nginx/conf/modsecurity.conf

You can also change default log directory for Modsecurity

sed -i 's#/var/log/modsec_audit.log#/var/log/nginx/modsec_audit.log#' /usr/local/nginx/conf/modsecurity.conf

Install OWASP ModSecurity Core Rule Set (CRS)

The OWASP ModSecurity Core Rule Set (CRS) is a set of generic attack detection rules for use with ModSecurity. It aims at protecting the web applications from a wide range of attacks, including the OWASP Top Ten, minimum of false alerts.

Clone the CRS from GitHub repository to /usr/local/nginx/conf/ as shown below;

git clone /usr/local/nginx/conf/owasp-crs

Next, rename crs-setup.conf.example to crs-setup.conf.

sudo cp /usr/local/nginx/conf/owasp-crs/crs-setup.conf{.example,}

Once the OWASP rules are in place, configure ModSecurity to use these rules. You therefore need to enter the following lines on the ModSecurity configuration file to tell it where to find the rules.

echo -e "Include owasp-crs/crs-setup.conf\nInclude owasp-crs/rules/*.conf" >> /usr/local/nginx/conf/modsecurity.conf

This command will append the lines below on /usr/local/nginx/conf/modsecurity.conf.

Include owasp-crs/crs-setup.conf
Include owasp-crs/rules/*.conf

Verify Nginx configuration file again.

nginx -t

Next, restart Nginx if everything is Okay.

systemctl restart nginx

Testing ModSecurity on Nginx

Next, you can test the effectiveness of Modsecurity with OWASP rules, for example, using the command injection. Run the command below;

curl localhost/index.html?exec=/bin/bash

You should get 403 Forbidden if the rules are file.

<head><title>403 Forbidden</title></head>
<center><h1>403 Forbidden</h1></center>

Check the logs file.

tail /var/log/nginx/mod
ModSecurity: Warning. Matched "Operator `PmFromFile' with parameter `' against variable `ARGS:exec' (Value: `/bin/bash' ) [file "/usr/local/nginx/conf/owasp-crs/rules/REQUEST-932-APPLICATION-ATTACK-RCE.conf"] [line "496"] [id "932160"] [rev ""] [msg "Remote Command Execution: Unix Shell Code Found"] [data "Matched Data: bin/bash found within ARGS:exec: /bin/bash"] [severity "2"] [ver "OWASP_CRS/3.2.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-shell"] [tag "platform-unix"] [tag "attack-rce"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "OWASP_CRS/WEB_ATTACK/COMMAND_INJECTION"] [tag "WASCTC/WASC-31"] [tag "OWASP_TOP_10/A1"] [tag "PCI/6.5.2"] [hostname ""] [uri "/index.html"] [unique_id "157509875732.654695"] [ref "o1,8v21,9t:urlDecodeUni,t:cmdLine,t:normalizePath,t:lowercase"]
ModSecurity: Access denied with code 403 (phase 2). Matched "Operator `Ge' with parameter `5' against variable `TX:ANOMALY_SCORE' (Value: `5' ) [file "/usr/local/nginx/conf/owasp-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "79"] [id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Score: 5)"] [data ""] [severity "2"] [ver ""] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname ""] [uri "/index.html"] [unique_id "157509875732.654695"] [ref ""]
ModSecurity: Warning. Matched "Operator `Ge' with parameter `5' against variable `TX:INBOUND_ANOMALY_SCORE' (Value: `5' ) [file "/usr/local/nginx/conf/owasp-crs/rules/RESPONSE-980-CORRELATION.conf"] [line "76"] [id "980130"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Inbound Score: 5 - SQLI=0,XSS=0,RFI=0,LFI=0,RCE=5,PHPI=0,HTTP=0,SESS=0): individual paranoia level scores: 5, 0, 0, 0"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [tag "event-correlation"] [hostname ""] [uri "/index.html"] [unique_id "157509875732.654695"] [ref ""]

You can also create your own test rules. For example, append the line below on your /usr/local/nginx/conf/modsecurity.conf.

SecRule ARGS "@streq test" "id:1,phase:1,deny,msg:\'Mytest Rule\'"

Save the configuration file. You can also create your custom rules file and make sure it is included on the main ModSecurity configuration file.

Restart Nginx.

systemctl restart nginx

Test the rule.

curl localhost/index.html?a=test
<head><title>403 Forbidden</title></head>
<center><h1>403 Forbidden</h1></center>

Check the log file.

ModSecurity: Access denied with code 403 (phase 1). Matched "Operator `StrEq' with parameter `test' against variable `ARGS:a' (Value: `test' ) [file "/usr/local/nginx/conf/modsecurity.conf"] [line "254"] [id "1"] [rev ""] [msg "\'Mytest Rule\'"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname ""] [uri "/index.html"] [unique_id "157509886780.823503"] [ref "v18,4"]

The ModSecurity is now running and protecting your web server.

If you want to run any specific web application that requires LAMP stack/LEMP stack installed, you can follow the links below to set up LEMP/LAMP stack on CentOS 8.

Install LEMP Stack on CentOS 8

Install LAMP Stack on CentOS 8

You can check our other guides on ModSecurity by following the links below;

Install LibModsecurity with Apache on Ubuntu 18.04

Install LibModsecurity with Apache on Fedora 30/29/CentOS 7


We're passionate about sharing our knowledge and experiences with you through our blog. If you appreciate our efforts, consider buying us a virtual coffee. Your support keeps us motivated and enables us to continually improve, ensuring that we can provide you with the best content possible. Thank you for being a coffee-fueled champion of our work!

Photo of author
I am the Co-founder of, Linux and the whole FOSS enthusiast, Linux System Admin and a Blue Teamer who loves to share technological tips and hacks with others as a way of sharing knowledge as: "In vain have you acquired knowledge if you have not imparted it to others".

Leave a Comment