CoreDNS is a DNS server/forwarder, written in Go, that chains plugins. Each plugin performs a (DNS) function.
CoreDNS is a Cloud Native Computing Foundation graduated project.
CoreDNS is a fast and flexible DNS server. The key word here is flexible: with CoreDNS you are able to do what you want with your DNS data by utilizing plugins. If some functionality is not provided out of the box you can add it by writing a plugin.
CoreDNS can listen for DNS requests coming in over:
- UDP/TCP (go'old DNS).
- TLS - DoT (RFC 7858).
- DNS over HTTP/2 - DoH (RFC 8484).
- DNS over HTTP/3 - DoH3
- DNS over QUIC - DoQ (RFC 9250).
- gRPC (not a standard).
Currently CoreDNS is able to:
- Serve zone data from a file; both DNSSEC (NSEC only) and DNS are supported (file and auto).
- Retrieve zone data from primaries, i.e., act as a secondary server (AXFR only) (secondary).
- Sign zone data on-the-fly (dnssec).
- Load balancing of responses (loadbalance).
- Allow for zone transfers, i.e., act as a primary server (file + transfer).
- Automatically load zone files from disk (auto).
- Caching of DNS responses (cache).
- Use etcd as a backend (replacing SkyDNS) (etcd).
- Use k8s (kubernetes) as a backend (kubernetes).
- Serve as a proxy to forward queries to some other (recursive) nameserver (forward).
- Provide metrics (by using Prometheus) (prometheus).
- Provide query (log) and error (errors) logging.
- Integrate with cloud providers (route53).
- Support the CH class:
version.bindand friends (chaos). - Support the RFC 5001 DNS name server identifier (NSID) option (nsid).
- Profiling support (pprof).
- Rewrite queries (qtype, qclass and qname) (rewrite and template).
- Block ANY queries (any).
- Provide DNS64 IPv6 Translation (dns64).
And more. Each of the plugins is documented. See coredns.io/plugins for all in-tree plugins, and coredns.io/explugins for all out-of-tree plugins.
Compilation from Source
To compile CoreDNS, we assume you have a working Go setup. See various tutorials if you don’t have that already configured.
First, make sure your golang version is 1.26.0 or higher as go mod support and other api is needed.
See here for go mod details.
Then, check out the project and run make to compile the binary:
$ git clone https://github.com/coredns/coredns
$ cd coredns
$ make
NOTE: extra plugins may be enabled when building by setting the
COREDNS_PLUGINSenvironment variable with comma separate list of plugins in the same format as plugin.cfg
This should yield a coredns binary.
Compilation with Docker
CoreDNS requires Go to compile. However, if you already have docker installed and prefer not to setup a Go environment, you could build CoreDNS easily:
docker run --rm -i -t \
-v $PWD:/go/src/github.com/coredns/coredns -w /go/src/github.com/coredns/coredns \
golang:1.25 sh -c 'GOFLAGS="-buildvcs=false" make gen && GOFLAGS="-buildvcs=false" make'
The above command alone will have coredns binary generated.
Quick Start
Create a minimal Corefile:
cat > Corefile <<EOF
.:53 {
forward . 8.8.8.8
log
}
EOF
Run CoreDNS:
$ ./coredns -conf Corefile
Test it:
$ dig @127.0.0.1 google.com
Examples
JSON Logging
Start CoreDNS with -log-format=json to emit operational logs as single-line JSON.
The default -log-format=text retains the existing text output. The format applies
to the whole process, including all server blocks, and persists across Corefile
reloads. Query logging still requires the log plugin.
./coredns -conf Corefile -log-format=json
Records contain time (RFC3339 with fractional seconds), level (DEBUG, INFO,
WARN, ERROR, or FATAL), and msg. Named plugin loggers also include plugin.
Messages, including embedded newlines and DNS escapes, are JSON-encoded rather
than concatenated into JSON templates. Debug output still requires debug.
See the log plugin for typed query fields.
The standard library's default logger (including Caddy's lifecycle messages) is
routed through the same backend at INFO level; its original message is retained
without guessing severity or fields from text. Independently configured third-party
loggers, direct stdout/stderr writes, and Go runtime diagnostics are not intercepted.
Command-line help, flag parsing errors, -version, and -plugins remain human-readable.
Normal startup, Corefile errors, and query/error plugin logs use the selected format.
Querying CoreDNS
When starting CoreDNS without any configuration, it loads the
whoami and log plugins
and starts listening on port 53 (override with -dns.port), it should show the following:
.:53
CoreDNS-1.6.6
linux/amd64, go1.16.10, aa8c32
The following could be used to query the CoreDNS server that is running now:
dig @127.0.0.1 -p 53 www.example.com
Any query sent to port 53 should return some information; your sending address, port and protocol used. The query should also be logged to standard output.
The configuration of CoreDNS is done through a file named Corefile. When CoreDNS starts, it will
look for the Corefile from the current working directory. A Corefile for CoreDNS server that listens
on port 53 and enables whoami plugin is:
.:53 {
whoami
}
Sometimes port number 53 is occupied by system processes. In that case you can start the CoreDNS server
while modifying the Corefile as given below so that the CoreDNS server starts on port 1053.
.:1053 {
whoami
}
If you have a Corefile without a port number specified it will, by default, use port 53, but you can
override the port with the -dns.port flag: coredns -dns.port 1053, runs the server on port 1053.
You may import other text files into the Corefile using the import directive. You can use globs to match multiple
files with a single import directive.
.:53 {
import example1.txt
}
import example2.txt
You can use environment variables in the Corefile with {$VARIABLE}. Note that each environment variable is inserted
into the Corefile as a single token. For example, an environment variable with a space in it will be treated as a single
token, not as two separate tokens.
.:53 {
{$ENV_VAR}
}
A Corefile for a CoreDNS server that forward any queries to an upstream DNS (e.g., 8.8.8.8) is as follows:
.:53 {
forward . 8.8.8.8:53
log
}
Start CoreDNS and then query on that port (53). The query should be forwarded to 8.8.8.8 and the response will be returned. Each query should also show up in the log which is printed on standard output.
To serve the (NSEC) DNSSEC-signed example.org on port 1053, with errors and logging sent to standard
output. Allow zone transfers to everybody, but specifically mention 1 IP address so that CoreDNS can
send notifies to it.
example.org:1053 {
file /var/lib/coredns/example.org.signed
transfer {
to * 2001:500:8f::53
}
errors
log
}
Serve example.org on port 1053, but forward everything that does not match example.org to a
recursive nameserver and rewrite ANY queries to HINFO.
example.org:1053 {
file /var/lib/coredns/example.org.signed
transfer {
to * 2001:500:8f::53
}
errors
log
}
. {
any
forward . 8.8.8.8:53
errors
log
}
