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;
Restart Nginx after editing:
sudo systemctl reload nginx
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;
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;
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
Then include the module in Nginx:
modsecurity on;
modsecurity_rules_file /etc/modsecurity/crs/crs-setup.conf;
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
Place the file in /etc/fail2ban/jail.d/nginx.conf
and restart Fail2Ban:
sudo systemctl restart fail2ban
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;
}
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
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"
Place the file at /etc/systemd/system/certbot-renew.timer
and enable it:
sudo systemctl enable --now certbot-renew.timer
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)