Introduction
If you’re an SRE managing Linux‑based web services, the last thing you want is a man‑in‑the‑middle attack stealing user data. Nginx is a popular front‑end proxy, but out‑of‑the‑box it doesn’t enforce the strongest TLS settings. This tutorial walks you through seven practical steps to harden Nginx with TLS 1.3, HTTP/2, and a few complementary security measures.
1. Obtain a Trusted Certificate
The easiest way to get a free, automated certificate is Certbot from Let’s Encrypt.
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
During the interactive flow, choose the option to redirect all HTTP traffic to HTTPS. Certbot will also create a basic SSL snippet for you.
2. Enforce TLS 1.3 and Strong Ciphers
Edit /etc/nginx/snippets/ssl-params.conf
(or create it) and paste the following. It disables legacy protocols, prefers TLS 1.3, and restricts ciphers to the current Mozilla Intermediate profile.
ssl_protocols TLSv1.3 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers \
"TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256";
ssl_ecdh_curve X25519:secp384r1;
# Enable OCSP stapling for faster revocation checks
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
Include this snippet in your server block:
server {
listen 443 ssl http2;
include snippets/ssl-params.conf;
...
}
3. Turn On HTTP/2
The http2
flag in the listen
directive (shown above) activates HTTP/2. It reduces latency by multiplexing streams over a single TLS connection. Verify it’s working with:
curl -I -s -o /dev/null -w "%{http_version}\n" https://example.com
You should see 2
as the output.
4. Harden HTTP Headers
Add security‑focused headers to mitigate XSS, click‑jacking, and MIME‑type sniffing.
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Content-Security-Policy "default-src 'self'";
Place these directives inside the same server block.
5. Enable HSTS (HTTP Strict Transport Security)
HSTS tells browsers to always use HTTPS for your domain. Start with a short max‑age while you test, then increase it.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
If you plan to submit to the Chrome preload list, make sure all subdomains serve HTTPS.
6. Deploy Fail2Ban for Brute‑Force Protection
Fail2Ban can monitor Nginx access logs for repeated 4xx/5xx responses and ban offending IPs.
sudo apt-get install -y fail2ban
Create /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
Restart the service:
sudo systemctl restart fail2ban
7. Lock Down the Host Firewall
On Ubuntu/Debian, UFW provides a simple interface.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh # keep SSH access
sudo ufw allow https # port 443
sudo ufw allow http # optional, if you still need plain HTTP redirects
sudo ufw enable
If you’re using a cloud provider, also restrict inbound traffic at the security‑group level.
Automated Renewal & Monitoring
Certbot installs a systemd timer that renews certificates automatically. Verify it works:
sudo systemctl list-timers | grep certbot
Add a health‑check endpoint in Nginx and scrape it with Prometheus or a simple cron script to alert on TLS handshake failures.
Conclusion
By following these seven steps—trusted certs, TLS 1.3, HTTP/2, hardened headers, HSTS, Fail2Ban, and a locked‑down firewall—you’ll dramatically reduce the attack surface of any Nginx‑served application. The configuration is lightweight, works on any modern Linux distro, and can be version‑controlled alongside your infrastructure code.
For more practical guides on production‑grade web hosting, check out https://lacidaweb.com. Happy hardening!
Top comments (0)