Blazing Geo Lookups! How To Install Maxmind PHP Extension on Your Server

So there other day, while getting a burst of PPV traffic, I tried to load my landing page and it crapped out. More specifically, the page sort of half loaded then stopped. It turns out, the free maxmind javascript code that I was so fond of was hanging up my whole page. The maxmind server was out to lunch (or throttling my greedy PPV pop traffic) and I was losing coin.

What to do? Well, Maxmind was nice enough to offer a couple of more free solutions. They both involve downloading the database and self-hosting it. Sweet! You can read more here on their GeoLite City page.

Once you’ve got the database, you can access the GeoIP PHP API by using the “pure PHP module”, or you can use the PHP Extension on PECL.

The pure PHP module is cake to install. Great! The PHP Extension, however, can be confusing to install and finding proper directions to do so is almost impossible. So why even consider using it?

Speed Kills

According to maxmind api benchmarks, doing GeoIP City lookups, you can expect the following performance:

Pure PHP API (with no cache) handles 619 queries/second

C API / PHP Extension (with no cache) can do 22,211 queries/second

Holy crap! I’m in.  The PHP Extension is basically a wrapper for the fast C code, so you get a dramatic performance gain.  When your server is getting pounded with traffic, this can make a huge difference.

Let’s begin, shall we?

Step 1: Create & Upload Geotest.php

Create a new file, paste in the following code, and upload it to your web root as “geotest.php”.

