How to GeoIP block certain countries in Nginx with MaxMind

I spent too long thinking that ModSecurity was necessary for this, but you can do it with just the ngx_http_geoip2_module

Install nginx along with the module:

apt-get install nginx libnginx-mod-http-geoip2

Download the free GeoLite mmdb database from MaxMind into /etc/nginx/GeoLite2-Country.mmdb (you can and probably should use their tools to update this automatically).

Create /etc/nginx/conf.d/geoip.conf with the countries you want to block:

geoip2 /etc/nginx/GeoLite2-Country.mmdb {
    	auto_reload 5m;
       	$geoip2_metadata_country_build metadata build_epoch;
       	$geoip2_data_country_code default=XX source=$remote_addr country iso_code;
}

map $geoip2_data_country_code $block_country {
       	default 0;
       	CN 1;    # China
       	RU 1;    # Russia
       	IR 1;    # Iran
       	KP 1;    # North Korea
    	XX 1;	 # Unknown
}

Then in the server block simply block based on that variable:

server_name _;
	location / {
       	if ($block_country) {
      		return 403;
       	}
		try_files $uri $uri/ =404;
	}

If you want to check if the country code is working before returning 403, you can add the country code to the logs by modifying nginx.conf:

log_format geoip_combined '$remote_addr - $remote_user [$time_local] '
                          '"$request" $status $body_bytes_sent '
                          '"$http_referer" "$http_user_agent" '
                          '$geoip2_data_country_code';
access_log /var/log/nginx/access.log geoip_combined;