🔥

Cloudflare で Dynamic DNS (ありがち)

に公開

はじめに

ありがちですが、Cloudflare を使ったダイナミックDNS(DDNS)のスクリプトを書きました。

いろいろ見て回ったのですが、もっと簡略化できるか、とか、これは違うな、というのがあったので自分で書いて、せっかくなのでシェアしようと思った次第です。

まずはスクリプトを

https://github.com/keioni/blog-sample/blob/main/cloudflare-ddns/cf-ddns.sh

実行前に Cloudflare のダッシュボードから作ったAPIトークンを export してください。

(例)

export API_TOKEN=example6ZzJYRUl5ya_9r2hEN6k9n65AMTaZuSst

実行方法は以下の通りです:

./cf-ddns.sh FQDN [-4]

FQDNが存在しないときは、意図せぬレコードを作らないようエラーにしています。あらかじめ、Dynamic DNS として使うレコードを設定してください。

デフォルトでは IPv6 を対象にします。IPv4 のレコードを操作するには、コマンドラインの末尾に -4 を付けてください。

./cf-ddns.sh myhome.example.com -4

逐次解説

スクリプトのコアの部分を抜き出して説明します。
一部エラー処理を除くなどしています。

現在のIPアドレスの取得

IPのバージョンにあわせたアドレスを取得し、レコードタイプも設定します。
繰り返しますがデフォルトはIPv6です[1]

IPアドレスの取得にはセキュアな VPN やメール SaaS を提供する Proton 社が提供している ip.me を使っています。

if [ "$IP_VERSION" = "-4" ]; then
    ip_address=$(curl -s -4 https://ip.me)
    record_type="A"
else
    ip_address=$(curl -s -6 https://ip.me)
    record_type="AAAA"
fi

アカウントIDの取得

アカウントIDを使うことはありませんが、APIトークンの有効性確認のために使っています。

account_id=$(curl --silent -X GET "https://api.cloudflare.com/client/v4/accounts" \
    -H "Authorization: Bearer $API_TOKEN" \
    | jq -r '.result[0].id')

DNSゾーンIDの取得

FQDNから最初の . まで取り除きます。これを domain_name として扱います。

この部分は手抜きをしています。実際は、たとえばFQDNが foo.bar.example.com だったとしたとき、Cloudflare の場合、ゾーン名は example.com ですが、このコードでは bar.example.com を domain_name にしてしまいます。

このスクリプトをそのまま使うなら、DDNSのレコードはゾーン直下でなければなりません。

たとえばゾーンが example.com なら:

  • foo.example.com
  • foo.bar.example.com

となります。

そのドメイン名から、ゾーンIDを取得します。

domain_name="${FQDN#*.}"
zone_id=$(curl -s "https://api.cloudflare.com/client/v4/zones/?name=$domain_name" \
    -H "Authorization: Bearer $API_TOKEN" \
    | jq -r '.result[] | select(.name == "'"$domain_name"'") | .id')

レコードIDの取得

取得したゾーンにあるFQDNからレコードIDを取得します。

record_id=$(curl --silent "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records?name=$FQDN" \
    -H "Authorization: Bearer $API_TOKEN" \
    | jq -r '.result[] | select(.type == "'"$record_type"'" | .id')

レコードの更新

zone_id と record_id を指定して、PATCHして更新します。

curl -s "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records/$record_id" \
    -X PATCH \
    -H "Authorization: Bearer $API_TOKEN" \
    -d '{
        "type": "'"$record_type"'",
        "name": "'"$FQDN"'",
        "content": "'"$ip_address"'",
        "ttl": 3600,
        "proxied": false
    }' > $tmp_json

さいごに

気をつけなければならないのは、IPアドレスのバージョンと、レコードタイプを合わせるところだけで、意外と簡単です。

脚注
  1. 私がIPv6大好きマンだからです ↩︎

Discussion