# How to self-host authoritative DNS on Quake AI

Source: https://docs.quake.ai/docs/network/how-to/self-host-dns
Markdown: https://docs.quake.ai/docs/network/how-to/self-host-dns.md

---

# How to self-host authoritative DNS on Quake AI

Run an authoritative DNS server you operate on a Quake AI instance. Quake AI does not host managed DNS for your domains. You launch a VM, install PowerDNS, publish zones, and delegate the domain from your registrar to the nameserver hostnames you control.



PowerDNS on a single VM is regional infrastructure you patch, back up, and monitor. Quake AI provides the compute, floating IP, and network path. High availability, anycast, and DDoS scrubbing at the DNS layer come from your architecture or from a third-party DNS provider, not from this platform. Most teams keep registrar DNS and only self-host when they need a private zone, dynamic updates, or full control of the REST API.





[How to point a domain at a Quake AI resource](/docs/network/how-to/point-domain-to-quake-ai) covers the common path: you keep DNS at your registrar and publish `A` or `CNAME` records toward a Quake AI floating IP. This page covers the alternate path: your Quake AI VM answers authoritative queries, and the registrar delegates the zone to your nameserver hostnames.



<PrerequisiteBlock methods={["console", "cli"]}>

- An [SSH key pair](/docs/tools/add-ssh-key) uploaded to your account
- A domain you control at a registrar where you can edit nameserver delegation and glue records
- A private network with a router attached to `PublicStatic` ([create a VM on a private network](/docs/compute/how-to/create-vm-private-network) builds `my-private-net` if you need one)

</PrerequisiteBlock>

## Choose authoritative software

