Skip site navigation (1)Skip section navigation (2)

  
 
  

home | help
COREDNS-TEMPLATE(7)		 CoreDNS Plugins	     COREDNS-TEMPLATE(7)

NAME
     template - allows for dynamic responses based on the incoming query.

DESCRIPTION
     The  template  plugin  allows you to dynamically respond to queries by just
     writing a (Go) template.

SYNTAX
	    template CLASS TYPE [ZONE...] {
		match REGEX...
		answer RR
		additional RR
		authority RR
		rcode CODE
		ederror EXTENDED_ERROR_CODE [EXTRA_REASON]
		fallthrough [FALLTHROUGH-ZONE...]
	    }

     *	 CLASS the query class (usually IN or ANY).

     *	 TYPE the query type (A, PTR, ... can be ANY to match all types).

     *	 ZONE the zone scope(s) for this template. Defaults to the server zones.

     *	 match REGEX Go regexp <https://golang.org/pkg/regexp/> that are matched
	 against the incoming question name.  Specifying no regex matches every-
	 thing (default: .*). First matching regex wins. Regex patterns must not
	 exceed 10000 characters.

     *	 answer|additional|authority	    RR	      A 	RFC	    1035
	 <https://tools.ietf.org/html/rfc1035#section-5>  style  resource record
	 fragment built by a Go template <https://golang.org/pkg/text/template/>
	 that contains the reply. Specifying no answer will result in a response
	 with an empty answer section.

     *	 rcode CODE A response code (NXDOMAIN, SERVFAIL, ...).	The  default  is
	 NOERROR.  Valid  response code values are per the RcodeToString map de-
	 fined by the miekg/dns package in msg.go.

     *	 ederror EXTENDEDERRORCODE is an extended DNS error code as a number de-
	 fined in RFC8914 (0, 1, 2,..., 24).
		   EXTRA_REASON is an additional string  explaining  the  reason
	 for returning the error.

     *	 fallthrough  Continue with the next template instance if the template's
	 ZONE matches a query name but no regex match.	If there is no next tem-
	 plate, continue resolution  with  the	next  plugin.  If  [FALLTHROUGH-
	 ZONE...]  are listed (for example in-addr.arpa and ip6.arpa), then only
	 queries for  those  zones  will  be  subject  to  fallthrough.  Without
	 fallthrough,  when  the  template's  ZONE  matches a query but no regex
	 match then a SERVFAIL response is returned.

     Also see <#also-see> contains an additional reading list.

TEMPLATES
     Each    resource	 record    is	 a     full-featured	 Go	template
     <https://golang.org/pkg/text/template/> with the following predefined data

     *	 .Zone the matched zone string (e.g. example.).

     *	 .Name the query name, as a string (lowercased).

     *	 .Class the query class (usually IN).

     *	 .Type the RR type requested (e.g. PTR).

     *	 .Match  an  array  of	all  matches. index .Match 0 refers to the whole
	 match.

     *	 .Group a map of the named capture groups.

     *	 .Message the complete incoming DNS message.

     *	 .Question the matched question section.

     *	 .Remote clientas IP address

     *	 .Meta a function that takes a metadata name and returns the  value,  if
	 the  metadata plugin is enabled. For example, .Meta "kubernetes/client-
	 namespace"

     and      the      following       predefined	template       functions
     <https://golang.org/pkg/text/template#hdr-Functions>

     *	 parseInt interprets a string in the given base and bit size. Equivalent
	 to strconv.ParseUint <https://golang.org/pkg/strconv#ParseUint>.

     The     output	of     the    template	  must	  be	a    RFC    1035
     <https://tools.ietf.org/html/rfc1035> style resource record  (commonly  re-
     ferred to as a "zone file").

     WARNING there is a syntactical problem with Go templates and CoreDNS config
     files. Expressions
      like  {{$var}}  will be interpreted as a reference to an environment vari-
     able by CoreDNS (and
      Caddy) while {{ $var }} will work. See Bugs <#bugs> and corefile(5).

