DDoS Protection Setup for Websites
DDoS (Distributed Denial of Service) — server overload with stream of requests from multiple sources until complete unavailability. Attacks happen at network (L3/L4: UDP flood, SYN flood) and application (L7: HTTP flood) levels. Latter harder to filter — requests look like legitimate traffic.
Protection Layers
Layer 1: CDN + Anycast (Cloudflare, AWS Shield) Traffic passes through distributed network of nodes. Attacker forced to overload hundreds of presence points worldwide — practically impossible task.
Layer 2: Rate limiting at Nginx/application level Restrict number of requests from single IP.
Layer 3: Anomalous traffic analysis and blocking Behavioral patterns, IP reputation, Challenge (CAPTCHA/JS challenge) for suspicious traffic.
Cloudflare — Basic Setup
Cloudflare Free/Pro automatically closes most L3/L4 attacks. For L7:
Security > DDoS > HTTP DDoS attack protection:
- Sensitivity: High
- Action: Block (after testing, start with Log)
Security > Settings:
- Security Level: Medium or High under attack
- Bot Fight Mode: ON
- Browser Integrity Check: ON
Under active attack: Security > Under Attack Mode — all visitors pass JS challenge.
Rate Limiting in Nginx
# Limit zones — in http block
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/m;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_conn_zone $binary_remote_addr zone=perip:10m;
server {
# API — 30 requests per minute
location /api/ {
limit_req zone=api burst=10 nodelay;
limit_req_status 429;
}
# Login form — 5 tries per minute
location /login {
limit_req zone=login burst=3 nodelay;
limit_req_status 429;
}
# Maximum 20 concurrent connections from one IP
limit_conn perip 20;
}
Rate Limiting in Application (Laravel)
// routes/api.php
Route::middleware('throttle:60,1')->group(function () {
Route::get('/data', [DataController::class, 'index']);
});
// Custom limits with different rules for authorized
Route::middleware('throttle:api')->group(function () { ... });
// config/app.php or RouteServiceProvider
RateLimiter::for('api', function (Request $request) {
return $request->user()
? Limit::perMinute(120)->by($request->user()->id)
: Limit::perMinute(30)->by($request->ip());
});
SYN Flood at Linux Kernel Level
# /etc/sysctl.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 3
# Apply
sysctl -p
Firewall: Connection Limiting via iptables/nftables
# Limit new TCP connections: no more than 20 per second from one IP
iptables -A INPUT -p tcp --dport 80 -m state --state NEW \
-m recent --set --name HTTP_FLOOD
iptables -A INPUT -p tcp --dport 80 -m state --state NEW \
-m recent --update --seconds 10 --hitcount 200 \
--name HTTP_FLOOD -j DROP
Fail2ban for HTTP Flood
# /etc/fail2ban/filter.d/nginx-req-limit.conf
[Definition]
failregex = limiting requests, excess:.* by zone.*client: <HOST>
# /etc/fail2ban/jail.d/nginx.conf
[nginx-req-limit]
enabled = true
filter = nginx-req-limit
logpath = /var/log/nginx/error.log
maxretry = 10
findtime = 60
bantime = 600
Geo-blocking
Under attack from specific regions — temporary block via Cloudflare or GeoIP in Nginx:
# MaxMind GeoIP2
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_country_code country iso_code;
}
map $geoip2_country_code $blocked_country {
default 0;
CN 1;
RU 0; # Cannot block own audience
}
if ($blocked_country = 1) { return 403; }
Monitoring and Alerts
Tools for anomalous traffic observation:
- Grafana + Prometheus — RPS, 4xx/5xx, latency dashboards
- GoAccess — real-time Nginx log analysis
- Cloudflare Analytics — blocked request statistics
- Alert on 90th percentile RPS exceed — signal to activate enhanced mode.
Implementation Timeline
- Cloudflare connection + basic rules: 1 day
- Nginx rate limiting + Fail2ban setup: 1 day
- Monitoring setup: 1–2 days







