Host OS integration of DNS for zones

I’ve successfully got AXFR zone info for a custom zone I’ve created, following the steps below to set it up:

  1. Created a project, setting features.network.zones=true
  2. Set the default profile for the project to use the incusbr0 network from the default project
  3. Created a new zone in the project called myproject.incus
  4. Set forward DNS resolution on the network as described in the docs dns.zone.forward=myproject.incus
  5. Set the DNS server address core.dns_address=<incusbr0 ipv4>:1053
  6. Set the zone peer address peers.whatever.address=<incusbr0 ipv4>

Now when I run dig @<incusbr0 ipv4> -p 1053 axfr myproject.incus I get a successful response, listing the A and AAAA records of all my containers. So far so good.

; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> @10.203.20.1 -p 1053 axfr myproject.incus
; (1 server found)
;; global options: +cmd
myproject.incus.          3600    IN      SOA     myproject.incus. hostmaster.myproject.incus. 1765479953 120 60 86400 30
internal.myproject.incus. 300     IN      AAAA    fd42:cea0:a3d8:7a57:216:3eff:fef7:57b7
public.myproject.incus.   300     IN      AAAA    fd42:cea0:a3d8:7a57:216:3eff:fe8c:b10a
public.myproject.incus.   300     IN      A       10.203.20.68
internal.myproject.incus. 300     IN      A       10.203.20.133
myproject.incus.          3600    IN      SOA     myproject.incus. hostmaster.myproject.incus. 1765479953 120 60 86400 30
;; Query time: 2 msec
;; SERVER: 10.203.20.1#1053(10.203.20.1) (TCP)
;; WHEN: Thu Dec 11 14:05:53 EST 2025
;; XFR size: 6 records (messages 1, bytes 375)

My question is about how this gets integrated into my host OS.

Before I set up the project and zone (just using the default project), I followed the instructions for integrating with resolved, which worked just fine. I could query the host system DNS using dig mycontainer.incus and get a response (an A record).

While setting up the zone, I noticed that the little “note” box here says that the built in DNS server only supports AXFR responses. This seemed odd, because resolved was working just fine returning A records from Incus before I went through this process of setting up a zone and a project.

Is it possible for me to hook up resolved to my Incus DNS server now that I have created a zone? resolved is no longer returning anything useful when I set it up like the documentation shows:

resolvectl dns incusbr0 <incusbr0_ipv4>:1053
resolvectl domain incusbr0 '~myproject.incus'
$ dig mycontainer.myproject.incus

; <<>> DiG 9.18.39-0ubuntu0.24.04.2-Ubuntu <<>> mycontainer.myproject.incus
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOTIMP, id: 46316
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;mycontainer.myproject.incus.                IN      A

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Thu Dec 11 14:15:59 EST 2025
;; MSG SIZE  rcvd: 51

Do I really need to run another DNS server between Incus and resolved to make this work in development?

After a bit of digging, I found this line in the source of internal/server/project/project.go that makes me believe that by creating a project, my instances will automatically be placed under a subdomain for the project without creating a separate zone. But no dice, I can query myinstance.incus successfully but not myinstance.myproject.incus.

// DNS adds ".<project>" as a suffix to instance name when the given project name is not "default".
func DNS(projectName string, instanceName string) string {
	if projectName != api.ProjectDefaultName {
		return fmt.Sprintf("%s.%s", instanceName, projectName)
	}

	return instanceName
}

Any ideas? If there’s a way to make this work, then I don’t have to muck around with the zones anyway. Just need my projects on their own subdomains.

Well from the code posted I rather would say that the entry will be myinstance.myproject and not myinstance.myproject.incus have you tried this?

Properly not exactly what you want but that’s what the code looks like.

Regarding the zone record creation, this requires a separate DNS as it purpose is a bit different from what the default internal dns is designed for. Mainly to allow publishing DNS records to automated public facing DNS entries as far as I understood it. But also works very well for internal usage if you have multiple cluster or other complex network settings.

Thanks for the help. Yes I tried myinstance.myproject with dig, no dice. I figured the code appended .incus or the default TLD somewhere down the line.