METRICS
     If monitoring is enabled (via the prometheus  plugin)  then  the  following
     metrics are exported:

     *	 coredns_template_matches_total{server, zone, view, class, type} the to-
	 tal number of matched requests by regex.

     *	 coredns_template_template_failures_total{server,   zone,  view,  class,
	 type, section, template} the number of times the Go templating  failed.
	 Regex,  section  and template label values can be used to map the error
	 back to the config file.

     *	 coredns_template_rr_failures_total{server,  zone,  view,  class,  type,
	 section,  template}  the  number of times the templated resource record
	 was invalid and could not be parsed. Regex, section and template  label
	 values can be used to map the error back to the config file.

     Both  failure cases indicate a problem with the template configuration. The
     server label indicates the server incrementing the metric, see the  metrics
     plugin for details.

EXAMPLES
   RESOLVE EVERYTHING TO NXDOMAIN
     The most simplistic template is

	    . {
		template ANY ANY {
		  rcode NXDOMAIN
		}
	    }

     1.  This template uses the default zone (. or all queries)

     2.  All queries will be answered (no fallthrough)

     3.  The answer is always NXDOMAIN

   RESOLVE .INVALID AS NXDOMAIN
     The  .invalid domain is a reserved TLD (see RFC 2606 Reserved Top Level DNS
     Names <https://tools.ietf.org/html/rfc2606#section-2>) to indicate  invalid
     domains.

	    . {
		forward . 8.8.8.8

		template ANY ANY invalid {
		  rcode NXDOMAIN
		  authority "invalid. 60 {{ .Class }} SOA ns.invalid. hostmaster.invalid. (1 60 60 60 60)"
		  ederror 21 "Blocked according to RFC2606"
		}
	    }

     1.  A query to .invalid will result in NXDOMAIN (rcode)

     2.  A  dummy  SOA	record is sent to hand out a TTL of 60s for caching pur-
	 poses

     3.  Querying .invalid in the CH class will also cause  a  NXDOMAIN/SOA  re-
	 sponse

     4.  The default regex is .*

   BLOCK INVALID SEARCH DOMAIN COMPLETIONS
     Imagine you run example.com with a datacenter dc1.example.com. The datacen-
     ter  domain  is  part  of	the  DNS search domain.  However something.exam-
     ple.com.dc1.example.com would indicate a fully qualified domain name (some-
     thing.example.com) that inadvertently has the default domain or search path
     (dc1.example.com) added.

	    . {
		forward . 8.8.8.8

		template IN ANY example.com.dc1.example.com {
		  rcode NXDOMAIN
		  authority "{{ .Zone }} 60 IN SOA ns.example.com hostmaster.example.com (1 60 60 60 60)"
		}
	    }

     A more verbose regex based equivalent would be

	    . {
		forward . 8.8.8.8

		template IN ANY example.com {
		  match "example\.com\.(dc1\.example\.com\.)$"
		  rcode NXDOMAIN
		  authority "{{ index .Match 1 }} 60 IN SOA ns.{{ index .Match 1 }} hostmaster.{{ index .Match 1 }} (1 60 60 60 60)"
		  fallthrough
		}
	    }

     The regex-based version can do more complex matching/templating while zone-
     based templating is easier to read and use.

   RESOLVE A/PTR FOR .EXAMPLE
	    . {
		forward . 8.8.8.8

		# ip-a-b-c-d.example A a.b.c.d

		template IN A example {
		  match (^|[.])ip-(?P<a>[0-9]*)-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
		  answer "{{ .Name }} 60 IN A {{ .Group.a }}.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
		  fallthrough
		}

		# d.c.b.a.in-addr.arpa PTR ip-a-b-c-d.example

		template IN PTR in-addr.arpa {
		  match ^(?P<d>[0-9]*)[.](?P<c>[0-9]*)[.](?P<b>[0-9]*)[.](?P<a>[0-9]*)[.]in-addr[.]arpa[.]$
		  answer "{{ .Name }} 60 IN PTR ip-{{ .Group.a }}-{{ .Group.b }}-{{ .Group.c }}-{{ .Group.d }}.example."
		}
	    }

     An IPv4 address consists of 4 bytes, a.b.c.d. Named groups make it less er-
     ror-prone to reverse the IP address in the  PTR  case.  Try  to  use  named
     groups to explain what your regex and template are doing.

     Note  that the A record is actually a wildcard: any subdomain of the IP ad-
     dress will resolve to the IP address.

     Having templates to map certain PTR/A pairs is a common pattern.

     Fallthrough is needed for mixed domains where only some responses are  tem-
     plated.

   RESOLVE HEXADECIMAL IP PATTERN USING PARSEINT
	    . {
		forward . 8.8.8.8

		template IN A example {
		  match "^ip0a(?P<b>[a-f0-9]{2})(?P<c>[a-f0-9]{2})(?P<d>[a-f0-9]{2})[.]example[.]$"
		  answer "{{ .Name }} 60 IN A 10.{{ parseInt .Group.b 16 8 }}.{{ parseInt .Group.c 16 8 }}.{{ parseInt .Group.d 16 8 }}"
		  fallthrough
		}
	    }

     An IPv4 address can be expressed in a more compact form using its hexadeci-
     mal  encoding.  For example ip-10-123-123.example. can instead be expressed
     as ip0a7b7b7b.example.

   RESOLVE MULTIPLE IP PATTERNS
	    . {
		forward . 8.8.8.8

		template IN A example {
		  match "^ip-(?P<a>10)-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]dc[.]example[.]$"
		  match "^(?P<a>[0-9]*)[.](?P<b>[0-9]*)[.](?P<c>[0-9]*)[.](?P<d>[0-9]*)[.]ext[.]example[.]$"
		  answer "{{ .Name }} 60 IN A {{ .Group.a}}.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
		  fallthrough
		}
	    }

     Named capture groups can be used to template one response for multiple pat-
     terns.

   RESOLVE A AND MX RECORDS FOR IP TEMPLATES IN .EXAMPLE
	    . {
		forward . 8.8.8.8

		template IN A example {
		  match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
		  answer "{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
		  fallthrough
		}
		template IN MX example {
		  match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
		  answer "{{ .Name }} 60 IN MX 10 {{ .Name }}"
		  additional "{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
		  fallthrough
		}
	    }

   ADDING AUTHORITATIVE NAMESERVERS TO THE RESPONSE
	    . {
		forward . 8.8.8.8

		template IN A example {
		  match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
		  answer "{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
		  authority  "example. 60 IN NS ns0.example."
		  authority  "example. 60 IN NS ns1.example."
		  additional "ns0.example. 60 IN A 203.0.113.8"
		  additional "ns1.example. 60 IN A 198.51.100.8"
		  fallthrough
		}
		template IN MX example {
		  match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
		  answer "{{ .Name }} 60 IN MX 10 {{ .Name }}"
		  additional "{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
		  authority  "example. 60 IN NS ns0.example."
		  authority  "example. 60 IN NS ns1.example."
		  additional "ns0.example. 60 IN A 203.0.113.8"
		  additional "ns1.example. 60 IN A 198.51.100.8"
		  fallthrough
		}
	    }

   FABRICATE A CNAME
     This example responds with a CNAME to google.com for any DNS query made ex-
     actly for foogle.com.  The answer will also contain a record for google.com
     if the upstream nameserver can return a record  for  it  of  the  requested
     type.

	    . {
	      template IN ANY foogle.com {
		match "^foogle\.com\.$"
		answer "foogle.com 60 IN CNAME google.com"
	      }
	      forward . 8.8.8.8
	    }

ALSO SEE
     *	 Go  regexp <https://golang.org/pkg/regexp/> for details about the regex
	 implementation

     *	 RE2 syntax  reference	<https://github.com/google/re2/wiki/Syntax>  for
	 details about the regex syntax

     *	 RFC  1034  <https://tools.ietf.org/html/rfc1034#section-3.6.1>  and RFC
	 1035 <https://tools.ietf.org/html/rfc1035#section-5> for  the	resource
	 record format

     *	 Go  template  <https://golang.org/pkg/text/template/>	for the template
	 language reference

BUGS
     CoreDNS   supports   caddyfile    environment    variables    <https://cad-
     dyserver.com/docs/caddyfile#env>  with  notion  of  {$ENV_VAR}. This parser
     feature will break Go template variables  <https://golang.org/pkg/text/tem-
     plate/#hdr-Variables> notations like{{$variable}}.  The equivalent notation
     {{  $variable }} will work.  Try to avoid Go template variables in the con-
     text of this plugin.

CoreDNS 			   March 2026		     COREDNS-TEMPLATE(7)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=coredns-template&sektion=7&manpath=FreeBSD+Ports+15.1.quarterly>

home | help