根据 RFC1912,域名根目录不得存在 CNAME 记录,因为根目录下的 CNAME 记录会使得整个域名的 MX
邮箱记录、TXT
域名验证记录等全部失效。
因此,CloudFlare 推出了拉平根目录 CNAME 的功能,通过 CloudFlare 的服务器,将 CNAME 解析为 A 记录,避免了冲突问题。
但是有一点问题,如果像 CDN 这样的,会根据请求者的 IP 而改变的动态 CNAME 记录,将会被 CloudFlare 拉平为一个固定的 A 记录。
CloudFlare 的主服务器位于境外,即使你的用户主要是在国内,CloudFlare 仍然会将其拉平为美国的服务器,使得这个固定的 A 记录经常速度太慢、延迟过高甚至超时。
因此,编写 Python 程序来解决这个问题。
自定义 CNAME 拉平 Python 程序
import requests
import socket
def get_dns_id(email, api_key, zone_id, record_name):
url = f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records"
headers = {
"Content-Type": "application/json",
"X-Auth-Email": email,
"X-Auth-Key": api_key
}
try:
response = requests.request("GET", url, headers=headers)
data = response.json()
except:
print(f"Some thing went wrong while listing the DNS record: Network Error")
exit(-1)
if(not data["success"]):
print(f"Some thing went wrong while listing the DNS record: {data['errors'][0]['message']}")
exit(-1)
else:
for record in data["result"]:
if(record["name"] == record_name):
return record["id"]
print(f"Some thing went wrong while listing the DNS record: Record doesn't exist.")
exit(-1)
def get_dns(email, api_key, zone_id, record_id):
url = f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{record_id}"
headers = {
"Content-Type": "application/json",
"X-Auth-Email": email,
"X-Auth-Key": api_key
}
try:
response = requests.request("GET", url, headers=headers)
data = response.json()
except:
print(f"Some thing went wrong while getting the DNS record: Network Error")
exit(-1)
if(not data["success"]):
print(f"Some thing went wrong while getting the DNS record: {data['errors'][0]['message']}")
exit(-1)
else:
return data["result"]["content"]
def update_dns(email, api_key, zone_id, record_name, record_id, record_type, value):
url = f"https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{record_id}"
payload = {
"content": value,
"name": record_name,
"type": record_type
}
headers = {
"Content-Type": "application/json",
"X-Auth-Email": email,
"X-Auth-Key": api_key
}
try:
response = requests.request("PUT", url, json=payload, headers=headers)
data = response.json()
except:
print(f"Some thing went wrong while updating the DNS record: Network Error")
exit(-1)
if(not data["success"]):
print(f"Some thing went wrong while updating the DNS record: {data['errors'][0]['message']}")
exit(-1)
else:
return data["result"]["content"]
def resolve_domain(domain_name):
try:
ip_address = socket.gethostbyname(domain_name)
return ip_address
except socket.gaierror as e:
print("Something went error while resolving the domain: ", e)
exit(-1)
email = "Your Email"
api_key = "Your API-Key (https://dash.cloudflare.com/profile/api-tokens)"
zone_id = "Domain's Zone ID"
flatten_record_name = "Record name that wanted to be flatten"
target_cname = "Target CNAME"
flatten_record_type = "A" # Fixed, do not modify
print(f"Accoount Email: {email}")
print(f"Account API-Key: {api_key}")
print(f"Zone ID: {zone_id}")
flatten_rercord_id = get_dns_id(email, api_key, zone_id, flatten_record_name)
print(f"Flatten Record Name: {flatten_record_name} (ID = {flatten_rercord_id})")
current_dns = get_dns(email, api_key, zone_id, flatten_rercord_id)
print(f"Current DNS: {current_dns}")
fastest_ip = resolve_domain(target_cname)
if(fastest_ip == current_dns):
print(f"Fastest IP: {fastest_ip}, everything up to date")
else:
print(f"Fastest IP: {fastest_ip}, trying to update dns...")
print(f"Updated DNS: {update_dns(email, api_key, zone_id, flatten_record_name, flatten_rercord_id, flatten_record_type, fastest_ip)}, done.")
Python将这个程序部署于你的网站大部分用户所在的区域,并每隔 5~10 分钟运行一次,程序会从你的区域获取最快的 IP 并应用到 CloudFlare DNS 记录上。
注意请在部署前填入 CloudFlare 账户信息、欲拉平的域名以及要解析的目标 CNAME:
exit(-1)
email = "Your Email"
api_key = "Your API-Key (https://dash.cloudflare.com/profile/api-tokens)"
zone_id = "Domain's Zone ID"
flatten_record_name = "Record name that wanted to be flatten"
target_cname = "Target CNAME"
flatten_record_type = "A" # Fixed, do not modify
print(f"Accoount Email: {email}")
Python