Introduction
If you’re a DevOps lead responsible for public‑facing services, Nginx is probably the front‑line web server or reverse proxy in your stack. While it’s lightning‑fast, a mis‑configured instance can become an easy target for attackers. This tutorial walks you through a practical, step‑by‑step hardening checklist that covers TLS best practices, firewall rules, and a few often‑overlooked Linux tweaks.
1. Obtain a Strong TLS Certificate
Use Let’s Encrypt for Automation
# Install certbot (Debian/Ubuntu example) sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx # Request a certificate for example.com and www.example.com sudo certbot --nginx -d example.com -d www.example.com
- Certbot automatically edits your Nginx config to enable HTTPS.
- It also sets up a systemd timer for automatic renewal.
Prefer ECDSA Over RSA
If your client base includes modern browsers, generate an ECDSA key for better performance:
sudo openssl ecparam -genkey -name secp384r1 -out /etc/ssl/private/example.com.key sudo openssl req -new -key /etc/ssl/private/example.com.key -out /etc/ssl/csr/example.com.csr # Then use certbot with the --key-type ecdsa flag sudo certbot --nginx --key-type ecdsa -d example.com -d www.example.com
2. Harden the Nginx TLS Configuration
Create a dedicated snippet called ssl-strong.conf
and include it in your server blocks.
# /etc/nginx/snippets/ssl-strong.conf 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; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY; add_header X-XSS-Protection "1; mode=block";
Then reference it:
server { listen 443 ssl http2; server_name example.com www.example.com; include snippets/ssl-strong.conf; # …rest of config… }
3. Enable HTTP/2 and Brotli Compression
HTTP/2 reduces latency, while Brotli offers better compression ratios than gzip.
# Enable HTTP/2 in the listen directive (already shown above) # Install Brotli module (Debian example) sudo apt-get install -y nginx-module-brotli # Add Brotli settings brotli on; brotli_comp_level 6; brotli_types text/plain text/css application/javascript application/json image/svg+xml;
4. Restrict Access with a Host‑Based Firewall
Using UFW (Uncomplicated Firewall)
sudo ufw default deny incoming sudo ufw default allow outgoing # Allow SSH (limit to 5 attempts per minute) sudo ufw limit 22/tcp # Allow HTTP/HTTPS sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable
Fine‑Grained iptables Example
If you need more control, drop traffic from known malicious IP ranges:
# Block a CIDR (example) sudo iptables -A INPUT -s 185.220.101.0/24 -j DROP # Log and drop malformed packets sudo iptables -A INPUT -p tcp --tcp-flags ALL NONE -j LOG --log-prefix "[DROP NULL] " sudo iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
Persist rules with iptables-persistent
or netfilter-persistent
.
5. Deploy Fail2Ban for Brute‑Force Protection
Fail2Ban monitors log files and bans IPs that show malicious signs.
sudo apt-get install -y fail2ban
Create a custom jail for Nginx:
# /etc/fail2ban/jail.d/nginx-http-auth.conf [nginx-http-auth] enabled = true filter = nginx-http-auth logpath = /var/log/nginx/error.log maxretry = 3 bantime = 3600
The built‑in nginx-http-auth
filter catches repeated 401 responses.
6. Secure File Permissions and Ownership
# Nginx binary and config files should be owned by root:root sudo chown -R root:root /etc/nginx sudo chmod -R 644 /etc/nginx/*.conf sudo chmod 600 /etc/ssl/private/*.key # Serve static content with a non‑privileged user (www-data) sudo chown -R www-data:www-data /var/www/html
Avoid running Nginx as root; the master process runs as root only to bind privileged ports, while workers run as www-data
.
7. Automate Monitoring and Renewal
SSL Certificate Renewal
Certbot already creates a systemd timer, but verify it:
systemctl list-timers | grep certbot
Health Checks
Add a simple /healthz
endpoint that returns 200 OK
:
location = /healthz { access_log off; return 200 "OK"; add_header Content-Type text/plain; }
Integrate this endpoint with your monitoring stack (Prometheus node exporter, UptimeRobot, etc.) to get instant alerts if Nginx crashes.
Conclusion
Hardening Nginx is a combination of cryptographic hygiene, network‑level gating, and disciplined operational practices. By following these seven tips—obtaining a strong TLS certificate, tightening cipher suites, enabling HTTP/2 and Brotli, locking down the firewall, adding Fail2Ban, tightening file permissions, and automating monitoring—you’ll dramatically reduce the attack surface of any web service.
If you’re looking for a reliable partner to review your Nginx hardening checklist or need hands‑on assistance with cloud‑native deployments, consider checking out https://lacidaweb.com for practical guidance and support.
Top comments (0)