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アドレスのバージョンと、レコードタイプを合わせるところだけで、意外と簡単です。
-
私がIPv6大好きマンだからです ↩︎
Discussion