DEV Community

Ramer Labs
Ramer Labs

Posted on

7 Tips for Securing Nginx with TLS and Fail2Ban on Ubuntu Servers

Introduction

If you’re an SRE managing web traffic on Ubuntu, you’ve probably seen the headache that comes with brute‑force attacks, outdated cipher suites, and misconfigured firewalls. Nginx is a rock‑solid reverse proxy, but out‑of‑the‑box it isn’t hardened for the hostile internet. This tutorial walks you through seven practical steps to lock down Nginx using TLS, a strict firewall, and Fail2Ban. By the end you’ll have a server that not only serves content fast, but also survives the most common attack vectors.


1. Keep the OS and Packages Updated

Security starts with a clean foundation. On Ubuntu, enable unattended upgrades for critical patches:

sudo apt-get install unattended-upgrades sudo dpkg-reconfigure --priority=low unattended-upgrades 
Enter fullscreen mode Exit fullscreen mode

Make sure the unattended-upgrades config includes the -security repo. Regularly verify with:

sudo unattended-upgrade --dry-run --debug 
Enter fullscreen mode Exit fullscreen mode

2. Install Nginx from the Official Repository

Avoid third‑party PPAs; they may lag behind security patches. Install the latest stable release:

sudo apt-get update sudo apt-get install nginx 
Enter fullscreen mode Exit fullscreen mode

After installation, lock the version to prevent accidental downgrades:

sudo apt-mark hold nginx 
Enter fullscreen mode Exit fullscreen mode

3. Obtain a Strong TLS Certificate

Let’s Encrypt offers free, automatically renewing certificates. Install certbot and request a certificate for your domain:

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

During the interactive flow, select "Redirect HTTP to HTTPS". Certbot will also create a robust Nginx snippet that enforces modern TLS settings.


4. Harden the Nginx TLS Configuration

Even with Let’s Encrypt, you should audit the cipher suite and protocol list. Replace the default snippet (/etc/nginx/snippets/ssl-params.conf) with the following hardened version:

# /etc/nginx/snippets/ssl-params.conf ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers \ "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; ssl_ecdh_curve secp384r1; ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; ssl_stapling on; ssl_stapling_verify on; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY; add_header X-XSS-Protection "1; mode=block"; 
Enter fullscreen mode Exit fullscreen mode

Include this snippet in your server block:

server { listen 443 ssl http2; include snippets/ssl-params.conf; ... } 
Enter fullscreen mode Exit fullscreen mode

Reload Nginx:

sudo systemctl reload nginx 
Enter fullscreen mode Exit fullscreen mode

5. Restrict Access with UFW (Uncomplicated Firewall)

A minimal firewall reduces the attack surface. Allow only HTTP/HTTPS, SSH (restricted to a specific IP range), and Fail2Ban’s ssh jail:

sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp sudo ufw enable 
Enter fullscreen mode Exit fullscreen mode

Check the status:

sudo ufw status verbose 
Enter fullscreen mode Exit fullscreen mode

6. Deploy Fail2Ban to Thwart Brute‑Force Attempts

Fail2Ban monitors log files and bans offending IPs. Install and enable the service:

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

Create a local jail configuration (/etc/fail2ban/jail.local) that protects both SSH and Nginx:

[sshd] enabled = true port = ssh logpath = %(sshd_log)s maxretry = 5 bantime = 1h [nginx-http-auth] enabled = true port = http,https filter = nginx-http-auth logpath = /var/log/nginx/error.log maxretry = 3 bantime = 2h 
Enter fullscreen mode Exit fullscreen mode

The nginx-http-auth filter is shipped with Fail2Ban and watches for 401 responses. Restart the daemon:

sudo systemctl restart fail2ban 
Enter fullscreen mode Exit fullscreen mode

You can view bans with:

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

7. Automate Certificate Renewal and Nginx Reload

Let’s Encrypt certificates expire after 90 days. Certbot installs a systemd timer, but verify it works:

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

If you prefer a manual cron job, add this line to /etc/crontab:

0 3 * * * root certbot renew --quiet --post-hook "systemctl reload nginx" 
Enter fullscreen mode Exit fullscreen mode

Now the server will automatically fetch a fresh cert and reload Nginx without human intervention.


Monitoring and Logging

A hardened server is only as good as its visibility. Install ufw and fail2ban logs into a central syslog server, or use a lightweight stack like rsyslog + logrotate. Example logrotate snippet for Nginx:

/var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 www-data adm sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` endscript } 
Enter fullscreen mode Exit fullscreen mode

Conclusion

By following these seven steps—regular updates, strong TLS, a tight firewall, and Fail2Ban—you’ll dramatically reduce the risk of common web‑server attacks while keeping performance intact. Remember to test your configuration with tools like SSL Labs and fail2ban-client to verify that bans are applied as expected.

If you need a quick sanity‑check or want to explore more advanced hardening patterns, the team at https://lacidaweb.com offers practical guides and community support for Linux‑based web stacks.

Top comments (0)