| Software | Best for | Notes |
|---|---|---|
| [PowerDNS Authoritative](https://doc.powerdns.com/authoritative/) | General authoritative DNS with a REST API and optional SQL backends | Lead path in this guide |
| [CoreDNS](https://coredns.io/) | In-cluster service discovery on Kubernetes | Run inside a [Magnum cluster](/docs/kubernetes) or as a sidecar; use PowerDNS when the zone must be authoritative on the public internet |

This guide installs PowerDNS with the BIND zone-file backend on Ubuntu 22.04. The REST API listens on localhost; you reach it through SSH port forwarding.

## Create a security group for DNS

Allow DNS from the internet and SSH from your administrator address. Restrict the API to localhost on the instance; do not expose TCP `8081` on the floating IP.

Replace `YOUR_ADMIN_CIDR` with your workstation's public address, for example `203.0.113.10/32`.

<MethodTabs>
<Method label="Console">

1. Open **Network** > **Security Groups** > **Create Security Group**.
2. Name the group `dns-sg` and select **OK**.
3. On the `dns-sg` row, open **Settings** > **Create Rule**.
4. Add **SSH** (TCP `22`) with **Source** set to **CIDR** and **CIDR** set to `YOUR_ADMIN_CIDR`. Select **OK**.
5. Open **Create Rule** again. Add a **Custom TCP Rule** with **Destination Port** `53`, **Source** **CIDR** `0.0.0.0/0`. Select **OK**.
6. Open **Create Rule** again. Add a **Custom UDP Rule** with **Destination Port** `53`, **Source** **CIDR** `0.0.0.0/0`. Select **OK**.

</Method>
<Method label="CLI">

```bash
openstack security group create dns-sg
openstack security group rule create \
  --protocol tcp --dst-port 22 --remote-ip YOUR_ADMIN_CIDR dns-sg
openstack security group rule create \
  --protocol tcp --dst-port 53 --remote-ip 0.0.0.0/0 dns-sg
openstack security group rule create \
  --protocol udp --dst-port 53 --remote-ip 0.0.0.0/0 dns-sg
```

Verify:

```bash
openstack security group rule list dns-sg
```

The list shows one SSH rule scoped to your CIDR and inbound TCP/UDP `53` from `0.0.0.0/0`.

</Method>
</MethodTabs>

## Launch the DNS instance and assign a floating IP

<MethodTabs>
<Method label="Console">

1. Open **Compute** > **Instances** > **Create Instance**.
2. On **Base Config**, name the instance `dns-01`, select your region, and choose a small flavor such as `s1a.small`.
3. Select **Ubuntu-22.04** as the image.
4. On **Network Config**, choose your private network (for example `my-private-net`) with **Automatically Assigned Address**.
5. Attach `default` and `dns-sg`. Clear groups that allow broad inbound SSH.
6. On **System Config**, select your SSH key pair.
7. Create the instance.
8. On the **Instances** list, open **Networking** > **Associate Floating IP** for `dns-01`.
9. Allocate a floating IP from `PublicStatic` and associate it with the instance private port.

</Method>
<Method label="CLI">

```bash
openstack server create \
  --image Ubuntu-22.04 \
  --flavor s1a.small \
  --boot-from-volume 10 \
  --network my-private-net \
  --security-group dns-sg \
  --key-name MY_KEYPAIR \
  dns-01

openstack floating ip create PublicStatic
openstack server add floating ip dns-01 FLOATING_IP_ADDRESS
```

The `--boot-from-volume 10` option creates the required 10 GiB root volume for the zero-disk flavor.

Record the floating IP:

```bash
openstack server show dns-01 -f value -c addresses
```

</Method>
</MethodTabs>

SSH to the instance using the floating IP:

```bash
ssh -i ~/.ssh/MY_KEYPAIR ubuntu@FLOATING_IP_ADDRESS
```

## Install PowerDNS

On the instance:

```bash
sudo apt update
sudo apt install -y pdns-server pdns-backend-bind
```

Generate an API key:

```bash
API_KEY=$(openssl rand -hex 16)
echo "API_KEY=$API_KEY"
```

Edit `/etc/powerdns/pdns.conf` and set:

```ini
launch=bind
local-address=0.0.0.0,::
bind-config=/etc/powerdns/named.conf
api=yes
api-key=API_KEY
webserver=yes
webserver-address=127.0.0.1
webserver-port=8081
webserver-allow-from=127.0.0.1
```

Create `/etc/powerdns/named.conf`:

```text
zone "example.com" {
  type master;
  file "/etc/powerdns/zones/example.com.zone";
};
```

Create the zone directory and file:

```bash
sudo mkdir -p /etc/powerdns/zones
sudo tee /etc/powerdns/zones/example.com.zone <<'EOF'
$ORIGIN example.com.
$TTL 300
@   IN  SOA ns1.example.com. hostmaster.example.com. (
        2026070801 ; serial
        3600       ; refresh
        600        ; retry
        86400      ; expire
        300 )      ; minimum
    IN  NS  ns1.example.com.
ns1 IN  A   203.0.113.50
www IN  A   203.0.113.50
EOF
```

Replace `example.com` and the `A` records with your domain and [floating IP](/docs/network/how-to/allocate-floating-ips). Bump the SOA serial when you edit the zone.

Validate and restart:

```bash
sudo pdnsutil check-zone example.com
sudo systemctl restart pdns
sudo systemctl enable pdns
```

Verify PowerDNS listens on port `53`:

```bash
sudo ss -lunp | grep ':53'
dig @127.0.0.1 www.example.com +short
```

The `dig` command should print the `A` record you defined.

## Test the REST API over SSH

From your workstation, forward local port `8081` to the instance:

```bash
ssh -i ~/.ssh/MY_KEYPAIR -L 8081:127.0.0.1:8081 ubuntu@FLOATING_IP_ADDRESS
```

In another terminal:

```bash
curl -s -H "X-API-Key: API_KEY" http://127.0.0.1:8081/api/v1/servers/localhost/zones
```

The response lists the `example.com` zone. Use the API for dynamic record changes; zone files remain the bootstrap path in this guide.

## Delegate the zone at your registrar

At your registrar, point the domain's authoritative nameservers at the hostnames PowerDNS publishes (for example `ns1.example.com`). Add **glue records** (nameserver hostname to IPv4 address) when the registrar requires them.

| Registrar task | Typical field | Value |
|---|---|---|
| Nameserver 1 | Hostname | `ns1.example.com` |
| Glue / child nameserver | IPv4 | Your Quake AI floating IP |
| Optional nameserver 2 | Hostname | A second instance if you run HA later |

Provider UIs differ. Use their nameserver or custom DNS documentation:

| Provider | Delegation documentation |
|---|---|
| Cloudflare | [Change nameservers](https://developers.cloudflare.com/dns/zone-setups/full-setup/setup/) |
| Namecheap | [Custom DNS](https://www.namecheap.com/support/knowledgebase/article.aspx/767/10/how-to-change-dns-for-a-domain/) |
| GoDaddy | [Edit nameservers](https://www.godaddy.com/help/change-nameservers-for-my-domains-664) |
| Gandi | [External nameservers](https://docs.gandi.net/en/domain_names/operations/nameservers/index.html) |

Delegation can take up to 48 hours to propagate globally. TTL on the previous NS set controls how long resolvers cache the old delegation.

## Verify public resolution

Query from your workstation against a public resolver:

```bash
dig +trace www.example.com A
```

The trace should end at your floating IP for the `www` `A` record.

Query the authoritative server directly:

```bash
dig @FLOATING_IP_ADDRESS www.example.com A +short
```

Send HTTP to a host you published once records resolve:

```bash
curl -I http://www.example.com
```

If resolution fails, confirm the floating IP is associated, `dns-sg` allows UDP/TCP `53`, and the registrar glue records match the floating IP.

## CoreDNS for Kubernetes service discovery

When the goal is internal name resolution inside a cluster rather than public authoritative DNS, run [CoreDNS](https://coredns.io/) on Kubernetes. Magnum clusters ship CoreDNS as the in-cluster resolver. For a custom `Corefile` on Quake AI compute outside Magnum, install the binary on an instance and point `upstream` to your PowerDNS host or to a public resolver.

Example stub zone forwarding to your PowerDNS instance:

```text
example.com:53 {
    forward . FLOATING_IP_ADDRESS
}
log
```

Deploy CoreDNS with the DaemonSet or systemd unit pattern your orchestrator uses. Public delegation still flows through PowerDNS (or another authoritative server), not through cluster DNS.

## See also

- [How to point a domain at a Quake AI resource](/docs/network/how-to/point-domain-to-quake-ai): registrar `A`/`CNAME` records toward a Quake AI address
- [How to allocate floating IP addresses](/docs/network/how-to/allocate-floating-ips)
- [How to put a CDN in front of a Quake AI workload](/docs/network/how-to/front-with-cdn)
- [How to issue and auto-renew a TLS certificate with Let's Encrypt](/docs/network/how-to/lets-encrypt-certificate)
- [Self-hosted vibecode stack](/resources/solutions/self-hosted-vibecode-stack): perimeter comparison including managed DNS alternatives
