2023/06/06 ついでにIPv4も対応させコードを大幅に変更しました。
2023/06/05 レコード更新タイミングをDNS逆引きと一致しない時だけにしました。
2023/06/04 初版
初めに
WEBサーバーIPv6移行についてCloudFlareを利用した
DNSレコード自動更新方法について(※会員登録方法などは割愛します。)
既にMyDNSなどでDDNSを運用されてる方は競合するので停止するか見直して下さい。
以下記事参考にしてます。先駆者様に感謝
https://zenn.dev/ten_takano/articles/20230706-cloudflare-ddns
https://qiita.com/napspans/items/455103748f3a0dd7ee18
CloudFlareにて空のDNSレコードを登録
タイプAAAA(IPv6)、名前(自ドメイン)、IPv6アドレスに::と入力
プロキシを外して空のレコードを登録します。(このレコードが後で更新されます。)
概要ページに戻り下にスクロールしていくと APIトークンを取得 があるので押下
アクセス許可で+さらに追加するを押下し、ゾーン・ゾーン・読み取りで追加し
ゾーンリソースで自ドメインを指定する
APIトークンがDNS編集、ゾーン読み取りになってるのを確認して作成を押下する
APIトークンが表示されます。次に作成するシェルスクリプトで指定しますので控えて下さい。
※閉じると二度と表示されません
シェルスクリプト作成
例としてCloudFlare_ip.shで作成します。
vi CloudFlare_ip.sh
以下設定を自環境に置き換えて下さい
DOMAIN="自ドメイン"
EMAIL="アカウント登録のメールアドレス"
NIC="グローバルIP取得しているNIC名"
API_TOKEN="先ほど生成したトークン"
動作概要
IPとcurlコマンドでIPv6とIPv4のアドレスを取得し
nslookupでドメインを逆引き取得しそれぞれを比較
何れか一致しなかった時だけ、
APIトークンからゾーンID&DNSレコードIDを取得しDNSレコードを更新します。
IPv6はAAAAレコード且つ自ドメイン=nameが一致するレコード
IPv4はAレコード且つ自ドメイン=nameとwww.自ドメイン=name一致のレコード
#!/bin/bash
# 設定
DOMAIN="niuind.com"
EMAIL="ここにメールアドレス"
NIC="enp1s0"
API_TOKEN="ここにAPIトークン"
# 設定終わり
# IPv6アドレスをNICから取得
NICIP6=`ip -f inet6 -o addr show ${NIC}|grep global|cut -d\ -f 7 | cut -d/ -f 1`
# IPv4アドレスをcurlで取得
NICIP4=`curl -s -4 ifconfig.me`
# nslookupで逆引き(IPv6)
DNSIP6=`nslookup -query=aaaa ${DOMAIN} | grep 'Address:' | awk 'NR==2{print $2}'`
# nslookupで逆引き(IPv4)
DNSIP4=`nslookup -query=a ${DOMAIN} | grep 'Address:' | awk 'NR==2{print $2}'`
Set_CFDNSRecord(){
# 1DOMAIN 2EMAIL 3API_TOKEN 4NICIP 5DNSIP 6TYPE 7WWW
NAME="$7$1"
# ZONE_ID 取得
ZONE_ID=`curl -s "\n" --request GET \
--url https://api.cloudflare.com/client/v4/zones?name=$1 \
--header 'Content-Type: application/json' \
--header "X-Auth-Email: $2" \
--header "Authorization: Bearer $3" | jq -r .result[].id`
#echo "ZONE_ID:" $ZONE_ID
# AAAA or A 且つNAMEがDOMAINと一致のRECORD_ID 取得
RECORD_ID=`curl -s "\n" --request GET \
--url https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records \
--header 'Content-Type: application/json' \
--header "X-Auth-Email: $2" \
--header "Authorization: Bearer $3" | jq -r '.result[] | select(.type=="'"$6"'" and .name=="'"$NAME"'") | .id'`
#echo "RECORD_ID("$6"):" $RECORD_ID
DATE=`date '+%Y-%m-%d %H:%M:%S'`
# CloudFlare レコード更新
FRAG=`curl -s --request PUT \
--url https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID \
--header 'Content-Type: application/json' \
--header "X-Auth-Email: $2" \
--header "Authorization: Bearer $3" \
--data '{
"content": "'"$4"'",
"name": "'"$NAME"'",
"proxied": false,
"type": "'"$6"'",
"comment":"'"renew at ${DATE}"'"
}' | jq -r '.success'`
# successなら更新完了とみなす
if [ $FRAG = true ]; then
echo "CloudFlare 更新完了しました($6 $NAME)"
echo "OLD:$5"
echo "NEW:$4"
else
echo "更新失敗しました。"
echo "NICIP:$4"
echo "DNSIP:$5"
fi
}
# IPv6 or IPv4 どちらか一致しなければレコード更新する
if [ ! "$NICIP6" = "$DNSIP6" ]; then
Set_CFDNSRecord $DOMAIN $EMAIL $API_TOKEN $NICIP6 $DNSIP6 "AAAA"
fi
if [ ! "$NICIP4" = "$DNSIP4" ]; then
Set_CFDNSRecord $DOMAIN $EMAIL $API_TOKEN $NICIP4 $DNSIP4 "A"
Set_CFDNSRecord $DOMAIN $EMAIL $API_TOKEN $NICIP4 $DNSIP4 "A" "www."
fi
if [ "$NICIP6" = "$DNSIP6" ] && [ "$NICIP4" = "$DNSIP4" ]; then
echo "IP一致の為更新ありません。"
echo "NICIP6: $NICIP6"
echo "DNSIP6: $DNSIP6"
echo "NICIP4: $NICIP4"
echo "DNSIP4: $DNSIP4"
fi
忘れずに実行権限を付与して実行します。
chmod +x CloudFlare_ip.sh
./CloudFlare_ip.sh
更新完了したらCloudFlareのDNSレコードから確認して下さい。
定期実行例としてsystemdでユニット化してタイマーで回します。
vi /etc/systemd/system/CloudFlare_ip.service
[Unit]
Description=CloudFlare IP renew dns record
[Service]
Type=simple
ExecStart=/usr/bin/CloudFlare_ip.sh
[Install]
WantedBy=multi-user.target
作成したCloudFlare_ip.shを移動しておきます。
mv CloudFlare_ip.sh /usr/bin/CloudFlare_ip.sh
続いてtimerを作成します。
vi /etc/systemd/system/CloudFlare_ip.timer
とりあえず15分定期実行にしてみます。
※IP一致判定をするだけでIP不一致でなければCloudFlareでレコード更新しません
[Unit]
Description=CloudFlare IP renew dns record
[Timer]
Persistent=true
OnCalendar=*-*-* *:00,15,30,45
[Install]
WantedBy=timers.target
サービスの自動起動を有効にしスタートする
systemctl enable CloudFlare_ip.timer
systemctl start CloudFlare_ip.timer
タイマー有効にしたら確認。以下の様に表示されていればOK
systemctl list-timers
NEXT LEFT LAST PASSED UNIT ACTIVATES
Wed 2024-06-05 11:45:00 JST 2min 16s left Wed 2024-06-05 11:42:41 JST 1s ago CloudFlare_ip.timer CloudFlare_ip.service
ログとしてはこんな感じに出ます。
systemctl status CloudFlare_ip.service --lines=20
6月 06 17:00:11 localhost.localdomain CloudFlare_ip.sh[11038]: CloudFlare 更新完了しました(AAAA niuind.com)
6月 06 17:00:11 localhost.localdomain CloudFlare_ip.sh[11038]: OLD:(DNSIP)
6月 06 17:00:11 localhost.localdomain CloudFlare_ip.sh[11038]: NEW:(NICIP)
6月 06 17:00:13 localhost.localdomain CloudFlare_ip.sh[11038]: CloudFlare 更新完了しました(A niuind.com)
6月 06 17:00:13 localhost.localdomain CloudFlare_ip.sh[11038]: OLD:(DNSIP)
6月 06 17:00:13 localhost.localdomain CloudFlare_ip.sh[11038]: NEW:(NICIP)
6月 06 17:00:14 localhost.localdomain CloudFlare_ip.sh[11038]: CloudFlare 更新完了しました(A www.niuind.com)
6月 06 17:00:14 localhost.localdomain CloudFlare_ip.sh[11038]: OLD:(DNSIP)
6月 06 17:00:14 localhost.localdomain CloudFlare_ip.sh[11038]: NEW:(NICIP)
6月 06 17:45:06 localhost.localdomain CloudFlare_ip.sh[11238]: IP一致の為更新ありません。
6月 06 17:45:06 localhost.localdomain CloudFlare_ip.sh[11238]: NICIP6: (NICIP)
6月 06 17:45:06 localhost.localdomain CloudFlare_ip.sh[11238]: DNSIP6: (DNSIP)
6月 06 17:45:06 localhost.localdomain CloudFlare_ip.sh[11238]: NICIP4: (NICIP)
6月 06 17:45:06 localhost.localdomain CloudFlare_ip.sh[11238]: DNSIP4: (DNSIP)
その他注意
トリガーがnslookupの逆引きと一致しなければ、なので
DNSレコードが更新された後も他のネームサーバーのキャッシュ残がヒットして
再度更新するなど処理が重複する可能性があります。
(問題になる様な負荷では無いですが)
DNSレコードのProxyを設定すると当然CloudFlareのProxyアドレスが返ってくるので
ホストのIPアドレスと一致する事はほぼなくなり毎回DNSレコードを更新する様になります。
以上。お疲れ様でした。