Introduction
As a DevOps lead, you know that a mis‑configured web server is an open invitation to attackers. Nginx is fast and flexible, but out‑of‑the‑box it lacks the hardened defaults you need for production. This checklist walks you through the essential steps to lock down Nginx on Ubuntu, covering TLS, firewall rules, fail2ban, and basic OS hardening. Follow each item, test, and you’ll dramatically reduce your attack surface.
1. Update the OS and Install Required Packages
sudo apt update && sudo apt upgrade -y
sudo apt install nginx ufw fail2ban -y
- Keep the kernel and packages patched – set up unattended upgrades if you haven’t already.
- Install
certbot
for automated Let's Encrypt certificates:
sudo apt install certbot python3-certbot-nginx -y
2. Harden the Underlying Linux System
2.1 Disable Unused Services
sudo systemctl list-unit-files --type=service | grep enabled
# Example: disable telnet, ftp, etc.
sudo systemctl disable telnet.service
2.2 Enforce Strong Password Policies
Edit /etc/pam.d/common-password
and set:
password requisite pam_pwquality.so retry=3 minlen=12 difok=4
2.3 Enable Automatic Security Updates
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure unattended-upgrades
3. Configure the Firewall (UFW)
Only allow the ports you need. For a typical HTTPS‑only site:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh # 22 (or custom SSH port)
sudo ufw allow http # 80 (optional, for HTTP→HTTPS redirect)
sudo ufw allow https # 443
sudo ufw enable
Verify:
sudo ufw status verbose
4. Obtain and Harden TLS Certificates
4.1 Get a Free Certificate with Certbot
sudo certbot --nginx -d example.com -d www.example.com
Certbot will automatically edit your Nginx config to use the new certs and set up a renewal timer.
4.2 Enforce Strong Cipher Suites
Edit the server block (or create /etc/nginx/snippets/ssl-params.conf
):
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305";
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
Include the snippet in each server block:
server {
listen 443 ssl http2;
server_name example.com www.example.com;
include snippets/ssl-params.conf;
# ... other directives ...
}
4.3 Test Your TLS Configuration
Run sslscan
or use the Qualys SSL Labs test. Aim for an A+ rating.
5. Harden Nginx Itself
- Disable Unused Modules – compile Nginx with only needed modules if you control the build.
- Limit Request Size – prevent buffer overflow attacks:
client_max_body_size 2M;
- Rate Limit Connections – mitigate brute‑force attempts:
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
limit_req zone=one burst=20 nodelay;
- Hide Nginx Version:
server_tokens off;
6. Deploy Fail2Ban for Nginx Logs
Create /etc/fail2ban/filter.d/nginx-http-auth.conf
(if using HTTP auth) or reuse the existing nginx-http-auth
filter.
Then add a jail in /etc/fail2ban/jail.local
:
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600
Restart Fail2Ban:
sudo systemctl restart fail2ban
sudo fail2ban-client status nginx-http-auth
7. Enable HTTP Strict Transport Security (HSTS) Preload
The add_header Strict-Transport-Security
line from the TLS snippet already includes preload
. Submit your domain to the HSTS preload list for browsers to enforce HTTPS even on first contact.
8. Set Up Automated Certificate Renewal Monitoring
Certbot creates a systemd timer, but you should verify it works:
sudo systemctl list-timers | grep certbot
sudo certbot renew --dry-run
Consider adding a simple health‑check script that alerts you if renewal fails.
9. Verify the Entire Stack
-
Port Scan –
nmap -sS -p 80,443 <your‑ip>
should show only 443 open (if you disabled HTTP). -
Header Inspection –
curl -I https://example.com
and confirm security headers. -
Log Review –
sudo tail -f /var/log/nginx/access.log
while you browse to catch any 4xx/5xx anomalies.
10. Ongoing Maintenance Checklist
- [ ] Apply OS security patches weekly.
- [ ] Review UFW rules after any new service deployment.
- [ ] Rotate TLS keys every 12‑18 months.
- [ ] Audit Fail2Ban bans monthly to adjust thresholds.
- [ ] Run SSL Labs test after each Nginx config change.
Conclusion
Securing Nginx is a layered effort: keep the OS patched, lock down the network with a firewall, enforce strong TLS, and add runtime guards like Fail2Ban. By ticking off each item in this checklist you’ll move from a default installation to a production‑grade, hardened web server.
If you need a quick, reliable hosting environment that already follows many of these best practices, consider checking out https://lacidaweb.com for managed solutions tailored to developers.
Top comments (0)