if ( function_exists ('geoip_record_by_name') ) {
    $geo = geoip_record_by_name( $_SERVER['REMOTE_ADDR'] );
    echo "<h1>How's the weather in $city, $region?</h1>";

Once it’s uploaded, navigate to the URL (e.g. and you should see a bunch of PHP Info.

Step 2: Login to your server as root via SSH

If you already know how to do this, go ahead and login and move on to Get Your Shell On

The first thing you’ll need is an SSH client. If you don’t have one, most people use PuTTY. It’s free and just works. If you want a slicker version, check out PuTTY Tray. PuTTY Tray has some refinements like better minimize options, configurable windows transparency, hyperlinking, portability features, etc.

After you get PuTTY running, enter your host name (or IP address), your port number (many hosts change it from the usual ’22’), and then click Open.

If you get a message warning you about the server host key, it’s OK to click ‘Yes’ and trust this connection. When the terminal window opens, you will be asked for your login in and password. Go to town!

Get Your Shell On

Important Stuff
First of all, messing around on your server like this is NOT hard. But if you’re careless you can very easily get into trouble.

Think of the command line as one of those people you meet in a seedy, border-town bar at 4AM. It’ll happily go along with any of your stupid, dangerous, wicked, or depraved schemes — no questions asked. It doesn’t give a shit. YOU have to be the sensible one.  You’re running with scissors. Pay attention, and keep your wits about you. Remember: I am not responsible if you jack up your server. So just take your time, and you’ll be fine.

Now, if you’re already pussing out after that last paragraph, then go ahead… pull up your skirt and run home Mary. Call tech support and have them do this for you.  And don’t forget to have them cut the crusts off your PB&J while they’re at it.  We won’t snicker at you… at least not to your face.  Now get out of my sight, you make me wanna puke.

Tough Guys (and Gals) Read On

The following are shell commands you need to do one after the other. Take note: PuTTY has a curious way of working. You can’t simply do a “ctrl-v” in in the window to paste stuff. To paste, you need right-click your mouse and the text on your clipboard will be pasted into the terminal window wherever the cursor is. Lame, I know.

So just to be crystal clear: in Step 3, below, you first copy & paste “mkdir /geotemp” into the terminal window, then press [ENTER]. Then you paste “cd /geotemp” [ENTER].   Monkey see, monkey do 😉

Step 3: Let’s Make a Work Directory

This will just be a place to download and unzip all the files we need.

mkdir /geotemp
cd /geotemp

Step 4: Get the GeoIP C Library

The above link is just for reference.  We’re going to download directly to our server using wget.  Note, line 4 is highlighted. The directory *may* be different on your server. Each time this library get’s updated, the filename inside the archive is changed. That’s the reason for the “ls” command. It will show you a directory listing so you can double check your filename.

tar xvfz GeoIP.tar.gz
cd GeoIP-1.4.8
make install
cd /geotemp

Step 5: Get the PHP Extension

There are easier ways to do this step. But I ran into some stupid compiling permissions problem. By doing it this way, I’ve had success on 3 different server setups.

tar xvfz geoip-1.0.7.tgz
cd geoip-1.0.7
make install

That last command you did ‘make install’ will output the path to the new extension.

Installing shared extensions:     /usr/local/lib/php/extensions/no-debug-non-zts-20090626/

You need to copy that path and use it in step 7.  So using your mouse, highlight that path.  (In PuTTY, any text you highlight is copied to the clipboard.)   Now open up Notepad and paste it so we can use it later.

Step 6: Get the GeoLite City DB

We’re downloading and unarchiving again. The only thing worth noting is when we move the GeoLiteCity.dat file to the proper directory, we’re also renaming it. The PHP Extension expects to find a file named GeoIPCity.dat, not GeoLiteCity.dat.

cd /geotemp
gzip -d GeoLiteCity.dat.gz
mv GeoLiteCity.dat /usr/local/share/GeoIP/GeoIPCity.dat

Step 7: Edit our php.ini file

Note the highlighted line. On both an Apache and a LiteSpeed server, the php.ini file is in this directory: /usr/local/lib as I’ve written below. However, your setup might be different. It would be wise to check that test page you uploaded in Step 1. You can find the correct directory where it says “Loaded Configuration File”

cd /usr/local/lib
vi php.ini

The last command “vi” opened an editor.   When it opens, you should see a bunch of stuff.  This is your php.ini file   If you don’t see anything and/or it says “[New File]” at the bottom, then you either mistyped or your php.ini file isn’t in this directory (see above.)   OK… so if you’re good, and you see a bunch of php directives, we need to get to the bottom of the file. To do that, press “G”. Now we need to insert the following lines at the bottom of the file. To do that, press “I” ([i]nsert.)  You can now move the cursor, and add the new lines as you see them here:

extension_dir = "/usr/local/lib/php/extensions/no-debug-non-zts-20090626/"

NOTE:  The highlighted line with “extension_dir =” is specific to my server.  Yours will be different.   Use the path you pasted into Notepad instead of the one I have here.

Once you’ve added the lines, press ‘Esc’. Then type “:wq”. (That is a colon followed by [w]rite [q]uit.) You will exit the editor.

Step 8: Restart the Web Service

Now that the editor is closed, we’re back at the command prompt.  To make PHP recognize the new extension and settings we need to restart Apache (or Litespeed).

service httpd restart

Step 9: Test

Now visit the page:

You should see something like this:

Mission Accomplished!

If all went well, nice job! Using the code I gave you way back in Step 1, you can now add geo functionality to any of your landing pages on this server.

If you get an error or run into problems, then retrace the steps above and make sure you did everything correctly.

If you don’t see the “How’s the weather” message, first check to make sure PHP has found and loaded the extension.  Do a search for “geoip” on the test page.  If PHP found the extension, it will show up here among all the other info.   If you don’t see it on this page, then PHP can’t find it or maybe never loaded it.   Maybe you goofed up the ‘extension_dir =’ in step 7?  You should have used info from Step 5.    Another thing to check is maybe you didn’t restart your httpd service properly?  Try doing that again and it should force PHP to reload the ini file and see the new extension.

If you still can’t figure it out, bug your hosting support guys. Your server config is probably a bit different and they will be able to figure out what’s wrong and sort it out quickly.

Leave a comment



CommentLuv badge


  • Great post man! I’ve been usually installing the Apache MOD extension from MaxMind and quite frankly I couldn’t write out instructions since I always stumble around for three hours until it works. This is a really good guide.

    • Man, I totally know what you’re talking about! I tried the Apache mod first. I got it installed but never got it to work.

      I then spent another 2 hours trying to install some “new, better” PHP Extension some guy had on github. Finally I got the original one working. I took good notes because I didn’t want to have to go through that ordeal again 😉

      Thanks for reading & commenting!

  • Works like a charm! The only differnce that I’ve used “WinSCP” over Putty, but that’s probably a matter of taste 😉

    Oh and I installed this on a Storm On Demand Cloud VPS server and you can literally follow step-by-step. Great share, thanks again!

    btw: Is there a reference on which PHP variables you can use to put country, city, zip etc. on your pages?

    • I forgot all about WinSCP. Also a good choice.

      I’m glad everything went smoothly. 😉 To see a list of all the values in the array, you can do this:

      print_r(geoip_record_by_name( $_SERVER[‘REMOTE_ADDR’] ) );

      You get something like this:

      Array ( [continent_code] => NA [country_code] => US [country_code3] => USA [country_name] => United States [region] => CA [city] => San Diego [postal_code] => 92103 [latitude] => 32.7448005676 [longitude] => -117.170196533 [dma_code] => 825 [area_code] => 619 )

      Assuming you use the code I gave you, the extract command populates the variables according to key name. So, $country_name will contain “United States”.

      Thanks for reading & commenting.

  • Peter

    Hey, I’m from MaxMind. Thanks for putting this together, we are going to link to it on our site since it will be very, very helpful to a lot of our users.


    • Cool, glad you like it. And thanks for offering this free db!

  • I was using another Geo-Targeting solution but I just followed this step by step guide and it was as easy as 1-2-3.

    What about making a sequel to this post to explain the steps to update the Geo-Database every month?

    • Good idea. Thanks for reading!

  • Guys, here’s how I update the MaxMind database every month:

    I create a text file inside /etc/cron.monthly which is where CentOS has the monthly scripts. I set the permissions to allow execute (chmod 755), and inside the file put this:

    cd /usr/local/share/GeoIP/
    cp -f GeoLiteCity.dat GeoLiteCity.dat_orig
    wget -N
    gunzip -f -c GeoLiteCity.dat.gz > GeoLiteCity.dat

    The first line is where the GeoIP database lives when I do the Apache mod install.
    The second line renames the original UNCOMPRESSED file.
    The third line retrieves the new databse ONLY IF the file is newer than the GeoLiteCity.dat.gz file the lives in the current directory (which was set on the first line)
    The final line unpacks the database into the expected filename (regardless if the file is newer or not, its not like I’m paying by the CPU cycle).


    • Very nice! I’m going to set this up on all my boxes.

  • I’ve always used the MySQL + PHP setup from Maxmind for a long time, but setting it up on different servers was always a pain.

    This is a great tutorial, I can’t wait to implement this and delete my old Geo databases.


    – Chris

    • Glad you like it. This setup should reduce the load on your server and be faster than the MySQL setup. And as for updating, a few comments up Negbox posted a mini-guide to setting up a cron for auto updates.

      Thanks for reading and commenting!

      • Got it installed, everything went smooth with your guide, thanks!

        Although I am getting some discrepancies between the GeoIP results from the Javascript API and the PHP Ext.:

        Any idea what’s causing this? Their IP lookup must be using different datasets for each? Or it could be my small town is hard to find :P, nevertheless the Javascript API can still find it.

        Hopefully that Peter guy from Maxmind can chip in some info too.

        – Chris

        • I think they’re using different data. I’ve seen differences in results too. Maxmind has a forum, it’s not very active but it might have the answer.

  • polarbacon

    I know we like tech here….so I will just post an opposing strategy that worked well for me…and was far less work….

    (SOD)”Hi this storm on demand how can I help you.”

    (me)”ya can you install this apache mod on my server”

    (SOD)”sure but we can’t support the script”

    (me)”ok no problem, I will take care of support”

    (SOD) “ok great I will email you when its installed”

    (me)”thank you have a great day”

    query as needed across the entire server via


    $country_code = apache_note(“GEOIP_COUNTRY_CODE”);
    $country_name = apache_note(“GEOIP_COUNTRY_NAME”);
    $city_name = apache_note(“GEOIP_CITY”);
    $region = apache_note(“GEOIP_REGION”);
    $metro_code = apache_note(“GEOIP_DMA_CODE”);
    $area_code = apache_note(“GEOIP_AREA_CODE”);
    $latitude = apache_note(“GEOIP_LATITUDE”);
    $longitude = apache_note(“GEOIP_LONGITUDE”);
    $postal_code = apache_note(“GEOIP_POSTAL_CODE”);

    • Cheater.

      But thanks for the info 😉 Definitely a simple way to go. Thanks for reading and posting.

  • Venture77

    Can some one kindly let me know what changes I need to do if I want to install the geolitecountry rather than city?

    I have tried changing the step 6 to download the geolitecountry database but when i execute the php file I get the following error.

    – Databse not found GeoIPCity.dat

    Thanks in advance!

    • You do realize that GeoIPCity contains the country info as well, don’t you? As far as I know, the geolitecountry DB is a subset of what’s included in the city DB.

      • Venture77

        Hi thanks for the reply. I am able to get the country info from your method and it is working 100% but I noticed that database for GeoIPCity.dat is much bigger in size than the GeoIP.dat. I was thinking that could have an impact on the performance of my server (since it has to parse through unwanted data).

        Please correct me if I am wrong. Thanks.
        P.S site gets lot of requests at peak time (around 100K to 200K visitors may try to connect within a 10-20 minute period)

  • I remember browsing across this post a while back and today finally had a need to come grab it! Thanks for the info!
    Mike Chiasson’s latest blog post: Affiliate Summit West 2012, Wicked Cool!

  • Chris

    Is there an easy to display the US State name in its entire length and not the abbreviation? So, instead of “CA” I want to display “California”. Thank you.

  • LeftH

    I tried these steps but I’m hung up on Step 4…

    In step 4, after entering line 5 (./configure), it runs a bunch of stuff that looks correct but then I get the below message:

    “configure: error: Zlib header (zlib.h) not found. Tor requires zlib to build. You may need to install a zlib development package.”

    I did try to just continue on with the next lines just to see, but it doesn’t look like it works.

    What to do in this spot?

    • Hmm.. I can’t really debug your issue. Best way to go is contact your hosting tech support.

  • Hi Mark,

    Thanks for the guide. It is so easy that I can just drop this link over at the support desk of my hosting provider and they compile and setup the C API in a few minutes.

    • You’re welcome! Thanks for reading.

  • Andy


    Thanks a lot for this post. You saved me tons of time today!

    • Sweet. Thanks for reading Andy!

  • Hi Mark!

    Thanks for the tutorial; I’ve successfully added the geolite database. Easy even for a non techie! I have a question though, for the initial code do you have to keep using the whole chunk of code for each variable u’d like to add in the landing page? I mean;

    if ( function_exists ('geoip_record_by_name') ) {
    $geo = geoip_record_by_name( $_SERVER['REMOTE_ADDR'] );
    echo "How’s the weather in $city, $region?”;

    Then somewhere else you’d like to reference city or country or something
    Do you have to enclose the whole thing with the same code and echo $country_name, or could you just use echo elsewhere? Sorry man, coding idiot. Can follow; not code =)

    • I took a look at one of my php landing pages and I realized all I need to do is to

      whereever or whatever is needed.

      Thanks Mark for this wonderful tutorial! Still figuring out how to code a LP from scratch and I’ll get the LPG for sure.

  • Hallo Super Plugin habe piwik geoip sowie geomap in der nsueten Version neuinstalliert le4uft alles Super audfer Bericht downloaden da bleibt die Seite weidf und Mann kann bis zum Nimmerleinstag warten und bei Bericht senden kommt folgender Fehler: API returned an error: Die Methode index’ existiert nicht oder ist im Modul Piwik_GeoIPMap_API’ nicht verffcgbar.Ich danke ffcr deine Hilfe


[…] post from CTRTard on how to install the Maxmind GeoIP extension. I did this a few months back (all by myself, somehow…) and it’s significantly faster […]

Blazing Geo Lookups! How To Install Maxmind PHP Extension on Your Server [Link] « September 14, 2011

[…] couple of years ago I posted “Blazing Geo Lookups! How To Install Maxmind PHP Extension on Your Server” which detailed how to get the Maxmind’s GeoIP database setup on your […]

Blazing Geo Lookups! How To Install Maxmind PHP Extension on Your Server [Link] « April 22, 2014


Related posts by category

Related posts by tag