When configuring DNS records, many developers encounter this exact scenario:
; Zone file snippet @ IN A 10.10.10.10 *.example.com. IN A 10.10.10.10 staging IN A 10.10.10.9 new-staging IN CNAME proxy.heroku.com.
The wildcard (*) record acts as a catch-all, but the specific CNAME record should theoretically take precedence. Yet in practice, we're seeing the wildcard A record winning this DNS resolution battle.
The RFC standards (specifically RFC 1034) state that more specific records should override wildcards, but there's a critical exception:
- CNAME vs A Record: The record type matters. A CNAME must be the only record for that name - it cannot coexist with other records for the same name.
- Wildcard Behavior: Wildcards are expanded before specific name lookups occur in the resolution process.
Here's what actually happens during DNS resolution:
- The resolver checks for an exact match (new-staging.example.com)
- If no exact match, it then checks for wildcard matches (*.example.com)
- Only if neither exists does it proceed up the domain hierarchy
Option 1: Remove the wildcard temporarily during migration
# Using AWS CLI example aws route53 change-resource-record-sets \ --hosted-zone-id Z1PEXAMPLE \ --change-batch file://changes.json
Where changes.json contains:
{ "Changes": [{ "Action": "DELETE", "ResourceRecordSet": { "Name": "*.example.com", "Type": "A", "TTL": 300, "ResourceRecords": [{ "Value": "10.10.10.10" }] } }] }
Option 2: Use ALIAS/ANAME records (cloud-specific solution)
# Cloudflare example using Terraform resource "cloudflare_record" "new_staging" { zone_id = var.cloudflare_zone_id name = "new-staging" value = "proxy.heroku.com" type = "CNAME" proxied = true }
- Always test DNS changes with
dig +trace new-staging.example.com
before relying on local cache - Consider TTL reduction prior to making DNS changes (set wildcard TTL to 300 seconds before modification)
- For critical services, implement DNS monitoring with tools like DNSViz or ZoneWatcher
Here's a safe migration pattern we've used successfully:
1. Create temporary name: staging-new.example.com (CNAME to Heroku) 2. Verify functionality 3. Reduce wildcard TTL to 300 4. Remove wildcard 5. Create new-staging CNAME 6. Verify resolution 7. (Optional) Restore wildcard if needed 8. Update all references to use new-staging
In DNS resolution, wildcard records (*.example.com) typically have lower precedence than explicit records (specific.example.com). However, there's a crucial exception when dealing with CNAMEs. The RFC 1034 specification states:
"A CNAME RR is not allowed to coexist with any other data" (Section 3.6.2)
When resolving new-staging.example.com, DNS servers will:
- First look for an exact match (new-staging.example.com)
- If no exact match, then check for wildcard (*.example.com)
In your case, the wildcard A record takes precedence because:
1. No explicit A record exists for new-staging.example.com
2. The CNAME cannot coexist with the wildcard A record
3. The resolver falls back to the wildcard
To fix this, you need to either:
Option 1: Remove the Wildcard
; BIND zone file example
example.com. IN A 10.10.10.10
*.example.com. IN A 10.10.10.10 ; Remove this line
staging.example.com. IN A 10.10.10.9
new-staging.example.com. IN CNAME proxy.heroku.com.
Option 2: Use ALIAS/ANAME Records
Some DNS providers offer pseudo-records that function like CNAMEs at the zone apex:
; Cloudflare example
new-staging.example.com. IN CNAME proxy.heroku.com
; Set Cloudflare proxy (orange cloud) to bypass wildcard
Use dig to verify your DNS setup:
dig +norecurse new-staging.example.com ANY
dig +trace staging.example.com
nslookup -type=CNAME new-staging.example.com
- TTL propagation delays (always check current values)
- DNSSEC validation failures
- DNS caching at multiple levels (local, resolver, authoritative)
For complex migrations:
; Temporary solution during migration
old-staging.example.com. IN A 10.10.10.9
new-staging.example.com. IN CNAME proxy.heroku.com
; Then gradually update client configurations
Always remember that wildcards and CNAMEs have complex interactions that vary slightly between DNS implementations. Test thoroughly in staging before production changes.