GeoIP in Knot DNS 2.7

By on 14 Nov 2018

Category: Tech matters

Tags: , ,


Blog home

The latest release of the CZ.NIC authoritative DNS server, Knot DNS 2.7, comes with several new features. One of them is the GeoIP module for geography-based or subnet-based responses.

In this post, I will briefly explain what the module is for and how it works, and then explore how to set up and configure the module on your Knot server.

How GeoIP in DNS servers work

If you have never encountered GeoIP in DNS, consider the following illustrative example.

Figure 1 — An example of GeoIP in DNS servers in action. Imagine you want to serve your website,, to many clients all over the world. You might store your site data on a single server, accessed by all of your clients. Or you might have multiple copies of the site stored on several data servers around the world.

In the case of the latter, when a client requests the IP address of the server, there are many possible answers. Wouldn’t it be great to choose the server that is the closest to the client and therefore save time on routing and minimize latency?

GeoIP in DNS servers, such as BIND, PowerDNS and now also Knot DNS, is a mechanism that does just that.

Figure 1 illustrates the case where the DNS server makes decisions according to the economy from which the request for your service is coming. If the address of the client is determined to be located in Norway, for example, the DNS server responds with the address of your Norwegian mirror server. However, there is no mirror server for your hypothetical web service in Italy yet, so the DNS server responds to the Italian client with the address of the default data server.

What our module can do

The GeoIP module in Knot can operate in two different modes: subnet and geodb.

In the subnet mode, the appropriate response is chosen based on whether the client’s source address belongs to a particular subnet of IPv4 or IPv6 addresses. This mode is simple to use as it does not require any external databases.

In the geodb mode, the response is chosen based on geographical data associated with the client’s address, which is retrieved from an external GeoIP database in the MaxMind format, such as GeoIP2 or the free GeoLite2. Depending on the database and the configuration of the module, the choice of the response may be tailored according to the client’s continent, economy, city, Autonomous System Number (ASN), Internet Service Provider (ISP) and more.

Finally, our GeoIP module also has DNSSEC support, which can be enabled in multiple ways. See the documentation for details.

How to use it

The following section comprises a short tutorial on a simple configuration of the GeoIP module. For help with more complicated scenarios, consult our documentation or ask us.


To walk through the tutorial you need to have Knot DNS 2.7.0 or a later version installed (download), and a DNS lookup utility, either our kdig or ISC BIND’s dig.

To test the geodb mode of the module, download and unzip the free GeoLite2 City database. It is of course very useful to have experience in configuring and operating Knot DNS. Finally, create a tiny zonefile for our examples, with the following content:

$TTL 3600
@    SOA (
            2010111213  ; serial
            6h          ; refresh
            1h          ; retry
            1w          ; expire
            1d )        ; minimum

     NS     dns1
dns1 A
www  A
     TXT    "default server"


We will use a total of three short configuration files in our setup — the main server configuration file (for example /etc/knot/knot.conf), one file for the module in the subnet mode (let’s name it net.conf), and one for the geodb mode, which we will name geo.conf.

To try out both of the described modes of the module, we will add two mod-geoip sections to the main server configuration file. We will also enable the EDNS Client Subnet option in the server section, which we will later use to test if everything works correctly. This is what the entire miniature configuration file may look like:

    edns-client-subnet: on

  - id: net 
    config-file: "/path/to/net.conf"
    mode: subnet

  - id: geo 
    config-file: "/path/to/geo.conf"
    mode: geodb
    geodb-file: "/path/to/GeoLite2-City.mmdb"
    geodb-key: [country/iso_code, city/names/en]

  - domain:
    file: "/path/to/"
    module: mod-geoip/net
    module: mod-geoip/geo

This configuration creates two instances of the GeoIP module with separate IDs and configuration files. The geodb-file option specifies the location of the MaxMind database to be used. Here we use the GeoLite2 City database, which we downloaded at the start. The geodb-key option specifies a list of database keys according to which the responses will be tailored. Here we use the client’s economy referred to by its ISO code, and if available, their city specified by its name in English (note that the order in which the keys are given is important).

The next step is to create the module config files. A simple net.conf may look as follows: 
  - net: 
  - net: 

This syntax means that if a client queries for the A record of the domain from an address in the range, Knot will respond with the and similarly with the second option. If a client sends a query from a different address, they will receive the default A record from the zone.

The geographical config in geo.conf might look like this: 
  - geo: "CZ;Prague" 
    TXT: "Prague" 
  - geo: "CZ;Brno" 
    TXT: "Brno"
  - geo: "CZ;*"
    TXT: "Czechia" 

In this example, we specify different A and TXT records to be returned if the client queries from Prague or from Brno. If a client queries from the Czech Republic but outside of the two cities, the third option applies. The * stands for ‘any city’. Finally, if a client queries from somewhere else, the default record from the zone is returned.

Let’s have a test run

Finally we are ready to run the server! Open up a terminal and type:

$ knotd -c /etc/knot/knot.conf


$ systemctl start knot.service

according to you preferences.

You can try querying the server using the kdig utility using the +subnet option to specify different source addresses and check if you are getting the expected responses. The following query invokes the net module instance:

$ kdig @ A +subnet=

;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 56869
;; Flags: qr aa rd; QUERY: 1; ANSWER: 1; AUTHORITY: 0; ADDITIONAL: 1

;; Version: 0; flags: ; UDP size: 4096 B; ext-rcode: NOERROR

;;         IN  A

;; ANSWER SECTION:        60  IN  A

;; Received 72 B
;; Time 2018-09-18 16:47:15 CEST
;; From in 0.1 ms

And the next query invokes the geo module instance:

$ kdig @ TXT +subnet=

;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 33440
;; Flags: qr aa rd; QUERY: 1; ANSWER: 1; AUTHORITY: 0; ADDITIONAL: 1

;; Version: 0; flags: ; UDP size: 4096 B; ext-rcode: NOERROR

;;         IN  TXT

;; ANSWER SECTION:        60  IN  TXT "Brno"

;; Received 110 B
;; Time 2018-09-18 16:49:47 CEST
;; From in 0.3 ms

As always, we’d love to know your thoughts.

Adapted from original post which appeared on CZ.NIC Blog.

Mark Karpilovskij is a junior research and development programmer at CZ.NIC Labs.

Rate this article

The views expressed by the authors of this blog are their own and do not necessarily reflect the views of APNIC. Please note a Code of Conduct applies to this blog.


  1. IObserver

    When I’m correct, geolocation support has been removed from BIND (older version may still support). The main issue with geolocation is that available databases are anything but accurate.

    1. Freddy Manullang

      Agree. I have experience buy IP from Indonesia NIR (APJII). When i open site, the site redirect to google taiwan. Mean, the google detect the ip as Taiwan IP even country in whois ip is Indonesia.

  2. lucas

    I don’t know what’s benefit if you implement geo module without load balancing in this example if Prague dns down people from Prague still answer from You need either implement something native or lua


Leave a Reply

Your email address will not be published. Required fields are marked *