COREDNS-GEOIP(7)
πΈ COREDNS-GEOIP(7) πΈ
okay so before we even get into it β welcome to the geoip page of the CoreDNS Plugins manual, bestie. grab a snack, this one's a chonky read but it's honestly so good. π
β¨ NAME β¨
geoip β it looks up .mmdb databases (that's the MaxMind db file format, over at https://maxmind.github.io/MaxMind-DB/) using the client IP, and then it adds all that associated geoip data into the context request. slay. πΊοΈ
π DESCRIPTION π
So the geoip plugin is literally here to enrich the data tied to Client IP addresses β think geoip info like City, Country, and Network ASN. π GeoIP data usually comes in .mmdb format, which is a database format that maps IPv4 and IPv6 addresses to data records using a binary search tree. ikyk. π³
All that data gets added by leveraging the metadata plugin, and then you can retrieve the values by using it too. it's giving teamwork. π«Ά
Longitude example β here's the vibe:
import (
"strconv"
"github.com/coredns/coredns/plugin/metadata"
)
// ...
if getLongitude := metadata.ValueFunc(ctx, "geoip/longitude"); getLongitude != nil {
if longitude, err := strconv.ParseFloat(getLongitude(), 64); err == nil {
// Do something useful with longitude.
}
} else {
// The metadata label geoip/longitude for some reason, was not set.
}
// ...
City example β yes we're doing this one too ποΈ:
import (
"github.com/coredns/coredns/plugin/metadata"
)
// ...
if getCity := metadata.ValueFunc(ctx, "geoip/city/name"); getCity != nil {
city := getCity()
// Do something useful with city.
} else {
// The metadata label geoip/city/name for some reason, was not set.
}
// ...
ASN example β ok last one, and it's a two-parter π₯:
import (
"strconv"
"github.com/coredns/coredns/plugin/metadata"
)
// ...
if getASN := metadata.ValueFunc(ctx, "geoip/asn/number"); getASN != nil {
if asn, err := strconv.ParseUint(getASN(), 10, 32); err == nil {
// Do something useful with asn.
}
}
if getASNOrg := metadata.ValueFunc(ctx, "geoip/asn/org"); getASNOrg != nil {
asnOrg := getASNOrg()
// Do something useful with asnOrg.
}
// ...
π DATABASES π
The supported databases use city schema β like ASN, City, and Enterprise. basically .mmdb files are generally supported, as long as their field names correctly map to the Metadata Labels down below. π Other database types with different schemas? not supported yet, sorry bestie. π
Free and commercial GeoIP .mmdb files are commonly available from vendors like:
- MaxMind β https://dev.maxmind.com/geoip/docs/databases
- IPinfo β https://ipinfo.io/developers/database-download
- IPtoASN β https://iptoasn.com/ β and this one's Public Domain-licensed, fr fr (https://opendatacommons.org/licenses/pddl/1-0/) π
β SYNTAX β
geoip [DBFILE]
orrrr
geoip [DBFILE] {
[edns-subnet]
}
DBFILEβ the mmdb database file path. highly recommend you update your mmdb database periodically for more accurate results. like, keep it fresh. π§edns-subnetβ Optional. Use EDNS0 subnet (https://en.wikipedia.org/wiki/EDNS_Client_Subnet) (if present) for Geo IP instead of the source IP of the DNS request. This helps identifying the closest source IP address through intermediary DNS resolvers, and it also makes GeoIP testing easy β look:dig +subnet=1.2.3.4 @dns-server.example.com www.geo-aware.com. πβ¨
NOTE: due to security reasons, recursive DNS resolvers may mask a few bits off of the clients' IP address, which can cause inaccuracies in GeoIP resolution. β οΈ
There's no defined mask size in the standards, but there are examples, so let's look at those: RFC 7871's example (https://www.rfc-editor.org/info/rfc7871/#section-13) conceals the last 72 bits of an IPv6 source address, and the NS1 Help Center mentions (https://help.ns1.com/hc/en-us/articles/360020256573-About-the-EDNS-Client-Subnet-ECS-DNS-extension) that ECS-enabled DNS resolvers send only the first three octets (eg. /24) of the source IPv4 address. the way they just chop off bits π
π¦ EXAMPLES π¦
This config configures the City database, and looks up geolocation based on EDNS0 subnet if present. iconic behaviour honestly:
. {
geoip /opt/geoip2/db/GeoLite2-City.mmdb {
edns-subnet
}
metadata # Note that metadata plugin must be enabled as well.
}
The view plugin can use geoip metadata as selection criteria to give you GSLB functionality. β¨ In this example, clients from the city "Exampleshire" will receive answers for example.com from the zone defined in example.com.exampleshire-db. All other clients will receive answers from the zone defined in example.com.db. Note that the order of the two example.com server blocks below is important; the default viewless server block must be last. don't mess with the order, i'm serious. π
example.com {
view exampleshire {
expr metadata('geoip/city/name') == 'Exampleshire'
}
geoip /opt/geoip2/db/GeoLite2-City.mmdb
metadata
file example.com.exampleshire-db
}
example.com {
file example.com.db
}
π METADATA LABELS π
A limited set of fields will be exported as labels, and all values are stored using strings regardless of their underlying value type β so you may have to convert it back to its original type. π note that numeric values are always represented in base 10. no hex shenanigans here, bestie.
ok and that's literally only the beginning β the labels themselves are coming up next, so don't go anywhere π«Άβ¨
geoip/city/nameβ string β e.g.Cambridgeβ the city name in English π₯geoip/country/codeβ string β e.g.GBβ the country's ISO 3166-1 code, iykyk (https://en.wikipedia.org/wiki/ISO_3166-1)geoip/country/nameβ string β e.g.United Kingdomβ the country name, in English, no capgeoip/country/is_in_european_unionβ bool β e.g.falseβ literally just eithertrueorfalseπgeoip/continent/codeβ string β e.g.EUβ check the Continent codes#continent-codessection for the full loregeoip/continent/nameβ string β e.g.Europeβ the continent name in English πgeoip/latitudeβ float64 β e.g.52.2242β base 10, max available precision, she's precise β¨geoip/longitudeβ float64 β e.g.0.1315β base 10, max available precision, same energy πgeoip/timezoneβ string β e.g.Europe/Londonβ the timezone, bestie π°οΈgeoip/postalcodeβ string β e.g.CB4β the postal code πgeoip/subdivisions/codeβ string β e.g.ENG,TWHβ comma separated ISO 3166-2- (this one's the tail end of the subdivision label above β no type, no default listed) β <https://en.wikipedia.org/wiki/ISO_3166-2> subdivision(region) codes, e.g. first level (province), second level (state). πΊοΈ
geoip/asn/numberβ typeuint, default396982β¨ β literally the autonomous system number.geoip/asn/orgβ typestring, defaultGOOGLE-CLOUD-PLATFORMπ β the autonomous system organization. ok that default is such a flex ngl.
π CONTINENT CODES π
bestie these are the continent values, memorise them or keep this open, either works π«Ά
AFβ AfricaANβ AntarcticaASβ AsiaEUβ EuropeNAβ North AmericaOCβ OceaniaSAβ South America
π NOTABLE CHANGES π
- In CoreDNS v1.13.2, the
geoipplugin was upgraded to useoschwald/geoip2-golang/v2(https://github.com/oschwald/geoip2-golang/blob/main/MIGRATION.md), the Go library that reads and parses.mmdb(https://maxmind.github.io/MaxMind-DB/) databases. It has a small, but possibly-breaking change, where theLocation.LatitudeandLocation.Longitudestructs changed from value types to pointers (float64β*float64). Inoschwald/geoip2-golangv1, missing coordinates returned"0"(which is a valid location βhttps://en.wikipedia.org/wiki/Null_Island), and in v2 they now return an empty string"".
π¨ real talk: if your code was checking for0to mean "no coords", that check is lowkey cooked now. it's""in v2, and0was never actually "missing" anyway because Null Island is a whole real place. so yeah β possibly-breaking, read the migration guide, do not come for me. π«
and that's the whole page, bestie!! π you officially know more about geoip than like 99% of people. the vibe check passed, the docs ate, periodt. π
β¨
this little icon was brought to you by CoreDNS, October 2026 edition, filed under COREDNS-GEOIP(7) in the manual shelf β go read it again, iykyk π¦π
π¦ where this page comes from
- opensuse-leap 16.0: coredns-extras 1.15.0-bp160.1.1 Β· Apache-2.0 AND MPL-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms