In this tutorial, we'll learn how to install and harden NGINX with ModSecurity on Ubuntu 24.04 server.
When we set up NGINX as a web server or reverse proxy, security cannot be left as an afterthought. A hardened NGINX with ModSecurity Web Application Firewall (WAF) provides protection against common threats such as SQL injection, XSS, and brute force attempts. Below is a complete step-by-step guide on how to install and harden NGINX with ModSecurity on Ubuntu 24.04.
Prerequisites
Before we begin, ensure we have the following:
- An Ubuntu 24.04 on dedicated server or KVM VPS.
- Basic Linux Command Line Knowledge.
Install and Harden NGINX with ModSecurity on Ubuntu
Step 1: Update System Packages
Before making any changes, we must ensure that our server is running the latest packages.
sudo apt update && sudo apt upgrade -y
Keeping the system up to date closes vulnerabilities that attackers often exploit.
Step 2: Install NGINX
Ubuntu 24.04 provides the latest stable NGINX through its official repositories. We install it with:
sudo apt install nginx -y
Enable and start the service:
sudo systemctl enable nginx
sudo systemctl start nginx
Check if it’s running:
systemctl status nginx
Step 3: Install ModSecurity
We need ModSecurity as a dynamic module for NGINX. First, install required dependencies:
sudo apt install libnginx-mod-http-modsecurity -y
This package includes ModSecurity built for NGINX.
Step 4: Enable ModSecurity in NGINX
The module is installed but not enabled by default. We need to load it.
Edit the main configuration file:
sudo nano /etc/nginx/nginx.conf
Inside the http block, add:
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
Step 5: Configure ModSecurity Core Settings
Now we configure ModSecurity to run in Detection Only Mode first. This allows us to monitor requests without blocking legitimate traffic.
Create the ModSecurity directory:
sudo mkdir /etc/nginx/modsec
Copy the default configuration:
sudo cp /etc/modsecurity/crs/crs-setup.conf /etc/nginx/modsec/
sudo cp -r /usr/share/modsecurity-crs/rules /etc/nginx/modsec/
Then copy the main configuration:
sudo curl -o /etc/nginx/modsec/modsecurity.conf \
https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended
Switch to blocking mode:
sudo nano /etc/nginx/modsec/modsecurity.conf
Find the line:
SecRuleEngine DetectionOnly
Change it to:
SecRuleEngine On
Save and exit.
Step 6: Include OWASP Core Rule Set (CRS)
The OWASP CRS provides a strong baseline against common web attacks. We include it in the ModSecurity main configuration file:
sudo nano /etc/nginx/modsec/main.conf
Add:
Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/crs-setup.conf
Include /etc/nginx/modsec/rules/*.conf
Grab the official unicode.mapping file
Pull it straight from OWASP’s repo:
sudo curl -o /etc/nginx/modsec/unicode.mapping \
https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/unicode.mapping
Open your /etc/nginx/modsec/modsecurity.conf
:
sudo nano /etc/nginx/modsec/modsecurity.conf
Find this line (around 258):
SecUnicodeMapFile unicode.mapping
Replace to:
SecUnicodeMapFile /etc/nginx/modsec/unicode.mapping 20127
Step 7: Test NGINX and Reload
Check syntax:
sudo nginx -t
If there are no errors, reload NGINX:
sudo systemctl reload nginx
Step 8: Verify ModSecurity Logs
ModSecurity logs blocked requests to /var/log/nginx/error.log
or a dedicated log file if configured.
Example test request (simulates SQL injection):
curl "http://localhost/?id=1' OR '1'='1"
Output may look like:
curl: (3) URL rejected: Malformed input to a URL function
Check the error log:
sudo tail -f /var/log/nginx/error.log
If rules are working, the request will be logged as blocked.
Step 9: Harden NGINX Configuration
Besides ModSecurity, we must strengthen NGINX itself:
1. Disable Server Tokens
sudo nano /etc/nginx/nginx.conf
Inside http block, add:
server_tokens off;
2. Enable Only Strong TLS Protocols
sudo nano /etc/nginx/snippets/ssl-params.conf
Add:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers HIGH:!aNULL:!MD5;
Include this snippet in site configurations.
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include snippets/ssl-params.conf;
root /var/www/html;
index index.html;
}
3. Limit Request Methods
Inside server block:
if ($request_method !~ ^(GET|POST|HEAD)$) {
return 444;
}
This must also go inside a server {}
block — not in http {}
and not in location {}
. Put it just after your server_name and root directives so it applies to all locations for that domain.
4. Restrict Buffer and Body Sizes
client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 1M;
large_client_header_buffers 2 1k;
Example placement:
http {
server_tokens off;
client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 1M;
large_client_header_buffers 2 1k;
include /etc/nginx/mime.types;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Step 10: Restart and Monitor
Restart NGINX:
sudo systemctl restart nginx
Monitor for any issues:
sudo journalctl -u nginx -f
Final Thoughts
By installing NGINX with ModSecurity WAF on Ubuntu 24.04 and applying additional hardening steps, we establish a solid defense against common web attacks. With the OWASP Core Rule Set, we gain community-tested protection, while NGINX tweaks ensure tighter control over connections and traffic handling. Regular updates, monitoring, and fine-tuning rules will keep our environment secure and reliable