# Set DNS with Hetzner

Connect a Hetzner Cloud API token once. MainPath writes A and CNAME records into your DNS zones.

> Source: https://www.mainpath.ai/en/docs/dns-hetzner/

If your domain's DNS zone lives in the [Hetzner Console](https://console.hetzner.com/), you no longer have to copy records by hand. You store an API token under **Connections**; once a project has domains, MainPath writes the records into the matching zone.

Manual DNS is still possible. See [Configure a DNS record]({{< relref "domain-how-to" >}}).

## API token in the Hetzner Console

This uses the **Hetzner Cloud DNS API** (`api.hetzner.cloud/v1/zones`), not the retired DNS Console at `dns.hetzner.com`. Tokens from the old DNS Console will not work.

1. In the [Hetzner Console](https://console.hetzner.com/), open the project that holds the DNS zones.
2. Under **Security → API tokens**, create a token with **Read & Write**.
3. Copy the token. It is shown only once.

A token always belongs to **one** Console project. The cleanest setup is a dedicated project that only contains DNS zones, so the token cannot manage servers.

The existing Hetzner Cloud connection under **Servers** is **not** reused automatically for DNS. DNS gets its own tile under **Connections**, even if you paste the same token text there.

The domain must use Hetzner nameservers, for example `hydrogen.ns.hetzner.com`, `oxygen.ns.hetzner.com`, and `helium.ns.hetzner.de`.

## Connection in MainPath

1. Open **Connections** and **Add connection**.
2. Under **DNS**, choose the **Hetzner DNS** tile.
3. Paste the API token and save. MainPath checks whether the token is valid and which zones it can see.

Several Hetzner DNS connections in one organization are allowed, for example one per Console project. If a hostname matches more than one zone, MainPath uses the most specific one.

## What is written

MainPath uses the same hosts you see under **Domains**.

- Records are only written when a real server address already exists.
- Existing records of the same name and type are updated; the whole zone is never replaced.
- Changes usually show up quickly.

```mermaid
flowchart LR
  org["Hetzner DNS connection"]
  domains["Domains in MainPath"]
  zone["Hetzner zone"]
  server["Your server"]
  org --> zone
  domains -->|"A / CNAME"| zone
  zone --> server
```

After you save a project, MainPath tries to align missing or mismatched records. You can see the check status in the domain overview.

## SSL via DNS-01 (optional)

If Let's Encrypt cannot reach the server (no public HTTP/443, firewall, internal IP), open this connection's details and tick the affected domains. MainPath then writes the `_acme-challenge` TXT record into this zone. Unticked domains keep the existing TLS-ALPN challenge on the server.

## Troubleshooting

- **Invalid token**: Create a **Read & Write** token in the Hetzner Console for the project that holds the DNS zones. A token from the old DNS Console or a read-only token is not enough.
- **No record at Hetzner**: The domain is not in a project this token can see. Check the project or zone name.
- **Zone visible, domain unreachable**: The zone exists in the Console, but the domain's nameservers point elsewhere. MainPath flags this in the connection details and on Domains. Point the nameservers at the registrar to Hetzner (`*.ns.hetzner.com` / `*.ns.hetzner.de`).
- **Status in MainPath still red**: DNS often takes a few minutes, or the server does not have a known address yet.

## See also

- [Domain setup]({{< relref "domain" >}})
- [Configure a DNS record]({{< relref "domain-how-to" >}})
- [Connections]({{< relref "connections" >}})
- [Hetzner]({{< relref "hetzner-tutorial" >}})

