Whenever someone publishes a website on the internet, most of the times, their intention is that site to be seen around the globe. However, as a site administrator you may want to divert users from one country to visit some specific version of that site, maybe because of the visitor’s language. Other times, less often but nonetheless a viable and valid approach, for some purposes the site administrator may want to block visitors from a country or several ones, even plainly block all but one. All of these options can be achieved by managing site visitors based on IP geolocation.
Most sites around the globe are presented with the NGINX or Apache HTTP web servers. In this guide I’ll concentrate on Apache HTTP.
The process we’ll follow is simple. Create an account in MaxMind to get access to the geolocation databases, download them, install an Apache HTTP module to handle requests in tune with their geolocation information, configure Apache to just do that and test with a VPN if the solution is really working.
If you find the articles in Adminbyaccident.com useful to you, please consider making a donation.
Use this link to get $200 credit at DigitalOcean and support Adminbyaccident.com costs.
Get $100 credit for free at Vultr using this link and support Adminbyaccident.com costs.
Mind Vultr supports FreeBSD on their VPS offer.
Pre-requisites
1.- Having one FreeBSD box with a FAMP stack installed on it. If you don’t have any you may use this promo link to get 100$ free access for two months at Digital Ocean and use any of the following scripts.
Mind both scripts will set a FAMP stack box without TLS certificates.
2.- A VPN service of some sort that allows you to test the configuration changes based on different geolocations.
Step 0. Create an account in MaxMind
MaxMind is a company that sells databases containing information relative to IPs and how those are related to specific geographical locations. Countries, cities and even ASN (autonomous systems). To get that information one must pay a fee for accurate, very reliable data. However, there’s still a free edition anyone can download with a registration to their site. Those free access databases are called GeoLite2.
We’ll need to get access to the free (less reliable) geolocation databases opening an account in MaxMind. That’s an easy step that needs little guidance and a link for you to open that account. I have no affiliation to MaxMind in any way so feel free to use this or just look for it yourself.
Once we’ve opened the account, we can move on to get the databases.
Step 1. Installing Geolocation databases
In order to manage site visitors based on IP geolocation we need some kind of database to pull data from and know what ranges of IPs are related to countries or cities around the globe. Mind that data often changes since ISPs are just using all IPv4 internet space and big blocks of IPs can suddenly change from one geographical location to another.
The first piece of software to install is the ‘geoipupdate’ package.
root@geolocation:~ # pkg install geoipupdate-4.7.1
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 1 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
geoipupdate: 4.7.1
Number of packages to be installed: 1
The process will require 6 MiB more space.
3 MiB to be downloaded.
Proceed with this action? [y/N]: y
[geolocation] [1/1] Fetching geoipupdate-4.7.1.txz: 100% 3 MiB 1.6MB/s 00:02
Checking integrity... done (0 conflicting)
[geolocation] [1/1] Installing geoipupdate-4.7.1...
[geolocation] [1/1] Extracting geoipupdate-4.7.1: 100%
=====
Message from geoipupdate-4.7.1:
--
You must register for a (free) MaxMind account
to download the free GeoIP2 databases.
Register for an account: https://www.maxmind.com/en/geolite2/signup
Get a license key: https://www.maxmind.com/en/accounts/155743/license-key
Place the generated account key and license key
into /usr/local/share/geoipupdate/GeoIP.conf
root@geolocation:~ #
The exact location of this configuration file for the geolocation to work is sitting in the following path:
root@geolocation:~ # ls -al /usr/local/etc/GeoIP.conf
-rw-r--r-- 1 root wheel 1817 28 juny 21:53 /usr/local/etc/GeoIP.conf
root@geolocation:~ #
Once this geoipupdate software is installed we need to configure it so we can use or user ID and license to pull those databases we want to use.
root@geolocation:~ # grep -n 'AccountID' /usr/local/etc/GeoIP.conf
8:AccountID YOUR_ACCOUNT_ID_HERE
root@geolocation:~ #
As it can be seen the Account ID sits on line 8 in the GeoIP.conf file and just below of it the license entry.
root@geolocation:~ # grep -n 'LicenseKey' /usr/local/etc/GeoIP.conf
9:LicenseKey YOUR_LICENSE_KEY_HERE
root@geolocation:~ #
Grab your favorite editor and edit both lines, 8 and 9, and replace the capital string with the real information relative to your MaxMind’s account.
Once that’s done it’s time to pull the databases from MaxMind. We’ll do this with the following command.
root@geolocation:~ # /usr/local/bin/geoipupdate
root@geolocation:~ #
Where have they gone? Down to /usr/local/share/GeoIP.
root@geolocation:/usr/local/share/GeoIP # ll
total 48118
-rw------- 1 root wheel 0 28 juny 21:57 .geoipupdate.lock
-rw-r--r-- 1 root wheel 64454306 28 juny 21:58 GeoLite2-City.mmdb
-rw-r--r-- 1 root wheel 4206286 28 juny 21:58 GeoLite2-Country.mmdb
root@geolocation:/usr/local/share/GeoIP #
With the databases in place, it’s time to move on to the next step and install the necessary module for Apache to interact with these databases and manage site visitors based on IP geolocation.
Step 2. Install mod_maxminddb module for Apache HTTP
Apache HTTP doesn’t incorporate any geolocation functionality by default. MaxMind does produce a module for this powerful web server to make use of the databases they produce. By installing it we’ll let Apache HTTP make use of them and redirect, block or just accept connections based on their IP’s geolocation.
To install the module we’ll use the following command.
[root@geolocation ~]$ sudo pkg install -y ap24-mod_maxminddb-1.2.0
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 1 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
ap24-mod_maxminddb: 1.2.0
Number of packages to be installed: 1
10 KiB to be downloaded.
[1/1] Fetching ap24-mod_maxminddb-1.2.0.txz: 100% 10 KiB 10.6kB/s 00:01
Checking integrity... done (0 conflicting)
[1/1] Installing ap24-mod_maxminddb-1.2.0...
[1/1] Extracting ap24-mod_maxminddb-1.2.0: 100%
[root@geolocation ~]$
With the module in place it’s time to configure it so it can be used.
Step 3. Configure mod_maxminddb in Apache HTTP
In this step we just want to configure the use of the mod_maxminddb module in Apache HTTP, so it is enabled on this box. On later steps we’ll make the necessary changes to adequate it to different ways of managing site visitors based on IP geolocation.
We’ll create a configuration file in the modules.d directory in Apache HTTP first.
[root@geolocation ~]$ cd /usr/local/etc/apache24/modules.d
[root@geolocation /usr/local/etc/apache24/modules.d]$ sudo touch 200_mod_maxmindb.conf
[root@geolocation /usr/local/etc/apache24/modules.d]$
Now we’ll edit the file with some configuration bits.
LoadModule maxminddb_module /usr/local/libexec/apache24/mod_maxminddb.so
<IfModule mod_maxminddb.c>
MaxMindDBEnable On
MaxMindDBFile COUNTRY_DB /usr/local/share/GeoIP/GeoLite2-Country.mmdb
MaxMindDBEnv MM_COUNTRY_CODE COUNTRY_DB/country/iso_code
</IfModule>
Tip: For more directives about this module read the following guide from MaxMind in Github.
https://github.com/maxmind/mod_maxminddb
With the module enabled in Apache HTTP to make use of MaxMind databases it’s time to set the automatic retrieval of updated geolocation databases.
Step 4. Automatically receive geolocation database updates
To get regular updated geolocation database information we do only need to add a cronjob in our server. This way we’ll receive automated updates without the hassle to manually perform them.
After issuing the following command add the data below it.
root@awstats:~ # crontab -e
Data:
SHELL=/bin/sh
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin
# Order of crontab fields
# minute hour mday month wday command
0 0,12 * * * /usr/local/www/awstats/cgi-bin/awstats.pl -update -config=awstatsdemo.com
1 0 * * 1,3 /usr/local/bin/geoipupdate
With this in place we’ll get updates every Monday and Wednesday at 00:01 hours.
Time now to plot different scenarios to make use of these IP geolocation databases.
Step 5. Examples on how to manage site visitors based on IP geolocation
In this step we’ll see a few examples on how to manage traffic based on IP geolocation such as redirects, blocking countries and allow some countries while avoiding others.
Example1. Redirect traffic based on IP geolocation
In order to redirect traffic at all we need to make sure the redirect module is enabled in Apache HTTP. For that we’ll use the following command.
[root@geolocation ~]$ apachectl -M | grep rewrite
rewrite_module (shared)
[root@geolocation ~]$
We need to see that rewrite_module appearing. Otherwise, the module is not set up. In case it’s not enabled for you use the following command to look for the line the directive sits.
[root@geolocation ~]$ grep -n 'rewrite' /usr/local/etc/apache24/httpd.conf
184:#LoadModule rewrite_module libexec/apache24/mod_rewrite.so
[root@geolocation ~]$
Once you know what line to uncomment (remove the ‘#’ hashtag symbol at the beginning of the line) you can edit the config file with your favorite editor.
At the bottom of the Apache HTTP main configuration file, we will place the configuration bits for this redirection. Those directives can be also placed in different configuration files, such as the (often abused .htaccess) and the virtual host ones.
Let’s say one wants to redirect users coming from IPs located in Spain. First, we’ll place an index.html file within a subdirectory for the Spanish site.
Since we haven’t yet created the directory we’ll do just that.
[freebsd@Geolocation /usr/local/www/apache24/data]$ sudo mkdir es
[freebsd@Geolocation /usr/local/www/apache24/data]$ ll es
total 9
drwxr-xr-x 2 root wheel 2B Sep 26 13:49 .
drwxr-xr-x 7 root wheel 8B Sep 26 13:49 ..
[freebsd@Geolocation /usr/local/www/apache24/data]$
We get into the recently created ‘es’ directory and create an empty ‘index.html’ file.
[freebsd@Geolocation /usr/local/www/apache24/data]$ cd es
[freebsd@Geolocation /usr/local/www/apache24/data/es]$ sudo touch index.html
Now the file is create we’ll use a one liner to the file.
[freebsd@Geolocation /usr/local/www/apache24/data/es]$ sudo echo '<html><body><h1>Funciona!</h1></body></html>' | sudo tee /usr/local/www/apache24/data/es/index.html > /dev/null
With the ‘cat’ command we check the content we need inside the file has been correctly written.
[freebsd@Geolocation /usr/local/www/apache24/data/es]$ cat index.html
<html><body><h1>Funciona!</h1></body></html>
[freebsd@Geolocation /usr/local/www/apache24/data/es]$
What are the redirect directives one must place in Apache HTTP configuration for a visitor with a Spanish IP to be redirected to a specific site for them?
The following ones will do the trick.
RewriteEngine On
RewriteCond %{ENV:MM_COUNTRY_CODE} ^(ES)$
RewriteRule ^(.*)$ https://albertvalbuena.com/es$1 [R,L]
Remember to restart Apache HTTP whenever you apply changes, so they take effect.
[freebsd@Geolocation ~]$ sudo service apache24 restart
Performing sanity check on apache24 configuration:
Syntax OK
Stopping apache24.
Waiting for PIDS: 10861.
Performing sanity check on apache24 configuration:
Syntax OK
Starting apache24.
[freebsd@Geolocation ~]$
Visiting the site, from a Spanish based IP, you should be presented with the redirect notice.
Tip: For you not to lose that ability to redirect any visitors to an encrypted TLS connection, just place the following directives at the bottom of all the geolocation redirects you may need.
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://albertvalbuena.com$1 [R,L]
But what are the configuration bits for more than one country, or two, or three? Let’s say you want to redirect visitors from Spain, Germany and Australia to their respective sites and leave the rest of the world to visit a generic site at the root of your directories.
These will come handy.
RewriteEngine On
RewriteCond %{ENV:MM_COUNTRY_CODE} ^(ES)$
RewriteRule ^(.*)$ https://albertvalbuena.com/es$1 [R,L]
RewriteEngine On
RewriteCond %{ENV:MM_COUNTRY_CODE} ^(DE)$
RewriteRule ^(.*)$ https://albertvalbuena.com/de$1 [R,L]
RewriteEngine On
RewriteCond %{ENV:MM_COUNTRY_CODE} ^(AU)$
RewriteRule ^(.*)$ https://albertvalbuena.com/au$1 [R,L]
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://albertvalbuena.com$1 [R,L]
Time now to restart Apache HTTP, so these directives are effective.
Tip: For these directives to successfully work just remember to repeat the process of creating a subdirectory for them with an index.html file on each. Change, if you want, the default content, so for example you’re welcomed with a specific message for each geolocation. With these little changes you will be assured of visiting and seeing the right content for each location.
After restarting Apache HTTP it’s a good idea to make use of the VPN service you have contracted or built to make your testing of this configuration. Just switch from country to country so you get a new IP on your testing rig and start visiting the domain name you are using. Do also mind browsers use cache and you want to do this testing in “Incognito Mode” and even close the full window and open it back again so it unloads all the information it has on the site.
When I was connected to a Spanish IP this is what I got when I visited my .com site.
This is what I got when I switched to a German IP.
Then I switched to an Australian IP and this is what I saw.
And finally, I went to a French IP so no bit of configuration concerning those countries applied so I could check if that root international site was presented or something else had to happen.
So, if the results satisfy you, you’ve achieved the goal to apply a redirect to visitors based on IP geolocation. Don’t panic if a specific country isn’t working. MaxMind databases are quite accurate but remember those IP slots may change from time to time and you are using the free version!
Tip: If you want to redirect several countries to one specific site just apply some formula like this one with a “pipe-like” sign, as seen in the following setup for English speaking countries.
RewriteEngine On
RewriteCond %{ENV:MM_COUNTRY_CODE} ^(UK|IE|IM|US|CA|AU|NZ)$
RewriteRule ^(.*)$ https://albertvalbuena.com/english$1 [R,L]
Example 2. Blocking access to a site based on IP Geolocation.
This is a different approach to the first one. Directives are different, don’t mix both approaches unless you know how to adapt each.
For this setup we’ll slightly modify the directives we’ve used at the third step of this very article. Let’s see the actual content that should be in Apache HTTP to make use of MaxMindDB.
[freebsd@Geolocation /usr/local/etc/apache24/modules.d]$ cat 200_mod_maxminddb.conf
LoadModule maxminddb_module /usr/local/libexec/apache24/mod_maxminddb.so
<IfModule mod_maxminddb.c>
MaxMindDBEnable On
MaxMindDBFile COUNTRY_DB /usr/local/share/GeoIP/GeoLite2-Country.mmdb
MaxMindDBEnv MM_COUNTRY_CODE COUNTRY_DB/country/iso_code
</IfModule>
[freebsd@Geolocation /usr/local/etc/apache24/modules.d]$
What configuration should we use instead? What about blocking a series of countries’ IPs? Let’s say we don’t want visitors from China and Russia. The following directives will do just that.
<IfModule mod_maxminddb.c>
MaxMindDBEnable On
MaxMindDBFile COUNTRY_DB /usr/local/share/GeoIP/GeoLite2-Country.mmdb
MaxMindDBEnv MM_COUNTRY_CODE COUNTRY_DB/country/iso_code
<Location />
SetEnvIf MM_COUNTRY_CODE ^(CN) BlockCountry
SetEnvIf MM_COUNTRY_CODE ^(RU) BlockCountry
Deny from env BlockCountry
</Location>
</IfModule>
What is the difference from the old configuration?
<Location />
SetEnvIf MM_COUNTRY_CODE ^(CN) BlockCountry
SetEnvIf MM_COUNTRY_CODE ^(RU) BlockCountry
Deny from env=BlockCountry
</Location>
As it can be seen we are now using the Location directive in Apache HTTP and setting an environment variable that implies visitors from China and Russia.
With this setup you will block any visitors from the countries you declared based on IP Geolocation.
Example 3. Allow access to a site based on IP Geolocation.
This is a very similar setup to the one in example two in this article. However, one must note that any visitor from a country that isn’t allowed won’t be able to visit the site, unless using some sort of geolocation modification, such as a VPN.
The directives to place to allow only specific countries, also leveraging the Location directive in Apache HTTP, are:
<Location />
SetEnvIf MM_COUNTRY_CODE ^(ES) CountryList
Require env CountryList
</Location>
With this setup only visitors from an IP geolocated in Spain will be allowed to visit the site.
Conclusion.
Setting up an IP geolocation-based site isn’t that difficult. If you have one server and several custom pages dedicated to specific languages or regions this setup can perfectly work for you. However, if you were looking for a different solution such as a setup with several servers distributed in different locations this Apache HTTP official documentation entry may be helpful.
Extra tip. In this link you will find the Wikipedia entry for the ISO 3166 country codes.
If you find the articles in Adminbyaccident.com useful to you, please consider making a donation.
Use this link to get $200 credit at DigitalOcean and support Adminbyaccident.com costs.
Get $100 credit for free at Vultr using this link and support Adminbyaccident.com costs.
Mind Vultr supports FreeBSD on their VPS offer.