LoginSignup
17
10

【CloudFlare】動的IPアドレスをAPIで自動更新する。DDNS

Last updated at Posted at 2023-06-28

前回Google DomainsからCloudFlareにドメインとDNSを移管する記事を書きました。

動的IPでwebサーバーを運用している方はIPが更新されたら通知してあげる必要があります。今回はこの手順について記述していきます。IP更新していくために材料をそろえるのが少しめんどくさいですがお付き合いください。

目次

前提

  • CloudFlareでDNSを運用していること。
  • Linuxサーバーでwebサーバーが運用されていること。
  • sudo 権限

コード、コマンドの***で囲んでいるメールなどの情報は適宜自身の環境にあった項目に書き換えてください。

【材料1】 APIキーの取得

DNSを遠隔で編集するために、2種類の

上記リンクから自身のCloudFlaredのAPIトーク画面を開き、APIキーGlobal API keyを表示します。
image.png
パスワードを入力し、表示された文字列をコピーしてグローバルAPIキーとわかるように保管しておきます。
image.png
次に、APIトーク画面に戻りトークンを作成します。
image.png
ゾーンDNSを編集するのテンプレートで作成します。
image.png
次の画面でアクセス許可ゾーンリソースを編集します。
image.png

  • アクセス許可
    • ゾーン -> DNS -> 編集
    • ゾーン -> ゾーン -> 読み込み
  • ゾーンリソース
    • 包含 -> 特定のゾーン -> ドメイン名

次の確認画面でドメイン名 - ゾーン:読み取り, DNS:編集となっていればOKです。トークンを作成するをクリックしてください。
image.png
トークンが作成されたらAPIトークンとテストコードが発行されます。ここで表示されるキーはこの画面でのみ表示されますので、一度閉じると再表示できませんので大切に保管してください。先ほどと同様にDNS編集用トークンとわかるようにしましょう。DNSレコードを修正する場合はこちらのトークンを使用します。
image.png
表示されているテストコードを実行します。

.sh
curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify"
-H "Authorization: Bearer ***APIトークン***" 
-H "Content-Type:application/json"

実行するとidなどが返ってきます。

{"result":{"id":"*****","status":"active"},"success":true,"errors":[],"messages":[{"code":10000,"message":"This API Token is valid and active","type":null}]}

This API Token is valid and activeとメッセージが入っていればAPIトークンアクセスは正常です。

【材料2】ゾーンIDの取得

.sh
curl -w "\n" --request GET \
  --url https://api.cloudflare.com/client/v4/zones?name=***example.com*** \
  --header 'Content-Type: application/json' \
  --header 'X-Auth-Email: ***CloudFlareアカウントメールアドレス***'\
  --header 'X-Auth-Key: ***グローバルAPIキー***'

出力が下記の通りとなっていれば成功です。jsonの"name":"example.com"が自身のドメインとなっていれば"id":"***32文字乱数***"ゾーンIDとなります。これ次の項で使用しますのでゾーンIDとわかるようにメモしておきます。

