wordpress comment spam

Lets face it, wordpress comment spam is a real pain in the butt

I manage a ton of WordPress client sites and of course I always use Akismet to flag spammers. Akismet does help by flagging comments as spam in your WordPress backend, but this still means:

  • You have to manually delete them – which wastes your valuable time.
  • Spammers get to consume a ton of your bandwidth.
  • All this junk spam normally reaches your sql database.
  • Spam comment activity gets into your server logs and into your analytics. This can make it difficult to distinguish real traffic from spam traffic. 
  • Lots of site activity from undesirable countries, can send confusing signals to search engines. This may give engines the wrong idea about who your primary audience is and where they reside.

Bye, Bye Spam

Regardless of what system or plugins you use to manage spam and comments, its better to stop spam at the server level and prevent your precious bandwidth and resources from being wasted. If your sites are anything like mine, you will probably notice 99% of the spam comments come from the same countries.

Hello, China (CN) and Russia (RU) I am talking to you!

Yes, I said it!

Data does not lie, and on most of my sites I get literally hundreds of spam comments a day all of them are from the above 2 countries. We can ultimately thank Google for this. Comment spam is driven purely as shoddy attempt by link builders to create links in order to rank for keywords in google search results.

What I am going to show you, is how to specifically – only block comment  attempts from certain countries. We still want visitors from these countries to access the actual website content. We will apply the block only when they try and POST using the WordPress comment form.

Spammer – You shall not pass!

To do this you need to first make sure your nginx version has been compiled with GEOIP support. You are looking for “http_geoip_module” to be listed.

[root@new-wp-test-site ~]# nginx -V
nginx version: nginx/1.6.0
built by gcc 4.7.3 (GCC)
TLS SNI support enabled
configure arguments: --user=www --group=www --with-ld-opt='-L/opt/local/lib -Wl,-R/opt/local/lib' --prefix=/opt/local --sbin-path=/opt/local/sbin --conf-path=/opt/local/etc/nginx/nginx.conf --pid-path=/var/db/nginx/nginx.pid --lock-path=/var/db/nginx/nginx.lock --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/db/nginx/client_body_temp --http-proxy-temp-path=/var/db/nginx/proxy_temp --http-fastcgi-temp-path=/var/db/nginx/fstcgi_temp --with-mail_ssl_module --with-http_ssl_module --with-http_dav_module --with-http_realip_module --with-ipv6 --with-http_stub_status_module --with-http_geoip_module

If its not listed you will need to recompile nginx with http_geoip_module support.

Next we install the MaxMind GeoIP Country database. If you are using SmartOS simply install it:

[root@new-wp-test-site ~]# pkgin -y in GeoIP
calculating dependencies... done.

nothing to upgrade.
1 packages to be installed: GeoIP-1.4.8 (0B to download, 2398K to install)

downloading packages...
installing packages...
installing GeoIP-1.4.8...
GeoIP-1.4.8: copying /opt/local/share/examples/GeoIP/GeoIP.conf.default to /opt/local/etc/GeoIP.conf
pkg_install warnings: 0, errors: 0
reading local summary...
processing local summary...
updating database: 100%
marking GeoIP-1.4.8 as non auto-removable
[root@new-wp-test-site ~]#
[root@new-wp-test-site ~]# ls /opt/local/share/GeoIP/

As you can see the GeoIP database is installed in “/opt/local/share/GeoIP/”

If you are using another operating system or want the most up-to-date version, you can download the database directly from MaxMind:

[root@site ~]# wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
[root@site ~]# gunzip GeoIP.dat.gz

Now it is simply a matter of configuring nginx.conf and our virtual host .conf file to use it.

#1 First we tell nginx where the GeoIp database file is located. We add this to the nginx “http” section.


geoip_country /opt/local/share/GeoIP/GeoIP.dat;

#2 Next we edit the nginx virtual host file’s “server” section and specify where to apply GeoIp filtering and what to do when we get a country ip match. I found this needed to be added right near the top of the “Server” section directly under the “server_name” in the virtual host file. If I added it in further down, it would not work.


set $cc "";
if ($request_uri = /wp-comments-post.php) {
        set $cc $geoip_country_code;
if ($cc ~ (CN|KR|RU|UA)) {
        return 444;

Essentially, What this bit of code does is when someone tries to post a comment via the WordPress comment mechanism “wp-comments-post.php” it then checks which country they are in. If they match a specific country they are returned an HTTP 444 status code to indicate that the server has returned no information to the client and closed the connection.

If you choose to enable WordPress trackbacks(pings) – You can also block spam on these via this bit of nginx code also added to the virtual host file “server” section.


location ~ /trackback/ {
        if ($geoip_country_code ~ (CN|KR|RU|UA|TR)) {
                return 444;

and the Score is: nginx – 1 ; spammers – 0

comment spam blocked in logs
Here is the result with this in place – running on a small obscure wordpress site after only 1 days worth of activity. As you can see that is 243 spam attempts that did not get to touch the SQL database nor require processing by any anti spam plugins. Pretty cool huh?


Here is the impact after being in place for 5 days. Yes the graph shows a lot less traffic, but at least we can now see what our real visitor numbers are without the spam getting through.