Part 2
The second part of this guide
The first part of this guide is here
So after all of that how do you go about implementing your geo-targeting DNS server? Well, thankfully most of the work is already done for you thanks to support written into the open source PowerDNS server by the blitzed.org IRC crew back in 2003, so the only real difficulty is configuring it properly. For this one needs to follow the instructions given in the PowerDNS geobackend given at http://wiki.powerdns.com/trac/browser/trunk/pdns/modules/geobackend/README and indeed these are what I followed. However, some of the links and resources given there have expired in the past seven years, and moreover there is nothing as quick and efficient as copying & pasting from someone else's config files and then customising as necessary.
First things first: You need an EXCELLENT VPS!
There are a LOT of budget VPS providers out there, the smallest packages of most of whom are listed at the famous http://www.lowendbox.com/ and I would strongly suggest that you consult there. A DNS server is very undemanding on modern machines: a 10Mbit network connection will be more than plenty, as is 128Mb of RAM and maybe 4Gb of disc space and an OpenVZ type VPS (the cheapest and nastiest kind) is just fine. You can easily pick up a VPS like this for US$5/month most of whom will be run by incompetent cowboys or even high school students, so I suggest that you do your homework carefully by searching WHT (http://www.webhostingtalk.com/) for user experiences.
One of the most important parts of choosing the ideal VPS for your DNS server is its network location i.e. somewhere with the lowest ping times internationally. The ideal location for this presently is somewhere very near New York - try http://just-ping.com/ with http://www.interserver.com/ and you'll see what is nearly as good as it gets before needing anycast IP to do better (Interserver have a long established reputation for outstanding premium network connectivity). Unfortunately because it's so great anything near NYC tends to be pricey, so you may have to balance international ping times with moving a bit further away. A very popular location with budget VPS providers because of its affordability is the Wiresix datacentre in Georgia, Atlanta - you can find out where a VPS is using Maxmind's GeoIP tool on the test VPS addresses which most VPS providers will list on their websites. And given its low price, Wiresix is well connected with only a few packet loss and routing problems from the Middle East and such.
If you're going to do this properly you're going to need TWO DNS servers, one for primary and the other for secondary. Because the IP returned will vary according to the requester's location you CAN'T use the standard secondary DNS services offered by third parties (often for free) - you'll just have to do your own secondary backup DNS. I'd suggest for the secondary finding a VPS somewhere in Western Europe - it's still pretty well connected internationally, it's still affordable and it's on a different continent which helps with redundancy.
Second step: You need at least one GOOD master server and at least one REASONABLE slave server
Normally one would choose a higher quality provider for their main server because the budget providers tend to be locally very well connected but very badly connected internationally. The classic example of this is OVH, the biggest European dedicated server provider, who have excellent European connectivity but deliberately downgrade any traffic going external. In fact because they do this to save on costs, they only accept customers who live in European countries as otherwise much more traffic would go external (and thus their costs would rise).
Ordinarily you would only consider a provider such as OVH if your site was exclusively used by Europeans. However, thanks to geo-targeting, this increases our flexibility somewhat. I would suggest when you are choosing your dedicated server or high end VPS that you consult http://www.lowenddedi.net/ which holds a database of low end dedicated server providers along with mini-reviews (note that I operate Low End Dedis).
Anyway, my point is that you can go for the low end when geo-targeting and save yourself a lot of money when doing so. Remember that a top end VPS can often be cheaper and better than a low end dedi (VPSs with 2Gb of RAM or more ARE listed on Low End Dedis), however I would strongly recommend that your primary master server from which geographical slaves mirror ought to always, always, always be a fully dedicated server as you can then configure some very fancy firewall security for the mirrors.
Setting up the DNS server
The instructions below are for Ubuntu 9.10 Server/Debian. Other Linuxes will vary.
First off do a top and apt-get remove anything which you don't need. Many VPS providers have bind and apache installed by default - you really don't want either on a small VPS.
Next do apt-get update, then apt-get upgrade, then reboot.
Now do apt-get install pdns-server pdns-backend-geo rsync. We will be using the bind backend as it's fast, doesn't use much memory and doesn't require a hefty MySQL instance running.
Now do a cd ~ to get into the root home directory and nano updatezoneinfo.sh:
#!/bin/sh
rsync -avvz rsync://countries-ns.mdc.dk/zone/zz.countries.nerd.dk.rbldnsd /root/zoneinfo
Do a chmod oug+x updatezoneinfo.sh, then a mkdir zoneinfo and ./updatezoneinfo.sh. This will rsync a file called zz.countries.nerd.dk, an IPv4 mapping file generated by enthusiasts more about which can be found here.
You now want this updated weekly, so do a crontab -e and:
# m h dom mon dow command
0 7 * * 0 /root/updatezoneinfo.sh > /dev/null
Now it's time to configure PowerDNS, so nano /etc/powerdns/pdns.d/pdns.local:
# Here come the local changes the user made, like configuration of
# the several backends that exist.
setgid=pdns
setuid=pdns
#loglevel=7
log-dns-details=no
# Speedups
wildcards=no
distributor-threads=1
# Configure as master allowing axfr's to secondary
master=yes
disable-axfr=no
#allow-axfr-ips=
# We're using bind style database and geotargeting
launch=bind,geo
bind-config=/etc/powerdns/named.conf
bind-check-interval=300
query-cache-ttl=0
cache-ttl=0
geo-zone=geo.nedproductions.biz
geo-soa-values=ns1.nedproductions.biz,hostmaster@nedproductions.biz
geo-ns-records=ns1.nedproductions.biz,ns2.nedproductions.biz
geo-ip-map-zonefile=/root/zoneinfo/zz.countries.nerd.dk.rbldnsd
geo-maps=/root/geomaps
We disable the query cache and multithreading because with the bind backend being so quick it's actually faster (and uses less memory). Next comes a bind style named.conf, so nano /etc/powerdns/named.conf:
zone "nedproductions.biz" IN {
type master;
file "/etc/powerdns/zones/nedproductions.biz.zone";
};
zone "neocapitalism.org" IN {
type master;
file "/etc/powerdns/zones/neocapitalism.org.zone";
};
<and so on ...>
# Reverse DNS
zone "166.121.91.in-addr.arpa" IN {
type master;
file "/etc/powerdns/zones/nedproductions.biz.rr.zone";
};
<and so on ...>
Here you need to define each and every of your domains which will be served. You will need to choose a primary geotargeting domain which will do all the grunt work for you and then have all other domains vector through the primary domain resolution. In our case nedproductions.biz is the primary domain.
Next thing you need are zone entries, so mkdir /etc/powerdns/zones and nano each of the domain zones you defined above into existance. To save you much time and hassle, I'd suggest something like this:
$INCLUDE /etc/powerdns/zones/nedproductions.common
; Send all www traffic to the www.geo. service
www IN CNAME www.geo.nedproductions.biz.
... for the primary domain and something like this:
$INCLUDE /etc/powerdns/zones/nedproductions.common
; Send all www traffic to the www.geo. service
www IN CNAME www.neocapitalism.org.geo.nedproductions.biz.
... for each of the other domains. Note how we prepend the other domain in front of the geo.nedproductions.biz but after the www. Then define the common zone config like this:
; BIND db file for nedproductions.biz
$TTL 60
@ IN SOA ns1.nedproductions.biz. hostmaster.nedproductions.biz. (
2010013001 ; serial number YYMMDDNN
28800 ; Refresh
7200 ; Retry
864000 ; Expire
38400 ; Min TTL
)
; The "clean" use of a domain must ALWAYS use an A record
; The web server running at @ simply does a HTTP 301 to www.
IN A 98.142.216.143
IN NS ns1
IN NS ns2
IN NS ns3
IN NS ns4
IN NS ns5
IN MX 10 mail
; ipv6. always goes to europe1
ipv6 IN CNAME ipv6.europe1
; Always send email to europe1
mail IN A 94.23.159.78
mail IN AAAA 2001:41D0:1:E74a::1
; Our server clusters
ns1 IN A 98.142.216.143 ; me
ns2 IN CNAME NS1.EVERYDNS.NET.
ns3 IN CNAME NS2.EVERYDNS.NET.
ns4 IN CNAME NS3.EVERYDNS.NET.
ns5 IN CNAME NS4.EVERYDNS.NET.
europe1 IN A 94.23.159.78
; Unfortunately geotargeting isn't currently working with IPv6
;europe1 IN AAAA 2001:41D0:1:E74a::1
ipv6.europe1 IN AAAA 2001:41D0:1:E74a::1
usa1 IN A 98.143.155.171
@ IN TXT "v=spf1 a mx a:smtp.ukfsn.org -all"
_adsp._domainkey IN TXT "dkim=all"
mail._domainkey IN TXT "v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMjaEe954hdYo9v$
; Geoip mapping to our server clusters
; Antartica
an.iso IN CNAME usa1
; Africa
af.iso IN CNAME europe1
; Asia (east of Bangladesh)
as.iso IN CNAME usa1
; Europe
eu.iso IN CNAME europe1
; Middle East (inc India, Pakistan)
me.iso IN CNAME europe1
; North America
na.iso IN CNAME usa1
; Oceania (inc Australia, NZ etc)
oc.iso IN CNAME usa1
; South America
sa.iso IN CNAME usa1
This saves a LOT of time later on and with one fell swoop you can reconfigure lots of stuff at once. For example I have set the TTL to 60 seconds which is a ridiculously short period and not good for your visitors, but it is very convenient for making changes and seeing the results quickly. Once your settings stabilise you can easily up the TTL to 86400s (one day).
Now you surely noticed the mapping of each of the geographical regions to physical servers via CNAME, and we'll get onto that shortly. Before that we must solve a problem: what happens when a visitor goes to the non-www part e.g. http://nedproductions.biz rather than http://www.nedproductions.biz? This is extremely important, much much more so than usual where you typically do a CNAME from www to @ because the www. part is crucial to the geotargeting machinery working correctly. In order words, if you don't use www. then the PowerDNS geo backend doesn't know it is to be invoked and therefore nothing works. Hence you need to make non-www access magically convert into www. accesses.
You'll note that I defined @ as the DNS server - this is because we're going to set up a local web server whose sole purpose is to rewrite the URL into containing a www. To do this, I suggest ngnix as it doesn't use anything like the memory of Apache so do a apt-get install nginx and then nano /etc/nginx/sites-available/default replacing the contents with:
server {
listen 80;
server_name localhost;
access_log /var/log/nginx/localhost.access.log;
location / {
if ($host ~* ^(.*)) {
set $newhost www.$1;
rewrite ^(.*)$ http://$newhost$1 permanent;
}
}
}
This simply rewrites any accesses to use www. via a HTTP 301 Permanently Moved response. By the way you don't need the if() in there, but I may in the future have the DNS server do live server monitoring and if all servers die then I'll want a static error page.
After doing a /etc/init.d/nginx restart, it's time to set up the geomaps which map ISO3166 country codes (which are returned by zz.countries.nerd.dk) onto the eight geographical regions mapped in the zone files. The following is a hard file to find on today's internet - I searched for hours to find the Perl file which generates it, so enjoy! Do nano /root/geomaps/<primary domain> and enter:
$RECORD www
$ORIGIN iso.nedproductions.biz.
# Default
0 eu
# Andorra
20 eu
# United Arab Emirates
784 me
# Afghanistan
4 me
# Antigua and Barbuda
28 sa
# Anguilla
660 sa
# Albania
8 eu
# Armenia
51 me
# Netherlands Antilles
530 sa
# Angola
24 af
# Antarctica
10 an
# Argentina
32 sa
# American Samoa
16 oc
# Austria
40 eu
# Australia
36 oc
# Aruba
533 sa
# Azerbaijan
31 me
# Bosnia and Herzegovina
70 eu
# Barbados
52 sa
# Bangladesh
50 me
# Belgium
56 eu
# Burkina Faso
854 af
# Bulgaria
100 eu
# Bahrain
48 me
# Burundi
108 af
# Benin
204 af
# Bermuda
60 sa
# Brunei Darussalam
96 me
# Bolivia
68 sa
# Brazil
76 sa
# Bahamas
44 sa
# Bhutan
64 as
# Bouvet Island
74 af
# Botswana
72 af
# Belarus
112 eu
# Belize
84 sa
# Canada
124 na
# Cocos (Keeling) Islands
166 as
# Congo, The Democratic Republic of the
178 af
# Central African Republic
140 af
# Switzerland
756 eu
# Cote D'Ivoire
384 af
# Cook Islands
184 oc
# Chile
152 sa
# Cameroon
120 af
# China
156 as
# Colombia
170 sa
# Costa Rica
188 sa
# Cuba
192 sa
# Cape Verde
132 af
# Christmas Island
162 as
# Cyprus
196 me
# Czech Republic
203 eu
# Germany
276 eu
# Djibouti
262 af
# Denmark
208 eu
# Dominica
212 sa
# Dominican Republic
214 sa
# Algeria
12 af
# Ecuador
218 sa
# Estonia
233 eu
# Egypt
818 af
# Western Sahara
732 af
# Eritrea
232 af
# Spain
724 eu
# Ethiopia
210 af
# Finland
246 eu
# Fiji
242 oc
# Falkland Islands (Malvinas)
238 sa
# Micronesia, Federated States of
583 oc
# Faroe Islands
234 eu
# France
250 eu
# France, Metropolitan
249 eu
# Gabon
266 af
# United Kingdom
826 eu
# Grenada
308 sa
# Georgia
268 me
# French Guiana
254 sa
# Ghana
288 af
# Gibraltar
292 eu
# Greenland
304 sa
# Gambia
270 af
# Guinea
324 af
# Guadeloupe
312 sa
# Equatorial Guinea
226 af
# Greece
300 eu
# Guatemala
320 sa
# Guam
316 oc
# Guinea-Bissau
624 af
# Guyana
328 sa
# Hong Kong
344 as
# Heard Island and McDonald Islands
334 af
# Honduras
340 sa
# Croatia
191 eu
# Haiti
332 sa
# Hungary
348 eu
# Indonesia
360 as
# Ireland
372 eu
# Israel
376 me
# India
356 me
# British Indian Ocean Territory
86 as
# Iraq
368 me
# Iran, Islamic Republic of
364 me
# Iceland
352 eu
# Italy
380 eu
# Jamaica
388 sa
# Jordan
400 me
# Japan
392 as
# Kenya
404 af
# Kyrgyzstan
417 me
# Cambodia
116 as
# Kiribati
296 oc
# Comoros
174 af
# Saint Kitts and Nevis
659 sa
# Korea, Democratic People's Republic of
408 as
# Korea, Republic of
410 as
# Kuwait
414 me
# Cayman Islands
136 sa
# Kazakhstan
398 me
# Lao People's Democratic Republic
418 as
# Lebanon
422 me
# Saint Lucia
662 sa
# Liechtenstein
438 eu
# Sri Lanka
144 as
# Liberia
430 af
# Lesotho
426 af
# Lithuania
440 eu
# Luxembourg
442 eu
# Latvia
428 eu
# Libyan Arab Jamahiriya
434 af
# Morocco
504 af
# Monaco
492 eu
# Moldova, Republic of
498 eu
# Madagascar
450 af
# Marshall Islands
584 oc
# Macedonia, the Former Yugoslav Republic of
807 eu
# Mali
466 af
# Myanmar
104 as
# Mongolia
496 as
# Macao
446 as
# Northern Mariana Islands
580 oc
# Martinique
474 sa
# Mauritania
478 af
# Montserrat
500 sa
# Malta
470 eu
# Mauritius
480 af
# Maldives
462 as
# Malawi
454 af
# Mexico
484 na
# Malaysia
458 as
# Mozambique
508 af
# Namibia
516 af
# New Caledonia
540 oc
# Niger
562 af
# Norfolk Island
574 oc
# Nigeria
566 af
# Nicaragua
558 sa
# Netherlands
528 eu
# Norway
578 eu
# Nepal
524 as
# Nauru
520 oc
# Niue
570 oc
# New Zealand
554 oc
# Oman
512 me
# Panama
591 sa
# Peru
604 sa
# French Polynesia
258 oc
# Papua New Guinea
598 oc
# Philippines
608 as
# Pakistan
586 me
# Poland
616 eu
# Saint Pierre and Miquelon
666 sa
# Pitcairn
612 oc
# Puerto Rico
630 sa
# Portugal
620 eu
# Palau
585 oc
# Paraguay
600 sa
# Qatar
634 me
# Reunion
638 af
# Romania
642 eu
# Russian Federation
643 eu
# Rwanda
646 af
# Saudi Arabia
682 me
# Solomon Islands
90 oc
# Seychelles
690 af
# Sudan
736 af
# Sweden
752 eu
# Singapore
702 as
# Saint Helena
654 af
# Slovenia
705 eu
# Svalbard and Jan Mayen
744 eu
# Slovakia
703 eu
# Sierra Leone
694 af
# San Marino
674 eu
# Senegal
686 af
# Somalia
706 af
# Suriname
740 sa
# Sao Tome and Principe
678 af
# El Salvador
222 sa
# Syrian Arab Republic
760 me
# Swaziland
748 af
# Turks and Caicos Islands
796 sa
# Chad
148 af
# French Southern Territories
260 af
# Togo
768 af
# Thailand
764 as
# Tajikistan
762 me
# Tokelau
772 oc
# Turkmenistan
795 me
# Tonga
788 oc
# East Timor
776 as
# Turkey
792 me
# Trinidad and Tobago
780 sa
# Tuvalu
798 oc
# Taiwan
158 as
# Tanzania, United Republic of
834 af
# Ukraine
804 eu
# Uganda
800 af
# United States Minor Outlying Islands
581 oc
# United States
840 na
# Uruguay
858 sa
# Uzbekistan
860 me
# Holy See (Vatican City State)
336 eu
# Saint Vincent and the Grenadines
670 sa
# Venezuela
862 sa
# Virgin Islands, British
92 sa
# Virgin Islands, U.S.
850 sa
# Vietnam
704 as
# Vanuatu
548 oc
# Wallis and Futuna
876 oc
# Samoa
882 oc
# Yemen
887 me
# Mayotte
175 af
# Yugoslavia
891 eu
# South Africa
710 af
# Zambia
894 af
# Zaire
180 af
# Zimbabwe
716 af
Note that the zero country code is what is returned when the IP mapping database doesn't recognise the IP. Now for each non-primary domain you are implementing, do cp /root/geomaps/<primary domain> /root/geomaps/<other domain> and replace the header at the top like this:
$RECORD www.neocapitalism.org
$ORIGIN iso.nedproductions.biz.
# Default
0 eu
In other words you replace the $RECORD with your domain in every geomap except for your primary which gets just "www".
After all of that it's now time to restart PowerDNS using /etc/init.d/pdns restart, ensure its running and now do dig @localhost www.<some domain> to ensure it's working correctly. You should see something like:
root@vps13:/etc/powerdns# dig @localhost www.nedproductions.biz
; <<>> DiG 9.6.1-P2 <<>> @localhost www.nedproductions.biz
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20180
;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;www.nedproductions.biz. IN A
;; ANSWER SECTION:
www.nedproductions.biz. 60 IN CNAME www.geo.nedproductions.biz.
www.geo.nedproductions.biz. 3600 IN CNAME eu.iso.nedproductions.biz.
eu.iso.nedproductions.biz. 60 IN CNAME europe1.nedproductions.biz.
europe1.nedproductions.biz. 60 IN A 94.23.159.78
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Feb 1 00:21:00 2010
;; MSG SIZE rcvd: 121
You ought to try dig @<your DNS server's IP> <your domain> from any SSH servers you may have distributed around the place. Make sure they're mapping okay. If they're not, try reading through the original docs at http://wiki.powerdns.com/trac/browser/trunk/pdns/modules/geobackend/README.
Probably you're now good to go with changing the nameservers for your domains at your domain registrar. Remember that most root nameservers need to think that they see at least two nameservers for a domain in order to accept it. If you can only afford one nameserver then you need to create two subdomains each with the same IP and feed those to the registrar - this seems to bypass the sanity checking in most cases.
Remember that if you're struggling with this then it's probably easier to simply rent someone else's geotargeting DNS services e.g. those of my company ned Productions Ltd. See here for pricing, and contact us if you want to know more.