{"result":[{"id":"***32文字乱数***","name":"example.com","status":"active",...

【材料3】DNSレコードIDの取得

.sh
curl -w "\n" --request GET \
  --url https://api.cloudflare.com/client/v4/zones/***ゾーンID***/dns_records \
  --header 'Content-Type: application/json' \
  --header 'X-Auth-Email: ***メールアドレス***'\
  --header 'X-Auth-Key: ***グローバルAPIキー***'

ゾーンID取得と同様にjsonが帰ってきます。"zone_id":"***ゾーンID***"の項目が入力したIDと合っていれば最初の項目の"id":"***32文字乱数***"DNSレコードIDになります。

"result":[{"id":"***32文字乱数***","zone_id":"***ゾーンID***",...

ここまでで取得したゾーンIDDNSレコードIDと最初に生成したAPIトークンを使ってIPを更新していきます。

シェルスクリプトの作成

遠隔でDNSのAレコードを更新する際には下記のコマンドを使います。

curl --request PUT \
  --url https://api.cloudflare.com/client/v4/zones/***ゾーンID***/dns_records/***DNSレコードID*** \
  --header 'Content-Type: application/json' \
  --header "X-Auth-Email: ***メールアドレス***" \
  --header "Authorization: Bearer ***APIトークン***" \
  --data '{
    "content": "'"***新しいIPアドレス***"'",
    "name": "'"***更新するドメイン***"'",
    "proxied": false,
    "type": "A",
    "comment": "Domain verification record"
  }'

また、サーバーのIPアドレスが変更された際にサーバー自身は自分のアドレスを知ることができない為、ipアドレスを取得するサービスを利用して新しいIPを知る必要があります。ただし、回数制限やサービスエラーが起こった場合に対処するために複数のサービスで取得できるようにしておきます。

ip_address=""

# IPアドレスを取得する関数
get_ip_address() {
  local url="$1"
  ip_address=$(curl -s "$url")
}

# IPアドレスの正規表現パターン
ip_pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}$"

# 正規表現でIPアドレスが検証できるかチェック
is_valid_ip() {
  [[ $ip_address =~ $ip_pattern ]]
}

# IPアドレス取得のループ
for service in "${services[@]}"; do
  get_ip_address "$service"

  if is_valid_ip; then
    break
  fi
done

上記のコードを組み合わせてアクセス情報を追加したのが下記のコードになるので、update_ip.shなど名前を付けて保存します。

update_ip.sh
#!/bin/bash

# 更新するドメイン
MY_DOMEIN="***sample.com***" 

# API アクセス情報
ZONE_ID="***ゾーンID***"
RECORD_ID="***レコードID***"
AUTH_EMAIL="***メールアドレス***"
API_TOKEN="***APIトークン***"

# IPアドレス取得サービスのリスト
services=(
  "https://api.ipify.org/"
  "https://checkip.amazonaws.com/"
  "https://ipv4.icanhazip.com/"
  "https://4.icanhazip.com/"
)

ip_address=""

# IPアドレスを取得する関数
get_ip_address() {
  local url="$1"
  ip_address=$(curl -s "$url")
}

# IPアドレスの正規表現パターン
ip_pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}$"

# 正規表現でIPアドレスが検証できるかチェック
is_valid_ip() {
  [[ $ip_address =~ $ip_pattern ]]
}

# IPアドレス取得のループ
for service in "${services[@]}"; do
  get_ip_address "$service"

  if is_valid_ip; then
    break
  fi
done

# ipアドレス更新テスト
# ip_address = 8.8.8.8

# CloudFlare API Aレコード更新
curl --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: $AUTH_EMAIL" \
  --header "Authorization: Bearer $API_TOKEN" \
  --data '{
    "content": "'"$ip_address"'",
    "name": "'"$MY_DOMEIN"'",
    "proxied": false,
    "type": "A",
    "comment": "Domain verification record"
  }'

私の場合はユーザフォルダの直下にscriptフォルダを作成し、その中に保存しています。
image.png
保存したらbushコマンドで実行してみます。

~$ bash script/update_ip.sh 

実行結果としては大量のjsonオブジェクトが帰ってきますが、最後の方に"success":trueとなっていれば更新が正常に行われています。不安な方はスクリプトの# ipアドレス更新テスト# ip_address = 8.8.8.8をコメントアウトを削除して試してみるといいと思います。

..."success":true,"errors":[],"messages":[]}

Crontabで自動実行

作成したスクリプトを自動実行してもらえるようにcrontabに設定していきますが、その前にファイルの権限を変更します。

chmod +x script/update_ip.sh

次にcrontabを呼び出します。

sudo crontab -e

crontabが開いたら実行コマンドを追記します。
image.png

*/10 * * * * bash /home/napspans/script/update_ip.sh

追記したコマンドは10分毎に実行するコマンドです。各自サーバーの重要性に応じて設定してください。

追加したらctrl+Xで保存して終了です。
crontabで本当に実行されているか心配な方はスクリプトの最後に>> /path/to/update-ip.log 2>&1を追加してログを取ってみるといいです。

curl --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: $AUTH_EMAIL" \
  --header "Authorization: Bearer $API_TOKEN" \
  --data '{
    "content": "'"$ip_address"'",
    "name": "'"$MY_DOMEIN"'",
    "proxied": false,
    "type": "A",
    "comment": "Domain verification record"
  }'>> /path/to/update-ip.log 2>&1

まとめ

googleやmyDNSはwgetだけでペペっと簡単だったのに、今回はややこしかったですね。
以上で動的IPの方も安心して夜眠れると思います。
お疲れ様でした。 ではまた。

参考文献

17
10
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
17
10