Pinged Whenever I Get a Visitor
To run my site, I am using NGINX, an open source software for web serving, load balancing, and much more. I am however only using it as a web server, as that is all I really need to serve simple html. The other day I was ssh'd into my server, and was in the
/var/log/ directory, as one does, going over my mail logs, authentication logs and other stuff, when I noticed a
nginx/ directory. Inside of that directory, there were multiple log files, including a log file names
access.log. Upon further inspection, I found out that this file contains a log of every visit to my website. It keeps a log of every ip address that connects to my website. And so I had this idea of getting notified somehow everytime this file gets modified, i.e., a new visit. And that is when the Bash wizard in me was awoken.
Just a disclaimer that the IP address I read is your router's public IP, meaning every device on your network that tries to connect to my website will have the same public IP, which is your router's IP address. Regarding geolocation, the public IP only reveals what city it's coming from, and nothing more.
cp -f /var/log/nginx/access.log /tmp/ ip_file=$(cat /tmp/access.log) currentip=$(tail -n 1 <<< $ip_file | cut -d' ' -f1)
Here, I start by copying the log file to
/tmp/ directory, reading the last line of that file, then storing the first field in the variable
$currentip. Now I can append that IP to this API, and extract the city, state and country of that IP, like so.
location=$(curl -s http://ip-api.com/json/$currentip) city=$(jq -r '.city' <<< $location) region=$(jq -r '.region' <<< $location) country=$(jq -r '.country' <<< $location)
Here, I run
curl silently, and have its output be stored, which is in json format, be stored in variable
$location. And to avoid using extra regex, I use
jq to extract the entries needed in the json output, storing the city in
$city, and so on. Lastly, I need my server to email me the output in a readable format, which I do here.
echo "$city, $region, $country" | mail -s "New Visit: $currentip" firstname.lastname@example.org
This will mail me the city, state, and country to my email. I also need to invoke the script everytime the log file
access.log gets modified. This is where the magic on entr comes to play. I have linked to its GitHub, as I will not go into detail on how it works. But basically, it lets me run my script everytime the log file gets modified. I can do this with this command
ls /var/log/nginx/access.log | entr ./myscript.sh
And now for the final script, you can copy this and run this on your webserver. But obviously put in your email instead of mine LOL.
#!/bin/bash cp -f /var/log/nginx/access.log /tmp/ ip_file=$(cat /tmp/access.log) currentip=$(tail -n 1 <<< $ip_file | cut -d' ' -f1) [[ -f /tmp/last_ip.log ]] && lastip=$(cat /tmp/last_ip.log) if [ "$currentip" == "$lastip" ]; then exit; else location=$(curl -s http://ip-api.com/json/$currentip) city=$(jq -r '.city' <<< $location) region=$(jq -r '.region' <<< $location) country=$(jq -r '.country' <<< $location) echo "$city, $region, $country" | mail -s "New Visit: $currentip" email@example.com fi echo $currentip > /tmp/last_ip.log