Here you can find a bunch of configurations for CoreDNS. All setups are done assuming you are not the
root user and hence can’t start listening on port 53. We will use port 1053 instead, using the
-dns.port flag. In every setup, the configuration file used is the CoreDNS’ default, named
This means we don’t need to specify the configuration file with the
-conf flag. In other words,
we start CoreDNS with
./coredns -dns.port=1053 -conf Corefile, which can be abbreviated to
All DNS queries will be generated with the
tool, the gold standard for debugging DNS. The full command line we use here is:
But we shorten it in the setups below, so
dig www.example.org A is really
dig -p 1053 @localhost +noall +answer www.example.org A
The file we create here is a DNS zone file, and it can have any name (file plugin doesn’t care). The
data we are putting in the file is for the zone
In your current directory, create a file named
db.example.org and put the following contents in
The last two lines are defining a name
www.example.org. with two addresses, 127.0.0.1 and (the
Next, create this minimal
Corefile that handles queries for this domain and adds the
log plugin to enable query logging:
Start CoreDNS and query it with
It works. Because of the log plugin, we should also see the query being logged:
The above logs show us the address CoreDNS replied from (
::1) and the time and date it replied.
Furthermore, it logs the query type, the query class, the query name, the protocol used (
size in bytes of the incoming request, the DO bit state, and the advertised UDP buffer size. This is
data from the incoming query.
NOERROR signals the start of the reply, which is the Response Code
sent back, followed by the set of flags on the reply:
qr,aa,rd,ra, the size of the reply in bytes
(121), and the duration it took to get the reply.
CoreDNS can be configured to forward traffic to a recursor with the forward. Here, we will use forward and focus on the most basic setup: forwarding to Google Public DNS (220.127.116.11) and Quad9 DNS (18.104.22.168).
We don’t need to create anything except for a Corefile with the configuration we want. In this case, we want all queries hitting CoreDNS to be forward to either 22.214.171.124 or 126.96.36.199:
Note that forward allows you to fine tune the names it will send upstream. Here, we
chose all names (
.). For instance:
forward example.com 188.8.131.52 184.108.40.206 would only forward names
Start CoreDNS and test it with
A common scenario you may encounter is that queries for
example.org need to go to 220.127.116.11 and
the rest should be resolved via the name servers in
/etc/resolv.conf. There are two ways that
could be implemented in a Corefile; one way that may work (depending on the plugin’s implementation) and
a way that is guaranteed to work.
Take this Corefile as an example:
The intent is to grab all possible queries (this Server Block is authoritative for the root domain), and then use the per-zone filtering of the forward plugin. Spoiler alert: this does not work. The reason is that the forward plugin can only be used once in a Server Block.
The above use case is a very valid one, so how do you implement this in CoreDNS? The quick answer is by using multiple Server Blocks, one for each of the domains you want to route on. Doing so results in this Corefile:
This leaves the domain routing to CoreDNS, which also handles special cases like DS queries. Having two smaller Server Blocks instead of one has no negative effects except that your Corefile will be slightly longer. Things like snippets and the import will help there.
CoreDNS does not have a native (i.e. written in Go) recursive resolver, but there is an (external) plugin that utilizes libunbound. For this setup to work, you first have to recompile CoreDNS and enable the unbound plugin. Super quick primer here (you must have the CoreDNS source installed):
- Do a
go generate, followed by
Note: the unbound plugin needs cgo to be compiled, which also means the coredns binary is now linked against libunbound and not a static binary anymore.
Assuming this worked, you can then enable unbound with the following Corefile:
cache has been included, because the (internal) cache from unbound is disabled to allow the cache’s metrics to works just like normal.