7 Tips for Securing Your Nginx Server with TLS and Fail2Ban



This content originally appeared on DEV Community and was authored by Ramer Labs

Introduction

Running a public web service on Nginx is great for performance, but it also makes you a target. A single mis‑configuration can expose sensitive data or open the door to brute‑force attacks. This guide walks you through a practical checklist to harden an Nginx instance on a Linux server using TLS, a strict firewall, Fail2Ban, and automated backups. The steps are written for a DevOps lead who wants reproducible, auditable security.

1. Enforce TLS with Modern Cipher Suites

TLS is the first line of defense. Use letsencrypt for free certificates, but the real work is in the Nginx configuration.

# /etc/nginx/conf.d/ssl.conf
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;

    # Only TLS 1.2+ and strong ciphers
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH";

    # 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;

    # HSTS – tell browsers to always use HTTPS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Your usual location blocks go here
}
  • Why these settings? TLS 1.2 and 1.3 drop legacy protocols vulnerable to POODLE and BEAST. The cipher list favours forward secrecy (ECDHE) and AEAD encryption (AES‑GCM). HSTS prevents downgrade attacks.

2. Redirect All HTTP Traffic to HTTPS

A simple server block catches plain HTTP and issues a 301 redirect.

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

3. Harden the Firewall (UFW Example)

Only expose ports you need. For a typical web stack, that’s 80, 443, and 22 (SSH). Block everything else.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp      # SSH – consider limiting to your IP range
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Tip: Use ufw status numbered to verify the rule order. Consider moving SSH to a non‑standard port or using key‑based auth only.

4. Deploy Fail2Ban to Thwart Brute‑Force Attempts

Fail2Ban watches Nginx logs for repeated 4xx/5xx responses and bans the offending IP via iptables.

# /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  ; 1 hour

Create the matching filter (/etc/fail2ban/filter.d/nginx-http-auth.conf):

[Definition]
failregex = ^<HOST> -.*"GET .* HTTP/.*" 401
            ^<HOST> -.*"POST .* HTTP/.*" 401

Restart Fail2Ban:

sudo systemctl restart fail2ban
sudo fail2ban-client status nginx-http-auth

5. Secure SSH Access

  • Disable password authentication: PasswordAuthentication no
  • Enforce key‑based login: PubkeyAuthentication yes
  • Limit users: AllowUsers deploy
  • Optional: Use AllowTcpForwarding no and PermitRootLogin no.

Apply changes with systemctl reload sshd.

6. Automated Backups of Certs and Configs

A broken TLS chain is worse than a compromised server. Use rsnapshot or a simple cron job to copy /etc/nginx/, /etc/letsencrypt/, and /etc/fail2ban/ to a remote storage bucket.

# /etc/cron.daily/nginx-backup
#!/bin/bash
TIMESTAMP=$(date +%F)
DEST="s3://my-backup-bucket/nginx-$TIMESTAMP/"
aws s3 sync /etc/nginx $DEST/nginx --delete
aws s3 sync /etc/letsencrypt $DEST/letsencrypt --delete
aws s3 sync /etc/fail2ban $DEST/fail2ban --delete

Rotate backups with a lifecycle policy (e.g., keep 30 days).

7. Keep the System Patched Automatically

On Debian/Ubuntu, enable unattended upgrades for security patches:

sudo apt-get install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

For Red Hat/CentOS, use yum-cron:

sudo yum install yum-cron
sudo systemctl enable --now yum-cron

Regularly audit the /var/log/unattended-upgrades/ directory to ensure updates are applied.

Monitoring and Alerting

Combine Nginx status metrics with Fail2Ban bans in a Prometheus + Grafana stack. A simple exporter can expose nginx_upstream_response_time and fail2ban_banned_ips. Set alerts for:

  • TLS certificate expiration within 30 days.
  • Sudden spikes in 4xx/5xx errors.
  • New IP bans exceeding a threshold.

Conclusion

Hardening Nginx is a layered effort: TLS configuration, firewall rules, intrusion‑prevention with Fail2Ban, and disciplined backup and patch processes. By following these seven steps you’ll dramatically reduce the attack surface while keeping your web service performant and reliable. For more hands‑on tutorials and community‑driven best practices, check out https://lacidaweb.com.


This content originally appeared on DEV Community and was authored by Ramer Labs