# How to Set Up Cloudflare Enterprise DNS on AWS Route 53

> Activate a Cloudflare Enterprise domain whose DNS is in AWS Route 53: add the proof records, wait for Active, then cut the root over with two A records and www with a CNAME.

Use this guide when your domain's DNS is hosted in **AWS Route 53** and you are activating it on the xCloud Cloudflare Enterprise add-on. Route 53 cannot put a CNAME at the root, and its ALIAS records cannot point at an external hostname, so the root reaches Cloudflare through **two A records**. Add the proof records first, wait until the domain shows **Active**, and only then cut traffic over.

If your DNS is somewhere else, use the matching guide: [Google Cloud DNS](/docs/cloudflare-enterprise-dns-setup-google-cloud-dns/), [Namecheap](/docs/cloudflare-enterprise-dns-setup-namecheap/), or [Cloudflare without an xCloud integration](/docs/cloudflare-enterprise-dns-setup-cloudflare-without-integration/).

## Prerequisites

-   You have bought Cloudflare Enterprise for the domain. See [How to Activate the Cloudflare Enterprise Addon](/docs/how-to-activate-the-cloudflare-enterprise-addon/) or [How to Use Cloudflare Enterprise for External Domains](/docs/how-to-use-cloudflare-enterprise-for-external-domains/).
-   The domain's nameservers are Route 53. Check with `dig +short NS example.com`; the answer lists `awsdns` servers.
-   The website already loads from its current origin.
-   You can edit the domain's public hosted zone in Route 53.

## What you are creating

Open the domain's Cloudflare Enterprise page in xCloud. For a site, open the site's **Cloudflare Enterprise** page. For an external domain, go to **Addons → Cloudflare Enterprise Addons**, open the row's actions menu, and select **Manage**. The **Ownership Verification** panel lists every record. Copy the values from the panel: the token, certificate target, and edge addresses are specific to your domain and environment.

| Purpose | Record | Moves live traffic? |
| --- | --- | --- |
| Ownership proof | TXT at `_cf-custom-hostname` | No |
| Certificate proof | CNAME at `_acme-challenge`, ending in `.dcv.cloudflare.com` | No |
| Routing | Two A records at the root, CNAME at `www` | **Yes** |

The first two prove control and are safe to add at any time. The routing records move traffic. For Route 53, the panel shows the two root A records as required records and warns that they must wait until the domain is **Active**.

## Activate the domain

### 1. Add the two proof records

In the Route 53 console, open **Hosted zones**, select the domain's zone, and create:

| Record name | Type | Value | TTL |
| --- | --- | --- | --- |
| `_cf-custom-hostname` | TXT | The ownership token from the panel, in double quotes | 300 |
| `_acme-challenge` | CNAME | The certificate target from the panel | 300 |

Route 53 expects TXT values in double quotes, for example `"abc123-..."`.

The `_acme-challenge` CNAME delegates certificate validation to Cloudflare, so it keeps working through every renewal. If the panel offers two `_acme-challenge` TXT records instead, add those. Never add both forms, because they cannot share a name.

**Expected result:** The website keeps serving from its current host, and the proof rows in the panel change to **Verified** after propagation.

### 2. Verify and wait for Active

Select **Verify Records** in the **Ownership Verification** panel. If your team has a Cloudflare integration connected, the same button reads **Verify & Add Records**. To refresh the status, use **Refresh Status** in the page header for an external domain, or open the domain row's actions menu and select **Refresh status** for a site.

**Expected result:** The domain status changes to **Active**. Do not add the root A records before this point.

### 3. Lower the TTL on the records you will replace

If you can, lower the TTL on the current root and `www` records to 300 a day before the cutover. The cutover takes as long as the TTL of the record you replace.

### 4. Cut the root and www over

After the domain shows **Active**, update the routing records:

| Record name | Type | Value | TTL |
| --- | --- | --- | --- |
| *(blank, for the root)* | A | Both edge addresses from the panel, one per line | 300 |
| `www` | CNAME | The www target from the panel | 300 |

Put both A values in **one record set**. If an A record or ALIAS already exists at the root, edit it and replace its values rather than creating a second record set.

You will not add the root CNAME. Route 53 rejects a CNAME at the apex with `RRSet of type CNAME with DNS name example.com. is not permitted at apex`, and the A records replace it.

**Expected result:** The routing rows change to **Verified**, and the site serves through Cloudflare Enterprise.

### Optional: cut over with the AWS CLI

Save this as `change-batch.json` and replace the example values with the values from your panel:

```json
{
  "Comment": "Cloudflare Enterprise cutover",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "example.com.",
        "Type": "A",
        "TTL": 300,
        "ResourceRecords": [
          { "Value": "203.0.113.10" },
          { "Value": "203.0.113.11" }
        ]
      }
    },
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "www.example.com.",
        "Type": "CNAME",
        "TTL": 300,
        "ResourceRecords": [{ "Value": "edge.example.net" }]
      }
    }
  ]
}
```

```bash
aws route53 change-resource-record-sets \
  --hosted-zone-id Z0123456789ABCDEFGHIJ \
  --change-batch file://change-batch.json

aws route53 get-change --id /change/C0123456789ABCDEFGHIJ
```

`UPSERT` replaces the existing record set, which avoids the "invalid set of changes" error that `CREATE` returns when a record already exists. `get-change` reports `INSYNC` once Route 53 has applied the change.

## Verify it worked

Query in this order:

```bash
dig +short NS example.com                          # the zone you edited serves this domain
dig +short TXT _cf-custom-hostname.example.com     # ownership proof
dig +short CNAME _acme-challenge.example.com       # certificate proof
dig +short A example.com                           # the two edge addresses
dig +short CNAME www.example.com                   # the www target
curl -sSI https://example.com | grep -iE 'server|cf-ray'
```

`server: cloudflare` with a `cf-ray` header means the edge is serving the site. Also check `https://www.example.com` and the site's critical paths.

If a record you just created still reads as missing, query a public resolver with `dig @1.1.1.1 +short TXT _cf-custom-hostname.example.com`. A resolver that asked before the record existed can cache the empty answer for the zone's SOA minimum, often 15 to 30 minutes.

## Troubleshooting

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| `RRSet of type CNAME ... is not permitted at apex` | Route 53 cannot hold a CNAME at the root. | Use the two A records instead. |
| `The request contains an invalid set of changes` | A record already exists at that name. | Edit the existing record set and replace its values, or use `UPSERT`. |
| Records never verify, but they look correct | You edited a hosted zone that is not delegated. Route 53 can hold several zones for one domain. | Compare `dig +short NS example.com` with the zone's **Hosted zone details** and edit the matching zone. |
| The panel says Cloudflare cannot verify the root while it points at Cloudflare | The root A records were added before the domain was active. | Point the root back at your origin, select **Verify Records**, and add the A records again after **Active**. |
| The root and www return Cloudflare error 1001 | The A records were added to a hostname that was not yet active. | Restore the origin A record, wait for **Active**, then cut over again. |

## FAQ

### Can I use a Route 53 ALIAS record at the root?

No. A Route 53 ALIAS can only target AWS resources or another record in the same hosted zone, not an external hostname. Use the two A records shown in the panel.

### Why does Route 53 say the request contains an invalid set of changes?

A record already exists at that name. Edit the existing record set and replace its values, or use `UPSERT` in the AWS CLI, instead of creating a second record set.

### When can I add the root A records?

Only after the domain shows **Active**. Cloudflare will not verify a domain that already points at its own addresses.

### Do I need the root CNAME the panel mentions?

No. Route 53 cannot hold a CNAME at the root, so the two A records are the root's routing record.
