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)