DEV Community

Ramer Lacida
Ramer Lacida

Posted on

Security Hardening for Nginx: TLS, Firewalls, and Fail2Ban Basics

Why Nginx Needs a Security Overhaul

Even though Nginx is renowned for speed and reliability, a default installation leaves a lot of attack surface exposed. As an SRE you’ll quickly discover that a few configuration tweaks, firewall rules, and a lightweight intrusion‑prevention tool like Fail2Ban can turn a plain HTTP server into a hardened, production‑ready gateway.

In this guide we’ll walk through:

  • Enforcing strong TLS with modern ciphers.
  • Locking down the network layer using ufw.
  • Deploying Fail2Ban to block brute‑force attempts.
  • Automating certificate renewal with Certbot.

All steps are reproducible on any recent Ubuntu or Debian box.


1. Harden TLS – The First Line of Defense

1.1 Install Certbot and Obtain a Certificate

sudo apt update && sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
Enter fullscreen mode Exit fullscreen mode

The wizard will ask you whether to redirect HTTP to HTTPS – choose Redirect. Certbot also creates a cron job for renewal, but it’s good practice to verify it:

sudo systemctl list-timers | grep certbot
Enter fullscreen mode Exit fullscreen mode

1.2 Tighten the Nginx SSL Block

Replace the default server { … } block with a hardened version. The snippet below forces TLS 1.2/1.3, disables weak ciphers, and adds HSTS (30‑day max‑age for testing).

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # TLS protocols – only modern versions
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers \
        "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";

    # HSTS – start with 30 days, increase later
    add_header Strict-Transport-Security "max-age=2592000; includeSubDomains" always;

    # OCSP stapling improves handshake latency
    ssl_stapling on;
    ssl_stapling_verify on;

    # Optional: enable TLS session tickets
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    location / {
        proxy_pass http://localhost:3000; # your app upstream
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
Enter fullscreen mode Exit fullscreen mode

Key takeaways

  • ssl_protocols drops TLS 1.0/1.1.
  • The cipher suite favours forward secrecy.
  • HSTS tells browsers to always use HTTPS.
  • OCSP stapling reduces round‑trips during the TLS handshake.

After editing, test the config and reload:

sudo nginx -t && sudo systemctl reload nginx
Enter fullscreen mode Exit fullscreen mode

2. Lock Down the Network with a Minimal Firewall

A well‑configured firewall blocks everything except the ports you explicitly need. For a typical web service you only need 80 (HTTP) and 443 (HTTPS). ufw (Uncomplicated Firewall) provides a clean syntax.

# Reset any existing rules
sudo ufw reset

# Default deny inbound, allow all outbound
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Open HTTP and HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Optional: SSH for remote management (limit to a trusted subnet)
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp

# Enable the firewall
sudo ufw enable
Enter fullscreen mode Exit fullscreen mode

Verify the active profile:

sudo ufw status verbose
Enter fullscreen mode Exit fullscreen mode

If you ever need to troubleshoot, ufw logging on will start recording dropped packets to /var/log/ufw.log.


3. Deploy Fail2Ban – Automated Brute‑Force Protection

Fail2Ban monitors log files for suspicious patterns and bans offending IPs via firewall rules. It’s especially useful for protecting Nginx from repeated 404 or malformed request attacks.

3.1 Install and Enable Fail2Ban

sudo apt install -y fail2ban
sudo systemctl enable fail2ban
Enter fullscreen mode Exit fullscreen mode

3.2 Create a Custom Jail for Nginx

Copy the default configuration and add a jail that watches the Nginx access log for repeated 404s.

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Enter fullscreen mode Exit fullscreen mode

Edit /etc/fail2ban/jail.local and append:

[nginx-http-404]
enabled = true
filter = nginx-http-404
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 600
bantime = 3600
Enter fullscreen mode Exit fullscreen mode

The accompanying filter lives in /etc/fail2ban/filter.d/nginx-http-404.conf:

[Definition]
failregex = ^<HOST> -.*"GET .*" 404
ignoreregex =
Enter fullscreen mode Exit fullscreen mode

Restart the service to apply changes:

sudo systemctl restart fail2ban
Enter fullscreen mode Exit fullscreen mode

You can check the jail status with:

sudo fail2ban-client status nginx-http-404
Enter fullscreen mode Exit fullscreen mode

3.3 Fine‑Tune Bans

  • maxretry: number of 404s before a ban.
  • findtime: window (seconds) to count retries.
  • bantime: how long the IP stays blocked.

Adjust these values based on your traffic pattern. For APIs you might want a stricter policy, whereas a public blog could tolerate a higher maxretry.


4. Validate Your Hardening Efforts

4.1 SSL Labs Test

Run a free SSL Labs assessment: https://www.ssllabs.com/ssltest/. Aim for an A rating. If you see “Cipher ordering” or “Protocol support” warnings, revisit the ssl_ciphers line.

4.2 Firewall Audits

List the active ufw rules and ensure only the intended ports are open:

sudo ufw status numbered
Enter fullscreen mode Exit fullscreen mode

4.3 Fail2Ban Logs

Inspect /var/log/fail2ban.log for ban events. A healthy system will show occasional bans for bots probing /wp-admin or trying SSH brute‑force attacks.


5. Ongoing Maintenance Checklist

  • Renew certificates: certbot renew --dry-run should succeed daily.
  • Update packages: sudo apt update && sudo apt upgrade -y at least weekly.
  • Review cipher suite: Keep an eye on emerging vulnerabilities (e.g., POODLE, BEAST).
  • Rotate Fail2Ban filters: Add new patterns as you discover novel attack vectors.
  • Backup Nginx config: Store /etc/nginx/ in a version‑controlled repo.

By treating security as a repeatable process rather than a one‑off task, you’ll keep the surface area minimal while preserving the performance Nginx is famous for.


Final Thoughts

Hardening Nginx doesn’t require a massive rewrite; a handful of focused changes—TLS tightening, a minimal firewall, and Fail2Ban—provide a solid defensive baseline. For teams looking for a quick, reliable way to audit and improve their web‑server posture, the steps above are a great starting point. If you need a managed solution that handles these details for you, consider checking out https://lacidaweb.com for a no‑hassle option.

Top comments (0)