DEV Community

Ramer Labs
Ramer Labs

Posted on

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

Introduction

If you’re an SRE or a DevOps lead managing web traffic on Ubuntu servers, you’ve probably heard the mantra "Lock it down before it locks you down". Nginx is a popular front‑end web server, but its default installation leaves a lot of attack surface exposed. In this practical guide we’ll walk through seven concrete steps to harden Nginx with strong TLS settings and a Fail2Ban shield against brute‑force attacks. By the end you’ll have a reproducible, auditable configuration that you can roll out across your fleet.


1. Keep the System Updated

Security starts at the OS level. Run the following commands after every reboot or as part of your CI/CD pipeline:

sudo apt update && sudo apt upgrade -y sudo apt install unattended-upgrades sudo dpkg-reconfigure --priority=low unattended-upgrades 
Enter fullscreen mode Exit fullscreen mode

Enabling unattended upgrades ensures that critical patches (including OpenSSL updates) are applied automatically.


2. Install Only Required Nginx Modules

A lean binary reduces the code you need to audit. Install the core package plus the http_ssl_module:

sudo apt install nginx-core libnginx-mod-http-ssl 
Enter fullscreen mode Exit fullscreen mode

Avoid the nginx-full meta‑package unless you truly need extra modules like mail or stream.


3. Enforce Strong TLS Settings

Create a dedicated snippet that you can include in any server block. Save it as /etc/nginx/snippets/strong-ssl.conf:

# /etc/nginx/snippets/strong-ssl.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"; 
Enter fullscreen mode Exit fullscreen mode

Then reference it in your site config:

server { listen 443 ssl http2; server_name example.com; include snippets/strong-ssl.conf; # ... other directives ... } 
Enter fullscreen mode Exit fullscreen mode

Run nginx -t and reload:

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

4. Use a Dedicated TLS Certificate Provider

Let’s Encrypt is free and automated, but for production you may want a paid CA that offers OCSP stapling and extended validation. Whichever you choose, store the private key outside the web root and set strict permissions:

sudo chown root:root /etc/ssl/private/example.key sudo chmod 600 /etc/ssl/private/example.key 
Enter fullscreen mode Exit fullscreen mode

5. Deploy Fail2Ban to Throttle Malicious Requests

Fail2Ban monitors log files and bans IPs that exceed defined thresholds. Install it and create a jail for Nginx:

sudo apt install fail2ban 
Enter fullscreen mode Exit fullscreen mode

Create /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 
Enter fullscreen mode Exit fullscreen mode

And the accompanying filter /etc/fail2ban/filter.d/nginx-http-auth.conf:

[Definition] failregex = ^.*client: <HOST>.*(401|403).*"GET" ignoreregex = 
Enter fullscreen mode Exit fullscreen mode

Restart Fail2Ban:

sudo systemctl restart fail2ban 
Enter fullscreen mode Exit fullscreen mode

You can verify active bans with sudo fail2ban-client status nginx-http-auth.


6. Harden Nginx Permissions and Process Isolation

Run Nginx under its own unprivileged user (www-data by default) and enable a private /tmp directory:

sudo mkdir -p /var/lib/nginx/tmp sudo chown www-data:www-data /var/lib/nginx/tmp 
Enter fullscreen mode Exit fullscreen mode

Add the following to the http block of nginx.conf:

http { # ... existing settings ... client_body_temp_path /var/lib/nginx/tmp 1 2; fastcgi_temp_path /var/lib/nginx/tmp 1 2; proxy_temp_path /var/lib/nginx/tmp 1 2; uwsgi_temp_path /var/lib/nginx/tmp 1 2; scgi_temp_path /var/lib/nginx/tmp 1 2; } 
Enter fullscreen mode Exit fullscreen mode

7. Enable Monitoring and Automated Alerts

A hardened stack is only as good as the visibility you have into it. Add a simple Prometheus exporter for Nginx:

sudo apt install prometheus-nginx-exporter 
Enter fullscreen mode Exit fullscreen mode

Configure the exporter to scrape the /status endpoint (make sure stub_status is enabled in a location block). Then set up an alert rule:

# alerts.yml - alert: HighFailedLogins expr: increase(fail2ban_banned_ips_total[5m]) > 10 for: 2m labels: severity: critical annotations: summary: "Too many IPs banned by Fail2Ban" description: "{{ $value }} IPs banned in the last 5 minutes." 
Enter fullscreen mode Exit fullscreen mode

Integrate the alerts with your preferred channel (Slack, PagerDuty, etc.).


Conclusion

By following these seven steps you’ve turned a vanilla Nginx install into a hardened, TLS‑only front‑end that actively blocks brute‑force attempts and surfaces security‑related metrics for your monitoring stack. Remember that hardening is an ongoing process: regularly review cipher suites, rotate certificates, and audit Fail2Ban logs.

If you’re looking for more hands‑on tutorials or managed hosting that respects these best practices, give https://lacidaweb.com a look. It offers a developer‑friendly environment with built‑in security defaults.

Top comments (0)