Skip to main content

Finding bad actors from Nginx logs

Occasionally your website will be under attack. Despite your rate limiting configuration, block-lists and Cloudflare WAF rules, some malicious traffic will still, inevitably, get through. The first line of defense in such cases is the system logs.

In this lesson we'll look at some ways to analyze Nginx access logs and identify bad actors and malicious traffic. We'll look at ways to sort, filter and pluck information from the logs. This information will help us restrict access to IP addresses, URL patterns and more.

Using bash and jq

We created a JSON log format in a previous lesson which we can query using jq. Combined with some simple bash scripting, we can build small single-purpose helper scripts to quickly get the information we need.

I like to keep these scripts in the /config/bin/logs/ directory, each with a short description at the very top, and accepting the path to the log file as the first argument. Here's a quick example of requests.sh:

#!/bin/bash
# Display the IPs and total number of requests in the last 24h
jq -r 'select(.timestamp > (now - 60*60*24)) | .remote_addr' \
    $1 | sort | uniq -c | sort -nr

This prints a list of IP addresses and the number of requests each made in the last 24 hours, sorted by request count. You can combine this with other tools such as grep and head:

cd /sites/uncached.org/logs
/config/bin/logs/total-requests.sh access.json.log | head -10

If you're comfortable with bash, you can further extend this to support a --since argument, derive the path to the access.json.log file from the working directory, and even do some auto-completion. There are some examples of this in the demo config repository, however it is also perfectly fine to keep these helper scripts as simple as possible.

This article is for premium members only. One-time payment of $96 unlocks lifetime access to all existing and future content on wpshell.com, and many other perks.