1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CloudFlareを利用したIPアドレス(IPv6/IPv4)のDNSレコード自動更新

Last updated at Posted at 2024-06-04

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レコードを登録

WEBサイトメニューから自サイトを登録して設定に進みます。
cf001.JPG

DNSレコードからレコードの追加を押下
cf012.JPG

タイプAAAA(IPv6)、名前(自ドメイン)、IPv6アドレスに::と入力
プロキシを外して空のレコードを登録します。(このレコードが後で更新されます。)
cf013.JPG

空のレコードが追加されたか確認します。
cf015.JPG

概要ページに戻り下にスクロールしていくと APIトークンを取得 があるので押下
cf002.JPG

ユーザーAPIトークンからトークンを作成するを押下
cf005.JPG

ゾーンDNSのテンプレートを使用します。
cf006.JPG

アクセス許可で+さらに追加するを押下し、ゾーン・ゾーン・読み取りで追加し
ゾーンリソースで自ドメインを指定する
cf007.JPG

概要に進むで次へ
cf008.JPG

APIトークンがDNS編集、ゾーン読み取りになってるのを確認して作成を押下する
cf009.JPG

APIトークンが表示されます。次に作成するシェルスクリプトで指定しますので控えて下さい。
※閉じると二度と表示されません
cf010.JPG

シェルスクリプト作成

例としてCloudFlare_ip.shで作成します。

shell (Linux)
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一致のレコード

CloudFlare_ip.sh(Linux)
#!/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

忘れずに実行権限を付与して実行します。

shell (Linux)
chmod +x CloudFlare_ip.sh
./CloudFlare_ip.sh

更新完了したらCloudFlareのDNSレコードから確認して下さい。
cf011.JPG

定期実行例としてsystemdでユニット化してタイマーで回します。

shell (Linux)
vi /etc/systemd/system/CloudFlare_ip.service
CloudFlare_ip.service (Linux)
[Unit]
Description=CloudFlare IP renew dns record

[Service]
Type=simple
ExecStart=/usr/bin/CloudFlare_ip.sh

[Install]
WantedBy=multi-user.target                               

作成したCloudFlare_ip.shを移動しておきます。

shell (Linux)
mv CloudFlare_ip.sh /usr/bin/CloudFlare_ip.sh

続いてtimerを作成します。

shell (Linux)
vi /etc/systemd/system/CloudFlare_ip.timer

とりあえず15分定期実行にしてみます。
※IP一致判定をするだけでIP不一致でなければCloudFlareでレコード更新しません

CloudFlare_ip.timer (Linux)
[Unit]
Description=CloudFlare IP renew dns record

[Timer]
Persistent=true
OnCalendar=*-*-* *:00,15,30,45

[Install]
WantedBy=timers.target

サービスの自動起動を有効にしスタートする

shell (Linux)
systemctl enable CloudFlare_ip.timer
systemctl start CloudFlare_ip.timer

タイマー有効にしたら確認。以下の様に表示されていればOK

shell (Linux)
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

ログとしてはこんな感じに出ます。

shell (Linux)
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レコードを更新する様になります。

以上。お疲れ様でした。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?