Bash script to parse Nginx logs and block bots


If you have a website as I do, inevitably, you are facing spam and bots trying to flood your machine, spoof, or hack it. My approach to addressing this was very straight-forward and even naive, but it did its job, and I am satisfied with the result.

The idea is to capture “prohibited keywords” and block source IP addresses by iptables.


while true
  do grep "$(date +%d/%b/%Y:%H:%M)" /var/log/nginx/access.log |\
    awk -F ":" '$0 ~/chmod|shell_exec/ {print $1}'|\
    cut -d ' ' -f 1 | sort | uniq -c | sort -rnk1 |\
    while read count ip
        [ $count -ge 1 ] && echo $count $ip || exit 0 
        while read count ip 
            [ $(/sbin/iptables -L -v -n | grep "$ip" | wc -l) -eq 0 ] &&\
            iptables -A INPUT -s $ip -j DROP &&  { echo "iptables -D INPUT -s $ip -j DROP" | at now +1 hour; } &&\
            echo "Blocking this IP for 1 hour since it attempted to hack the site $count times per minute: $ip"
  sleep 61

While the script is simple and the logic is straightforward, let me put a few words for clarity. At first, you have to run this script in virtual terminal emulators like tmux or screen. Otherwise, you have to keep the ssh session to the remote machine open indefinitely.

Sure thing, you can daemonize the script and make it running on the background like any other system process. But I really wanted it to be simple, without unnecessary features.

The following part might look a bit confusing:

iptables -A INPUT -s $ip -j DROP &&  { echo "iptables -D INPUT -s $ip -j DROP" | at now +1 hour; }

However, it is very simple. We are blocking bot’s IP addresses via iptables and removing the blockage an hour later through “iptables -D” and scheduler at.