Restrict Access to WordPress with Nginx and GeoIP

The goal of this post is to harden your WordPress dashboard by preventing logins from countries where you know you will never be connecting. Since brute-force login attempts may still originate from an allowed country, it would be wise to combine this with other tools like fail2ban or one of the numerous plug-ins that add login rate-limiting restrictions to WordPress.

This example targets Nginx on CentOS 7 using PHP 7 from the Remi repo. Settings may vary depending on your exact setup, so watch out for differences from your config, and back up your /etc/nginx first!

First make sure you keep an up-to-date GeoIP database by running a script like the example below via a nightly cron job.

#!/bin/bash

/bin/curl https://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz -o /tmp/GeoIP.dat.gz

/bin/gunzip -c /tmp/GeoIP.dat.gz > /etc/nginx/GeoIP.dat

/bin/rm -f /tmp/GeoIP.dat.gz

Make sure the GeoIP module is installed:

yum install nginx-mod-http-geoip

Make sure the module is loaded in /etc/nginx/nginx.conf:

load_module modules/ngx_http_geoip_module.so;

Inside of http { } in nginx.conf, add this, modifying country and default as desired:

geoip_country /etc/nginx/GeoIP.dat;
map $geoip_country_code $allowed_country {
   default no;
   US yes;
}

And finally add the necessary location statement in your virtual host’s server { }. In this example I’m using PHP 7.1 from the Remi repo, so your configuration may vary.

location ~ ^/(wp-admin|wp-login.php) {
 try_files $uri $uri/ /index.php?$args;
 # try_files $uri =404;
 fastcgi_pass unix:/var/run/php-fpm/php71-fpm.sock;
 fastcgi_index index.php;
 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 include fastcgi_params;
 index index.html index.htm index.php;
 if ($allowed_country = no) {
 return 444;
 }
}