让 CloudFlare 根目录 CNAME 拉平更好用

根据 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

此作品(让 CloudFlare 根目录 CNAME 拉平更好用)基于 CC-BY-NC-SA 4.0 协议授权。

转载请注明来源:作者:CodeZhangBorui,链接:https://codezhangborui.com/2023/08/make-cloudflare-cname-flatten-better/

暂无评论

发送评论 编辑评论


				
上一篇
下一篇