IP Blocker Script for Apache and Nginx Servers (Optional)

Optional request flood blocking through iptables

IP blocker script

ip-blocker.sh is an optional server script that ships with the Turbo Indexer. It has nothing to do with indexing: it blocks addresses that flood an Apache or Nginx server with requests. It runs from cron every 10 minutes, as root.

What one run does

  1. On a Sunday, the first run clears every block of the past week.
  2. Reads every file named *access*.log in /var/log/apache2, /var/log/nginx and /var/log/httpd.
  3. Counts the requests per address over the last 10 minutes. The combined, common and vhost_combined log formats all work.
  4. Blocks every address with 500 requests or more in that window, unless it is on the allow list below or already blocked. The iptables rule goes first in the INPUT chain.
  5. Writes each block, with its time, to /etc/ip-blocker.list.

Never blocked

  • This machine: 127.* and ::1.
  • Private networks: 10.*, 172.16.* to 172.31.*, 192.168.*, and link-local 169.254.*.
  • Cloudflare's IPv4 ranges, downloaded from cloudflare.com and kept for 30 days. When the download fails and nothing is kept yet, a list built into the script is used.
  • One Opensolr service address.

Install

The script is in the module's folder; with the standard Composer layout that is web/modules/contrib/opensolr_turbo_indexer/.

sudo cp web/modules/contrib/opensolr_turbo_indexer/ip-blocker.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/ip-blocker.sh

# See who it would block, block nobody
sudo ip-blocker.sh --dry-run

Then add it to root's crontab (crontab -e):

*/10 * * * * /usr/local/bin/ip-blocker.sh >> /var/log/ip-blocker.log 2>&1

Options

--threshold N

Requests in the window that get an address blocked. Default: 500.

--window N

Minutes of log to count; keep it equal to the cron interval. Default: 10.

--dry-run

Logs who would be blocked and blocks nobody. Default: off.

--list

Shows the blocked addresses and when each was blocked.

--unblock IP

Removes one address from the list and from iptables.

-h, --help

Shows the usage line.

What the log says

Each line starts with the date and time.

BLOCKED 203.0.113.7 - 812 requests in 10min
No offenders detected (threshold: 500 req/10min)
Weekly reset: cleared 3 blocked IPs

Good to know

  • IPv4 only. The rules are iptables rules, so IPv6 visitors are never blocked.
  • Direct connections only. Visitors who come through Cloudflare connect from Cloudflare addresses, which are never blocked.
  • After a server restart the iptables rules are gone, while /etc/ip-blocker.list still names the addresses. Those addresses are blocked again after the Sunday reset, or after you --unblock them.
  • When a run is still going, the next one exits at once, so cron runs never overlap.
  • It needs bash, root, iptables, curl, flock and awk.

Bonus tools: optional server scripts