Introduction
Running Nginx as a front‑end web server is common, but without proper hardening it can become an easy target for attackers. This guide walks you through seven practical steps to lock down Nginx using TLS, a robust firewall, and Fail2Ban. The checklist is written from the perspective of a DevOps lead who needs repeatable, auditable security controls for production workloads.
1. Enforce TLS 1.2+ and Strong Cipher Suites
Outdated TLS versions (1.0/1.1) are deprecated and vulnerable to POODLE, BEAST, and other attacks. Edit your nginx.conf (or a dedicated snippet in /etc/nginx/conf.d/
) to force TLS 1.2 and TLS 1.3 only:
# /etc/nginx/conf.d/ssl.conf ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers \ "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1h;
Why it matters: Strong ciphers protect data in‑flight and improve your SSL Labs grade.
2. Enable HTTP Strict Transport Security (HSTS)
HSTS tells browsers to only use HTTPS for your domain, preventing protocol downgrade attacks.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Add the header in the same block where you terminate TLS. Remember to test with curl -I https://example.com
before submitting to the HSTS preload list.
3. Deploy Free, Auto‑Renewing Certificates with Certbot
Manual certificate management is error‑prone. Use certbot to obtain and renew certificates automatically.
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx sudo certbot --nginx -d example.com -d www.example.com --agree-tos --no-eff-email
Certbot will edit your Nginx config, add the ssl_certificate
directives, and set up a systemd timer for renewal.
4. Harden the Underlying OS Firewall
Even with Nginx locked down, an open firewall can expose services you don’t intend to publish. Use ufw (or iptables) to allow only HTTP/HTTPS and SSH from trusted IPs.
sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 22/tcp from 203.0.113.0/24 comment "Admin SSH" sudo ufw allow 80/tcp comment "HTTP" sudo ufw allow 443/tcp comment "HTTPS" sudo ufw enable
Review the rules regularly with ufw status numbered
.
5. Install and Configure Fail2Ban for Nginx
Fail2Ban can automatically ban IPs that trigger repeated 4xx/5xx responses, such as brute‑force attempts on API endpoints.
- Install:
sudo apt-get install -y fail2ban
- Create a jail for Nginx:
# /etc/fail2ban/jail.d/nginx.conf [nginx-http-auth] enabled = true filter = nginx-http-auth logpath = /var/log/nginx/error.log maxretry = 3 bantime = 86400 findtime = 600
- Restart the service:
sudo systemctl restart fail2ban
Fail2Ban will now monitor the error log for authentication failures and block offending IPs via iptables.
6. Restrict Access to Sensitive Locations
Never expose the Nginx status page or internal APIs to the public internet. Use allow
/deny
directives or IP‑based ACLs.
location /nginx_status { stub_status; allow 127.0.0.1; deny all; }
Similarly, protect /admin
or /api
endpoints with basic auth or OAuth, and always limit them to known client IP ranges.
7. Enable Logging and Centralized Monitoring
Security is only as good as your ability to detect anomalies. Configure Nginx to log in JSON format and ship logs to a centralized system like ELK or Grafana Loki.
log_format json '{"time":"$time_iso8601",' '"remote_addr":"$remote_addr",' '"request":"$request",' '"status":$status, ' '"body_bytes_sent":$body_bytes_sent, ' '"http_referrer":"$http_referer",' '"http_user_agent":"$http_user_agent"}'; access_log /var/log/nginx/access.json json;
Feed the logs into your SIEM of choice and set alerts for spikes in 4xx/5xx responses.
Putting It All Together
Below is a minimal but complete server block that incorporates the hardening steps discussed:
server { listen 80 default_server; listen [::]:80 default_server; server_name example.com www.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name example.com www.example.com; # TLS configuration (ssl.conf is included) include /etc/nginx/conf.d/ssl.conf; # HSTS header add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; root /var/www/html; index index.html index.htm; location / { try_files $uri $uri/ =404; } # Restrict status page location /nginx_status { stub_status; allow 127.0.0.1; deny all; } }
Deploy the configuration, test with nginx -t
, and reload:
sudo nginx -t && sudo systemctl reload nginx
Conclusion
Hardening Nginx is a layered process: enforce modern TLS, lock down the OS firewall, automate certificate management, and add reactive defenses like Fail2Ban. By following these seven tips you’ll significantly reduce the attack surface of your web tier while keeping operational overhead low. For deeper dives into Nginx security patterns and managed hosting options, you might find the resources at https://lacidaweb.com helpful.
Top comments (0)