DEV Community

Ramer Labs
Ramer Labs

Posted on

7 Tips for Hardening Nginx: TLS, Fail2Ban, and WAF Configuration

Introduction

If you’re a DevOps lead tasked with keeping a public‑facing web service reliable and secure, Nginx is often the front‑line reverse proxy you’ll rely on. While Nginx excels at performance, it also needs a solid security posture to survive the modern threat landscape. This tutorial walks you through seven practical steps to lock down Nginx using TLS, Fail2Ban, and a Web Application Firewall (WAF). The focus is on actionable configuration snippets you can drop into your existing setup.


1. Enforce Strong TLS Settings

TLS is the first line of defense. A weak cipher suite or an outdated protocol version can expose you to downgrade attacks.

  • Disable SSLv2/SSLv3 and TLS 1.0/1.1
  • Prefer TLS 1.3 when the client supports it
  • Use a modern cipher suite (e.g., TLS_AES_256_GCM_SHA384)
  • Enable OCSP stapling to speed up certificate validation

Add the following block to your nginx.conf or a dedicated tls.conf file:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers \
    "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256";
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Enter fullscreen mode Exit fullscreen mode

Restart Nginx after editing:

sudo systemctl reload nginx
Enter fullscreen mode Exit fullscreen mode

2. Harden HTTP Headers

Security‑focused headers reduce the attack surface for XSS, click‑jacking, and MIME sniffing.

add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self'" always;
Enter fullscreen mode Exit fullscreen mode

Apply them in a server block that serves your public site.

3. Limit Request Size and Rate

Large bodies can be abused for DoS attacks, and rapid request bursts may indicate brute‑force attempts.

client_max_body_size 2M;
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
limit_req zone=mylimit burst=20 nodelay;
Enter fullscreen mode Exit fullscreen mode

Adjust the rate and burst values based on typical traffic patterns.

4. Deploy ModSecurity as a WAF

ModSecurity provides a rule‑based engine that can block common web exploits (SQLi, XSS, etc.). Install it via your package manager and enable the OWASP Core Rule Set (CRS).

# Ubuntu/Debian example
sudo apt-get install libnginx-mod-http-modsecurity
sudo apt-get install owasp-modsecurity-crs
Enter fullscreen mode Exit fullscreen mode

Then include the module in Nginx:

modsecurity on;
modsecurity_rules_file /etc/modsecurity/crs/crs-setup.conf;
Enter fullscreen mode Exit fullscreen mode

Fine‑tune the CRS by disabling rules that generate false positives for your application.

5. Set Up Fail2Ban for Nginx Logs

Fail2Ban can automatically ban IPs that repeatedly trigger 4xx/5xx responses. Create a jail that watches the Nginx error log.

[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600
Enter fullscreen mode Exit fullscreen mode

Place the file in /etc/fail2ban/jail.d/nginx.conf and restart Fail2Ban:

sudo systemctl restart fail2ban
Enter fullscreen mode Exit fullscreen mode

You can also add a custom filter (/etc/fail2ban/filter.d/nginx-http-auth.conf) that matches patterns like "401" or "403".

6. Separate Static and Dynamic Content

Running static assets (images, CSS, JS) from a dedicated location reduces the attack surface of your application backend.

server {
    listen 443 ssl http2;
    server_name static.example.com;
    root /var/www/static;
    location / {
        try_files $uri $uri/ =404;
    }
    # Re‑use TLS block from earlier
    include /etc/nginx/conf.d/tls.conf;
}
Enter fullscreen mode Exit fullscreen mode

By isolating static content, you can apply stricter rate limits and even serve it from a CDN.

7. Automate Certificate Renewal

Manual certificate updates are a recipe for downtime. Use certbot with a systemd timer to keep your certs fresh.

sudo apt-get install certbot python3-certbot-nginx
sudo certbot renew --dry-run
Enter fullscreen mode Exit fullscreen mode

Create a timer if your distro doesn’t provide one:

[Unit]
Description=Renew Let's Encrypt certificates
[Timer]
OnCalendar=weekly
Persistent=true
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"
Enter fullscreen mode Exit fullscreen mode

Place the file at /etc/systemd/system/certbot-renew.timer and enable it:

sudo systemctl enable --now certbot-renew.timer
Enter fullscreen mode Exit fullscreen mode

Conclusion

Hardening Nginx is a layered process: strong TLS, security headers, request limiting, a WAF, automated bans, and diligent certificate management all work together to keep your service resilient. Implement these seven steps incrementally, test each change in a staging environment, and monitor logs for unexpected behavior. When you need a quick sanity check or a deeper dive into any of these topics, the community resources at https://lacidaweb.com can provide useful references and real‑world examples.

Top comments (0)