Slowloris Slow-Attack Defense in Practice: Nginx and iptables Multilayer Protection Config
Slowloris slow attacks exhaust the server connection pool with tiny traffic. This article provides a three-layer protection config: Nginx parameter tuning, iptables connection limits, and Fail2ban auto-ban.
Applicable Scenarios
This article is for Nginx ops engineers, web security admins, and self-hosted site owners. Focus: defending Slowloris slow attacks. Slowloris abuses HTTP: it sends incomplete HTTP request headers at a very low rate, exhausts the server connection pool, and blocks legitimate users. This article provides a three-layer Nginx + iptables + Fail2ban protection scheme.
Prerequisites
- Linux server (Ubuntu 20.04+ / CentOS 7+), Nginx 1.18+
- root or sudo to edit Nginx config and iptables rules
- Fail2ban installed (if not, see the previously published Fail2ban config tutorial)
- Basic knowledge of HTTP request headers and TCP three-way handshake
How It Works
Slowloris was first published by Robert RSnake Hansen in 2009. Attack: the attacker opens many TCP connections, then keeps sending incomplete HTTP request headers (one extra header byte at a time, e.g. X-a: b\r\n). The server waits for the request to complete until max_clients is exhausted. Traditional DDoS defenses watch for high volume; Slowloris traffic is tiny, so you need dedicated config.
Procedure
Step 1: Tune Core Nginx Parameters
Edit the http block in /etc/nginx/nginx.conf and set these key parameters:
http {
# Idle connection close timeout (seconds) — default 75; lower so Slowloris connections release faster
keepalive_timeout 15;
# Client request header timeout (seconds) — max wait from first byte to a complete header
client_header_timeout 10;
# Client request body timeout (seconds)
client_body_timeout 10;
# Timeout for sending the response to the client (seconds)
send_timeout 10;
# Cap concurrent connections per client (requires ngx_http_limit_conn_module)
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 20;
# Buffer settings — mitigate large-header attacks
client_body_buffer_size 128k;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;
}
Step 2: Add Nginx Connection Monitoring and Auto-Release
In the server blocks you need to protect, add ngx_http_limit_req_module rate limiting:
server {
listen 80;
listen 443 ssl;
server_name yourdomain.com;
# Request rate limit — max 5 requests per second
limit_req_zone $binary_remote_addr zone=sLowloris:10m rate=5r/s;
limit_req zone=sLowloris burst=10 nodelay;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
Step 3: iptables Connection Limits
Use the connlimit module to cap concurrent connections per IP. Intercept Slowloris at the TCP layer before it reaches Nginx:
# Cap concurrent HTTP connections per IP at 30
iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 30 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 30 -j REJECT --reject-with tcp-reset
# Cap new connections per second (SYN Flood + Slowloris mix)
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --set --name HTTP
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 1 --hitcount 10 --name HTTP -j DROP
# Persist rules
apt-get install -y iptables-persistent # Ubuntu
netfilter-persistent save
# CentOS:
# yum install -y iptables-services
# service iptables save
Step 4: Fail2ban Custom Rules to Detect Slowloris
Fail2ban inspects Nginx access logs for Slowloris signatures — connections that stay incomplete for a long time:
# Create Fail2ban filter /etc/fail2ban/filter.d/nginx-slowloris.conf
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*HTTP/1\.[01]" 499 .*$
ignoreregex =
Create jail config /etc/fail2ban/jail.d/nginx-slowloris.conf:
[nginx-slowloris]
enabled = true
port = http,https
filter = nginx-slowloris
logpath = /var/log/nginx/access.log
maxretry = 20
findtime = 60
bantime = 3600
action = iptables[name=Slowloris, port=http, protocol=tcp]
Restart Fail2ban:
systemctl restart fail2ban
fail2ban-client status nginx-slowloris
Verify the Config
# 1. Check Nginx config syntax
nginx -t
# 2. Reload Nginx
systemctl reload nginx
# 3. Use a slowloris test script to verify defense
git clone https://github.com/llaera/slowloris-test.git
cd slowloris-test
python3 slowloris.py -s yourdomain.com -p 443
# 4. Monitor Nginx connection state
netstat -an | grep :80 | wc -l
# Under normal load this should stay under 30; under attack it should not exceed the configured limit_conn cap
# 5. Check Fail2ban ban logs
fail2ban-client status nginx-slowloris
FAQ
Q1: Will lowering keepalive_timeout hurt legitimate users?
Minor impact. Dropping keepalive_timeout from 75s to 15s frees idle connections faster; consecutive requests from real users pay a bit more TCP handshake cost. For most web apps (mean request interval under 5s), impact is tiny. If the site has lots of silent long-polling, set 30-45s as a compromise.
Q2: Will iptables connlimit of 30 false-ban users behind a corporate NAT egress?
Possible. Under NAT, many users share one public IP; a 30-connection cap may be too tight. Raise connlimit to 50-80 and add limit_req (request rate limit) as a second filter. Or measure peak concurrency in Nginx logs, then tune.
Summary
Core idea for Slowloris defense: shorten timeouts + cap connections, at both the Nginx app layer and the iptables network layer. Lower client_header_timeout/keepalive_timeout so incomplete connections drop fast; combine connlimit per-IP caps with Fail2ban auto-ban for a closed defense loop. Combine this config with the previously published Fail2ban SSH brute-force protection and Nginx limit_req CC defense to build a full site defense stack.