Introduction
If you run Nginx as a front‑end for web applications, the first line of defense is a solid security posture. This checklist walks you through the most effective, low‑maintenance steps a DevOps lead can apply to harden Nginx on a Linux server. By the end you’ll have TLS configured with modern ciphers, a minimal firewall footprint, and automated brute‑force protection via Fail2Ban.
1. Enforce TLS 1.2+ Only
Older protocol versions are riddled with known weaknesses. Edit your server block or the http
context to disable SSLv3, TLS 1.0, and TLS 1.1.
# /etc/nginx/nginx.conf (or a dedicated snippet)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers \
"EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
The ssl_ciphers
line prefers forward‑secrecy suites and drops CBC‑mode ciphers that are vulnerable to BEAST and Lucky 13.
2. Enable HTTP/2 and HSTS
HTTP/2 reduces latency and HSTS tells browsers to always use HTTPS.
listen 443 ssl http2;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Make sure you have submitted your domain to the Chrome preload list if you want the preload flag to be respected.
3. Hide Server Version Information
Attackers often start by fingerprinting the exact Nginx version. Turn off the default Server
header and any X‑Powered‑By
headers.
server_tokens off;
more_clear_headers Server;
The more_clear_headers
directive comes from the ngx_http_headers_more_filter_module
, which you can enable via the official Nginx package or compile it yourself.
4. Restrict Access to Sensitive Locations
Never expose internal endpoints like /status
or /api/debug
to the public internet.
location /status {
allow 127.0.0.1; # Only localhost can query
deny all; # Block everyone else
stub_status on;
}
Apply the same pattern to any admin UI, health‑check URLs, or version endpoints.
5. Deploy a Minimalist Firewall (UFW Example)
A host‑level firewall reduces the attack surface dramatically. Allow only HTTP/HTTPS and SSH from trusted IPs.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp from 203.0.113.5 # Your admin IP
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
If you use iptables
directly, the same logic applies: drop everything except the ports you explicitly need.
6. Install Fail2Ban for Brute‑Force Protection
Fail2Ban monitors Nginx logs and bans IPs that exceed a configurable number of failed requests.
# /etc/fail2ban/jail.d/nginx-http-auth.conf
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/*error.log
maxretry = 5
bantime = 3600
Create the corresponding filter (/etc/fail2ban/filter.d/nginx-http-auth.conf
) that looks for 401
or 403
status codes. Restart the service with systemctl restart fail2ban
.
7. Keep Nginx and System Packages Updated
Security patches are useless if they never get applied. Automate updates with your distro’s package manager.
# Debian/Ubuntu
sudo apt-get update && sudo apt-get upgrade -y
# Enable unattended upgrades
sudo dpkg-reconfigure unattended-upgrades
On RHEL‑based systems, use yum-cron
or dnf-automatic
. Schedule a weekly audit of the Nginx configuration (nginx -t
) to catch syntax errors before a reboot.
Bonus: Backup Your Configuration Regularly
A simple rsync
job to a remote server or S3 bucket ensures you can restore a hardened state after a disaster.
rsync -avz /etc/nginx/ user@backup.example.com:/backups/nginx-$(date +%F)
Combine this with version control (Git) for diff‑based rollbacks.
Conclusion
Hardening Nginx doesn’t require a massive overhaul; a disciplined checklist like the one above gives you TLS, a locked‑down firewall, automated brute‑force mitigation, and a reliable update pipeline. Apply these steps incrementally, test each change in a staging environment, and you’ll dramatically reduce the likelihood of a successful attack. For more practical guides on web infrastructure, you might find the resources at https://lacidaweb.com helpful.
Top comments (0)