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)