Overview
Running Nginx in a production environment means you’re the front line of your web traffic. A mis‑configured server can expose sensitive data, invite DDoS attacks, or leak internal version numbers. This checklist walks a DevOps lead through the essential hardening steps—TLS, firewall rules, and a few often‑overlooked tweaks—so you can lock down the stack without sacrificing performance.
1️⃣ Get a Valid TLS Certificate
A self‑signed cert is fine for internal testing, but browsers and API clients expect a trusted certificate chain. The easiest way to obtain one is Let’s Encrypt:
# Install Certbot (Debian/Ubuntu example) sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx # Request a cert for example.com and www.example.com sudo certbot --nginx -d example.com -d www.example.com
Certbot will automatically edit your Nginx config, add a listen 443 ssl;
block, and set up a renewal cron job. Verify renewal works with sudo certbot renew --dry-run
.
2️⃣ Harden SSL/TLS Settings
Modern browsers support TLS 1.3, which offers better security and lower latency. Disable older protocols and weak ciphers in a dedicated ssl.conf
snippet:
# /etc/nginx/snippets/ssl.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"; # Enable HTTP/2 for speed listen 443 ssl http2; # HSTS (force HTTPS for a year) add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # OCSP stapling ssl_stapling on; ssl_stapling_verify on;
Include the snippet in each server block: include snippets/ssl.conf;
. Remember to reload Nginx after changes: sudo systemctl reload nginx
.
3️⃣ Hide Server Identity
By default Nginx reveals its version in the Server
header, which gives attackers a foothold for known exploits. Turn it off and replace it with a generic value:
# In http { } server_tokens off; more_clear_headers Server; # requires ngx_headers_more module
If you don’t have ngx_headers_more
, you can simply set server_tokens off;
—most scanners will still see nginx
but not the exact version.
4️⃣ Implement Host‑Based Firewall Rules
A properly scoped firewall blocks everything except the ports you actually need. On Ubuntu/Debian, ufw
is straightforward:
sudo ufw default deny incoming sudo ufw default allow outgoing # Allow HTTP/HTTPS from anywhere sudo ufw allow 80/tcp sudo ufw allow 443/tcp # SSH limited to your admin IP (replace with your IP) sudo ufw allow from 203.0.113.42 to any port 22 proto tcp # Enable the firewall sudo ufw enable
If you’re on a cloud provider, also lock down the security group to the same ports.
5️⃣ Deploy Fail2Ban for Brute‑Force Protection
Fail2Ban watches Nginx logs for repeated 4xx/5xx patterns and bans the offending IP via iptables
. Install and enable a ready‑made filter:
sudo apt-get install -y fail2ban # Create a jail for Nginx HTTP auth failures cat <<EOF | sudo tee /etc/fail2ban/jail.d/nginx-http-auth.conf [nginx-http-auth] enabled = true filter = nginx-http-auth logpath = /var/log/nginx/error.log maxretry = 5 bantime = 3600 EOF sudo systemctl restart fail2ban
You can add custom filters for rate‑limit bypass attempts or malformed request strings.
6️⃣ Enable Rate Limiting at the Server Level
Even with a firewall, a sudden spike can overwhelm your upstream services. Nginx’s limit_req_zone
and limit_req
directives throttle abusive clients:
# Define a shared memory zone (10 MB can hold ~160k states) limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; server { listen 443 ssl http2; ... location /api/ { limit_req zone=mylimit burst=20 nodelay; proxy_pass http://backend; } }
Adjust rate
and burst
based on your traffic profile. Combine with limit_conn
if you need to cap concurrent connections per IP.
7️⃣ Test, Monitor, and Iterate
Hardening is a continuous process. Use these tools to verify you didn’t break anything:
- SSL Labs – Run a quick external scan of your domain to confirm protocol/cipher settings.
- curl – Check headers locally:
curl -I https://example.com
should showStrict-Transport-Security
and noServer
version. - Prometheus + Grafana – Export Nginx metrics (
stub_status
) and watch for spikes in 4xx/5xx rates. - Logwatch – Set up daily summaries of firewall denials and Fail2Ban bans.
When you spot a false positive (e.g., a legitimate IP getting blocked), fine‑tune the maxretry
or whitelist the address in /etc/fail2ban/jail.local
.
Wrap‑up
By following these seven steps—trusted TLS, stripped server fingerprints, tight firewall rules, automated brute‑force mitigation, and smart rate limiting—you’ll dramatically reduce the attack surface of any Nginx‑powered service. Remember, security is a habit, not a one‑time checklist. For deeper dives into Linux hardening and cloud‑native monitoring, you might find the resources at https://lacidaweb.com useful as you continue to refine your production pipeline.
Top comments (0)