Block DDoS Attacks with Nginx: Practical Guide
This guide shows you how to configure Nginx to absorb and mitigate common Distributed Denial of Service (DDoS) attacks—such as SYN floods, HTTP floods, and slowloris—before they exhaust your server’s resources. You’ll learn concrete directives for rate limiting, connection limits, timeouts, and IP blocking, which together can keep your site responsive during an attack. You’ll need root or sudo access to your Nginx server and a basic familiarity with editing Nginx configuration files.
What You’ll Need
- A server running Nginx (tested on Nginx 1.18+ but works on most modern versions)
- Root or sudo access to edit configuration files
- Basic knowledge of the command line and Nginx’s config structure
- Optional: a firewall (like UFW or iptables) for additional IP blocking
Step-by-Step
- Back up your current configuration. Before making changes, copy your main config and site configs:
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backupand similarly for each site in/etc/nginx/sites-available/. - Set global timeouts in the http block. Open
/etc/nginx/nginx.confand inside thehttp { }block, add or adjust these directives to close idle connections faster:client_body_timeout 10s; client_header_timeout 10s; keepalive_timeout 5s 5; send_timeout 10s;
These limit how long Nginx waits for a client to send data, which mitigates slowloris attacks.
- Limit connection rates per IP. In the same
httpblock, define a limit zone (outsideserverblocks):limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m; limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;
The first creates a zone to track concurrent connections, the second tracks request rate. Adjust the rate (e.g., 5r/s) based on your normal traffic—too low will block legitimate users.
- Apply limits in your server or location blocks. In your site’s config (e.g.,
/etc/nginx/sites-available/example.com), add these inside theserver { }or specificlocation { }blocks:limit_conn conn_limit_per_ip 10; limit_req zone=req_limit_per_ip burst=20 nodelay;
The
burstallows short spikes above the rate;nodelayprocesses them immediately but counts them. Tune these values—too strict will block legitimate users during traffic spikes. - Block specific IPs or subnets. If you know attack sources, add a deny list at the top of your
serverblock:deny 192.168.1.0/24; allow all;
Place
allow all;after all deny rules. For dynamic blocking, use a file included from the http block:include /etc/nginx/blocked_ips.conf;and update that file with deny rules. - Limit request size to prevent large payload floods. In your
serverorlocationblock, set:client_max_body_size 1m;
Adjust based on your legitimate needs (e.g., file uploads need more).
- Enable SYN cookies (if using Nginx as a reverse proxy). If Nginx fronts your app, set in the
httpblock:listen 80 backlog=1024; listen 443 ssl backlog=1024;
The
backlogincreases the queue for pending connections, helping absorb SYN floods. For full SYN cookie protection, use a firewall like iptables or a dedicated DDoS mitigation service. - Use a caching layer for static content. In your
locationblocks for static files, add:location ~* \.(jpg|jpeg|png|css|js)$ { expires 30d; add_header Cache-Control "public, immutable"; }This reduces the load on your backend, making it harder to overwhelm.
- Test the configuration. Run
sudo nginx -tto check for syntax errors. If it passes, reload Nginx withsudo systemctl reload nginx(orsudo service nginx reload). - Monitor and adjust. Watch your access and error logs (
/var/log/nginx/access.log,error.log) to see if legitimate users are being blocked. Usesudo tail -fto watch in real time during an attack.
Common Mistakes
- Setting rates too low. A rate of 1r/s might block users behind a NAT or proxy. Start with 10r/s and lower gradually.
- Forgetting to apply limits to all locations. Attackers can target unguarded endpoints (like /api). Apply limits at the server level, not just the root location.
- Using
limit_reqwithout a burst. Without burst, legitimate short spikes get 503 errors. Always set a reasonable burst. - Blocking your own IP. Test with your own IP first to ensure you don’t lock yourself out. Always have a backup way to access the server (e.g., console).
- Not testing after changes. A syntax error can take your site down. Always run
nginx -tbefore reloading.
Tips
- Use a CDN or DDoS protection service for large-scale attacks—Nginx alone can’t handle volumetric floods that saturate your bandwidth.
- Combine with fail2ban to automatically block IPs that trigger Nginx error codes (like 503 from rate limiting).
- Separate dynamic and static traffic. Serve static files from a different server or cache them aggressively.
- Keep Nginx updated. Newer versions have better performance and security fixes.
- Use a separate rate limit for login endpoints (e.g., 2r/s) to prevent brute-force attacks.
Troubleshooting
- Legitimate users getting 503 errors. Increase the
burstvalue or therateinlimit_req_zone. Also check if your limits are too low for your normal traffic. - Nginx won’t start after changes. Run
sudo nginx -tto see the exact error. Common issues: missing semicolons, duplicate zones, or incorrect paths ininclude. - Attack still succeeds. Check if the attack is targeting a different port (e.g., 443) or using distributed IPs that bypass rate limits. Consider adding a WAF or using a cloud-based mitigation service.
- IP blocking isn’t working. Ensure the
denyrules are in the correct order—denymust come beforeallow all;. Also check that you’re editing the right server block (e.g., the one with thelistendirective for your domain). - Logs show many 503s from your own IP. You’re likely behind a NAT or proxy—your IP appears as the same to Nginx. Adjust limits to allow more per IP or use
$http_x_forwarded_forif behind a proxy.
Frequently Asked Questions
Can Nginx completely stop a DDoS attack?
No. Nginx can mitigate application-layer attacks (HTTP floods, slowloris) and some connection floods, but it cannot handle volumetric attacks that saturate your bandwidth. For those, you need a CDN or DDoS protection service.
What is the difference between limit_req and limit_conn?
limit_req limits the number of requests per second from an IP, while limit_conn limits the number of concurrent connections. Use both—they address different attack vectors.
Will rate limiting affect SEO or crawlers?
Googlebot and other crawlers typically respect rate limits and may slow down, but they won’t be permanently blocked if your limits are reasonable. Set a higher rate for known crawler IPs if needed.
How do I know if I’m under a DDoS attack?
Check your server load (top), network traffic (iftop), and Nginx logs for a surge in requests from a single IP or many IPs. Also monitor connection timeouts and 503 errors.
Should I block IPs manually during an attack?
Only if you can identify attack sources quickly. Manual blocking can help, but automated tools like fail2ban or a CDN’s rate limiting are more effective for large-scale attacks.
Can I use these settings on a reverse proxy setup?
Yes, these directives work the same when Nginx is a reverse proxy. Just ensure the rate limits apply to the client IP, not the proxy IP—use $binary_remote_addr as shown, or $http_x_forwarded_for if your proxy forwards the original IP.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.