How to Set Up Rate Limiting
Rate limiting prevents abuse by restricting the number of requests from a single IP address within a time window. This guide covers common rate limiting scenarios.
Understanding Rate Limiting
Rate limiting tracks requests per IP address and blocks when thresholds are exceeded. Configuration includes:
- Protected paths: URLs to monitor
- Events per minute: Maximum requests allowed
- Time window: 60 seconds (fixed)
- Response: Block method (403, 404, drop)
Rate limits apply per source IP. Multiple users behind the same IP (corporate proxy, NAT) share the limit.
Protecting Login Pages
WordPress Login
Prevent brute force attacks on wp-login.php:
Configuration:
Rate Limiting: Enabled
Protected Paths: /wp-login.php
Events per minute: 5
Response: Drop
Rationale: – Legitimate users rarely need more than 5 login attempts per minute – Drop response wastes attacker resources – Protects against credential stuffing
Testing:
# Test legitimate login (should work)
curl -X POST https://example.com/wp-login.php \
-d "log=username&pwd=password"
# Test rate limit (repeat 6+ times rapidly)
for i in {1..10}; do
curl -w "Attempt $i: %{http_code}\n" -o /dev/null -s \
https://example.com/wp-login.php
sleep 1
done
Expected: First 5 attempts get response, subsequent attempts timeout (drop) or return 403.
Custom Admin Login
For custom admin panels:
Configuration:
Rate Limiting: Enabled
Protected Paths: /admin/login, /administrator/login
Events per minute: 10
Response: 403
Considerations: – Higher limit for internal tools with multiple quick operations – 403 response provides clear feedback – Monitor logs to verify legitimate use patterns
Protecting API Endpoints
Public API
Rate limit public API to prevent abuse:
Configuration:
Rate Limiting: Enabled
Protected Paths: /api/
Events per minute: 60
Response: 403
Rationale: – 60 requests per minute = 1 per second average – Legitimate API clients rarely exceed this – Prevents API scraping and abuse
Response Headers:
Clients receive standard HTTP 403 when rate limited. Consider implementing retry logic:
import time
import requests
def api_call_with_retry(url, max_retries=3):
for attempt in range(max_retries):
response = requests.get(url)
if response.status_code == 403:
# Assume rate limit, wait and retry
wait_time = (2 ** attempt) * 10
time.sleep(wait_time)
continue
return response
raise Exception("Max retries exceeded")
Authenticated API
Different limits for authenticated vs anonymous:
Anonymous API:
Protected Paths: /api/public/
Events per minute: 30
Response: 403
Authenticated API (use IP whitelist for known servers):
Protected Paths: /api/private/
Whitelist: [trusted-server-ips]
Events per minute: 300
Response: 403
Protecting Search Functionality
Search endpoints are commonly abused:
Configuration:
Rate Limiting: Enabled
Protected Paths: /search, /?s=
Events per minute: 20
Response: 403
Rationale: – Prevents search enumeration attacks – Reduces load from automated scanning – Legitimate users rarely search 20+ times per minute
Testing:
# Test search rate limit
for i in {1..25}; do
echo "Search $i:"
curl -s -o /dev/null -w "%{http_code}\n" \
"https://example.com/?s=test$i"
sleep 2
done
Expected: First 20 searches succeed, subsequent ones blocked.
Protecting Registration Pages
Prevent automated account creation:
Configuration:
Rate Limiting: Enabled
Protected Paths: /register, /wp-login.php?action=register
Events per minute: 3
Response: 403
Rationale: – Legitimate users register once – Very low limit acceptable – Prevents bot registration spam
Considerations: – May need to whitelist office IPs during user import – Monitor for legitimate users hitting limit – Consider CAPTCHA as alternative
Protecting Form Submissions
Contact forms and comment forms:
Configuration:
Rate Limiting: Enabled
Protected Paths: /wp-comments-post.php, /contact-form
Events per minute: 10
Response: 403
Rationale: – Prevents comment spam – Limits contact form abuse – Still allows legitimate rapid submissions
Advanced Configurations
Multiple Path Protection
Protect multiple endpoints with different limits:
Site-Wide Base Limit:
Protected Paths: /
Events per minute: 300
Response: 403
Login Endpoint:
Protected Paths: /wp-login.php
Events per minute: 5
Response: Drop
API Endpoint:
Protected Paths: /api/
Events per minute: 60
Response: 403
Most specific path wins. Request to /wp-login.php uses 5/min limit, not 300/min.
Graduated Response
Use different responses for different abuse levels:
Light Abuse:
Protected Paths: /api/
Events per minute: 60
Response: 403
Heavy Abuse:
Protected Paths: /wp-login.php
Events per minute: 5
Response: Drop
Drop response for login pages wastes more attacker resources than 403.
Temporary Whitelist
During legitimate high-volume operations:
- Note the source IP
- Add to Page Protection whitelist temporarily
- Perform operation
- Remove from whitelist
Example: Data migration, bulk operations, load testing.
Monitoring Rate Limiting
Check Security Logs
Review logs for rate limit triggers:
Dashboard Filters: – Filter by message: “rate limit” – Group by IP to identify repeat offenders – Check time distribution for patterns
Log Analysis:
Most rate-limited IPs:
203.0.113.45 - 1,247 blocks
198.51.100.30 - 892 blocks
192.0.2.15 - 456 blocks
Identify Legitimate Blocks
Signs legitimate users are being rate limited:
- Support requests about “too many requests” errors
- Logs show rate limits on normal business hours
- Known good IPs being blocked
- Specific users reporting issues
Solution: Increase limit or whitelist specific IPs.
Identify Attack Patterns
Attack indicators:
- Rate limits triggered outside business hours
- Consistent limits on login/admin endpoints
- Geographic distribution (attacks from multiple countries)
- Repeated patterns from same IP blocks
Response: Lower limits, change to drop response, or block IPs entirely.
Adjusting Rate Limits
Increasing Limits
If legitimate users are blocked:
- Review security logs for block patterns
- Identify specific legitimate use cases
- Increase limit by 50-100%
- Monitor for one week
- Adjust further if needed
Example: API at 60/min causing issues, increase to 120/min.
Decreasing Limits
If attacks continue:
- Review attack volume in logs
- Note attacker request rate
- Decrease limit to 50% of attack rate
- Monitor attack success rate
- Adjust further if attacks persist
Example: Login attacks at 20/min, decrease limit from 10/min to 5/min.
Per-Endpoint Tuning
Different endpoints have different legitimate use patterns:
Login: 3-5 requests/min (very low) API: 60-120 requests/min (moderate) Search: 10-20 requests/min (low-moderate) Public pages: 100-300 requests/min (high)
Tune each endpoint independently based on actual usage.
Common Scenarios
E-Commerce Checkout
Balance security and user experience:
Configuration:
Protected Paths: /checkout
Events per minute: 30
Response: 403
Rationale: – Users may refresh during payment processing – Some payment methods require multiple requests – Higher limit accommodates legitimate use – Still blocks automated card testing
Testing: Complete full checkout process multiple times rapidly.
Mobile App APIs
Mobile apps make frequent API calls:
Configuration:
Protected Paths: /api/mobile/
Events per minute: 120
Response: 403
Whitelist: [known-good-user-ips if applicable]
Considerations: – Mobile apps poll for updates – Users may trigger multiple operations – Background sync operations – Higher limits needed
Multi-User Environments
Corporate environments with shared IPs:
Problem: 100 users share one IP, 5/min limit = 0.05 requests per user per minute.
Solutions:
- Whitelist corporate IPs:
Page Protection whitelist: [corporate-ip]
- Increase limits significantly:
Events per minute: 500
- Use authentication-based rate limiting (application-level, not WAF)
Content Scraping Prevention
Prevent bulk content downloads:
Configuration:
Protected Paths: /
Events per minute: 100
Response: 403
Rationale: – Legitimate users browse ~1-2 pages per minute – Scrapers request 10-100+ pages per minute – 100/min allows headroom but blocks aggressive scraping
Additional Protection: – Enable bot protection – Block known scraper user agents – Use geographic blocking for regions with no legitimate users
Troubleshooting
Legitimate Users Blocked
Symptom: Users report “too many requests” errors during normal use.
Diagnosis: 1. Check security logs for user’s IP 2. Review request timestamps 3. Identify specific operations triggering limit
Solution: – Increase rate limit by 50-100% – Whitelist specific user IPs if identifiable – Review application behavior (excessive AJAX?)
Rate Limiting Not Effective
Symptom: Attacks continue despite rate limiting enabled.
Diagnosis: 1. Verify rate limiting is enabled and deployed 2. Check that correct paths are protected 3. Review logs to confirm limits are triggering 4. Check if attacker is rotating IPs
Solution: – Decrease rate limit threshold – Change response from 403 to Drop – Add geographic blocking – Consider blocking specific IP ranges
False Positive Spikes
Symptom: Sudden increase in rate limit blocks on legitimate traffic.
Diagnosis: 1. Check for application changes (new feature, marketing campaign) 2. Review request patterns in logs 3. Identify if specific feature causing issue
Solution: – Temporarily increase limits during high-traffic events – Whitelist known-good IPs – Optimize application to reduce request volume
Distributed Attacks
Symptom: Attack from many different IPs, rate limiting per-IP not effective.
Diagnosis: 1. Review security logs for attack pattern 2. Note geographic distribution 3. Check user agent patterns 4. Identify attack type (login, API, etc.)
Solution: – Enable geographic blocking for attack source countries – Enable bot protection if automated – Lower rate limits aggressively – Consider temporary site-wide restrictions
Best Practices
Start Conservative: Begin with lower limits, increase if needed. Easier to increase than decrease.
Monitor Actively: Watch logs for first 48 hours after enabling rate limiting.
Document Changes: Record limits, rationale, and any adjustments made.
Test Thoroughly: Verify legitimate workflows still function correctly.
Use Appropriate Response: 403 for visibility, Drop for aggressive blocking.
Layer Protections: Combine rate limiting with geographic blocking, bot protection, and IP whitelisting.
Review Regularly: Quarterly review of rate limits and effectiveness.
Plan for Events: Increase limits temporarily during marketing campaigns or known high-traffic periods.
Rate limiting is effective against automated abuse while minimizing impact on legitimate users when properly configured and monitored.
