CoreDNS - the forked Caddy that is a DNS server

Hi all,

CoreDNS is a fork of Caddy (0.8) that is a DNS server that chains middleware. Currently I’m working on a) making CoreDNS have a good set of middleware: etcd backend, k8s backend, file backend, on-the-fly DNSSEC signing, monitoring to name a few.

Futher more: I’m porting CoreDNS to be a plugin for Caddy 0.9; this is a work in progress and probably needs changes in Caddy as well.

Feel free to ask to questions :slight_smile: or mail me at


Holy cow, I was gonna ask about something like this. It looks pretty cool. A few questions:

  • I am currently loading a bunch of zone files into a directory for bind. Can it operate in this kind of mode, or do I need to convert my zones to a specific format? Can it do wildcard “host every zone in this directory” mode?

  • Can it limit the ips for which it will do recursive lookups?

  • Do you have an example of using it for local network machine name lookups?

  • Is the middleware format pretty well nailed down at this point? I can think of some cool ideas just off the top of my head:

    • statistics on number of queries per zone, etc.
    • logging domains queried with counts
    • Black hole ads (a la

I was about to give up on running bind for my home network and personal domains, but maybe this will make a local dns server a much more viable option. Pretty awesome looking project.

As an aside, one of the main things @mholt talks about with the 0.9.0 release is how alternate server types can be implemented as a plugin.

Would it ever make sense to run dns and http in the same caddy instance? Would that make the caddyfile kinda odd? How would you specify if a server block is http or dns? Would the syntax be the same for all? Kinda confused on how you would envision that working, or if this forking model is really best. Any thoughts?

Right now, an instance of the caddy binary (as officially distributed) will run only one server type:

$ caddy -type dns

But it’s easy to use multiple server types per process with a custom main(), something like this:

httpCaddyfile, err := caddy.LoadCaddyfile("http")
if err != nil {
httpInst, err := caddy.Start(httpCaddyfile)
if err != nil {
dnsCaddyfile, err := caddy.LoadCaddyfile("dns")
if err != nil {
dnsInst, err := caddy.Start(dnsCaddyfile)
if err != nil {


You’d probably have to plug in your own Caddyfile loader to handle multiple types. But that’s just a function.

So basically, each Caddyfile is for a server type; each instance is created from a Caddyfile and serves only that server type.

It is interesting, because just looking through the coredns middlewares, there are some interesting overlaps. Health checks and metrics among others, launch http servers for various utilities. It may make sense to somehow combine the functionality in a single caddyfile.

Some directives can cross server type boundaries; for example: startup, shutdown, and tls. But for code that is HTTP-middleware-specific, that’s harder to just share with a DNS middleware, I’d imagine. Maybe Miek has some ideas on that, but I don’t think combining server types into a single Caddyfile is a good idea. :confused:

One example would be something like It is a dns proxy server that has a blacklist of ad domains. For those domains it resolves to its own built in web server and serves a dummy page/image to satisfy the url. I could launch an http server and a dns server seperately, but it seems like the easy path is for the dns directive to launch its own http server, which does kinda feel dirty.

See <> for more docs on this as well. And the specific middleware READMEs in the source.

Yes, this mode is supported by the file middleware. You can’t use a “host every one in this directory”, that would be a nice feature though - how would the Corefile (my Caddyfile look like)? filed.

No, there is no middleware for that, filed:

? With what middleware? Just file:
Otherwise the etcd middleware works - and you should be able to replace SkyDNS with it.

Yes middleware/metrics

Yep, normal logging. No counts though - every query gets logged (might change in the future).

No does not exist, filed.

Thanks, I’m using it for the last couple of months on personal zones. Works good enough for that already.

CoreDNS Corefile semantics are very different from how Caddy handles its Caddyfile.

Serving the add itself… with https as well? Why can’t you just make the ad fail to load by returning or ::1 for that lookup?

No I don’t see how that would work…