基于Cloudflare DNS 部署 IPv6 DDNS

需求

自己有一个树莓派,在家可以拿到公网IPv6地址。
但IPv6地址经常变化,所以需要将IPv6地址映射到域名上。这样后面配置各种服务会方便很多。

参考内容:

[1] 知乎专栏, "基于 Cloudflare DNS API 部署 IPv6 DDNS", https://zhuanlan.zhihu.com/p/69379645
[2] Cloudflare API v4 Documentation, "Update DNS Record", https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record
[3] Cloudflare API v4 Documentation, "List DNS Records", https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records

本文基本上是按照文章[1]做的,只是稍有一些细节的更新。除此之外具体的API细节还参考了官方的API Doc[2, 3]。

需求资源

  • 一个域名,并且已经托管到Cloudflare。我们这里假设是 114514.love
  • 拥有公网IPv6的一个server。我的是一台装好了官方系统的Raspberry Pi 3B。

主要流程

1. 获取相关的Key

进入cloudflare的主页 -> 左侧Websites -> 点击中间的域名,进入域名设置部分。Overview的右侧有一栏是API,在这里看到ZoneID和AccountID。而API Key则需要点击API token的获取,会要求验证密码。


API部分长成这样

请务必保存好自己的这些Key,并记录下如下内容:

  • 你注册Cloudflare的邮箱。例:senpei@imn.org
  • Zone ID。每一个域名为一个Zone,这个ID则代表了是哪个域名下。比如我们假设这里Zone ID是Sleep-Black_Tea-ZoneID
  • API token。通过上面Get your API token获取到。我们假设咱们的token是nnnaaaAAAA!!!-APIToken
  • 除此之外我们还需要一个DNS Record ID。请参考下面的过程获取到这个ID。我们先假设这个ID是 OneSummerDREAM-RecordID

2. 添加AAAA记录并获取其ID

进入cloudflare的主页 -> 左侧Websites -> 点击中间的域名,进入域名设置部分。点击DNS,右侧选择Add record。我们增加一条DNS解析记录。如下图所示(图是P的)。

一个解析的样例。(图是P的!)

解释一下每个部分的含义:

  • Type:AAAA表示为ipv6的解析。
  • Name:这里写了summer,那么我们之后使用域名的时候就是输入 summer.114514.love
  • Content: 这里先写一个空白的v6地址。之后我们会使用自己的API对其进行修改。
  • Proxy Status:把橘红色可以点掉,我们这里只需要它做DNS解析。
  • TTL:可以设置一个你认为合适的时间。时间越长,DNS服务更新的就越慢。

搞定了之后,我们需要参考官方API文档[2]里面的内容,使用GET方法获得这个summer.114514.love所对应的Record ID。你可以使用任何一种你习惯的方式。官方样例里面直接用的是curl。既然我们都在树莓派下是一个linux环境,那么这里就直接运行curl进行结果的获取:

curl -X GET "https://api.cloudflare.com/client/v4/zones/Sleep-Black_Tea-ZoneID/dns_records?type=AAAA&name=summer.114514.love&page=1&per_page=100&order=type&direction=desc&match=all" \
     -H "X-Auth-Email: senpei@imn.org" \
     -H "X-Auth-Key: nnnaaaAAAA!!!-APIToken" \
     -H "Content-Type: application/json"

url里面具体的参数请参考doc里面的说明。总之应该可以拿到一个返回值的结果,结果直接打印在terminal里面会比较乱,但整理之后应该大概长成下面这个样子:

{
  "success": true,
  "errors": [],
  "messages": [],
  "result": [
    {
      "id": "OneSummerDREAM-RecordID",
      "zone_id": "Sleep-Black_Tea-ZoneID",
      "zone_name": "114514.love",
      "name": "summer.114514.love",
      "type": "AAAA",
      "content": "::1",
      ... # 以下省略
    }
  ]
}

我们需要的是result下面的id,这个就是该条目的Identifier。请记录下来。

3. 写DNS更新脚本并定时运行

更新现有的DNS条目可以参考官方文档[3]。写一个PUT即可完成。我们本地的脚本需要完成的工作为:

  1. 获取本机的IPv6地址。
  2. 调用官方给的API,用PUT更新上去。
  3. 能跑通后,把这个脚本设成每x分钟运行一次。

当然更优的方式是保存下来IPv6地址,只在变化的时候运行更新脚本。不过我懒了暂时没写这个。由于个人更熟悉Python操作,所以这个脚本我是用的Python写的,放出来仅供参考。Python版本3.6,由于用到了f-string更低的版本请自行修改。

import request

def update_addr(ipv6):
    email = 'senpei@imn.org'
    zone_id = 'Sleep-Black_Tea-ZoneID'
    api_key = 'nnnaaaAAAA!!!-APIToken' 
    record_id = 'OneSummerDREAM-RecordID'

    url_target = f'https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{record_id}'
    headers = {
        'X-Auth-Email': email,
        'X-Auth-Key': api_key,
        'Content-type': 'application/json',
    }
    data = {
        'type': 'AAAA',
        'name': 'blackpi.100097.xyz',
        'content': ipv6,
        'ttl': 300,
        'proxied': False,
    }
    resp = requests.put(url_target, headers=headers, json=data)
    return resp

而其中ipv6的地址则是使用了正则表达式获取:

import os
import re

def get_ipv6():
    command = 'ip -6 addr show dev eth0 | grep global'
    x = os.popen(command).read()
    result = re.findall(r'(([a-f0-9]{1,4}:){7}[a-f0-9]{1,4})', x, re.I)
    ipv6 = result[0][0]
    return ipv6

以上。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容