技術 ブログ

ConoHaのAPIでダイナミックDNSを実装する




はじめに



自宅および会社のサーバにSSHでアクセスしたり、リバースプロキシでバックエンドサーバ(アップストリーム)として自宅や社内のアプリケーションに接続したいことがITエンジニアをやっていると良くありませんでしょうか?

しかし、自宅や会社のグローバルIPが固定IPではなく、動的(ダイナミック)だと基本的にそれはできません。

ですが、例えばダイナミックDNSで、「home.example.com」のDNSレコードに対して、動的に参照するIPアドレスを変えれば、ドメインネームは契約しているかぎり固定なので、それが可能です。

具体的には、自分のグローバルIPが一時的に123.123.123.123だとして、「home.example.com」というドメインののAレコードに、そのIP「123.123.123.123」を登録していた場合、自分のグローバルIPが自動的に321.321.321.321に代わってしまったら、同じAレコードを「321.321.321.321」に自動で更新します。


これを行ってくれる無料のダイナミックDNSもありますが、自分が保有しているドメインが使えませんし、利用者はサービス提供側のDNSサーバーに頼るため、サービスの継続性に不安があります。


そこで、ConoHaのAPIを使って、動的にDNSのレコードを更新するbashを作りました。

思ったより苦戦したため、以下にて作成したコードを共有します。


作成したコード


前提作業


前提として以下作業が必要になります。


①ConoHaの管理画面で以下APIユーザを作成する必要があります。


②ConoHaのAPIでは、JSONでレスポンスが返ってきます。そのため、LinuxにJSONをクエリできるjqコマンドおよび、IPアドレス変更時およびエラー時にメールを送信するのにssmtpコマンドをインストールしています。また、ssmtpではメール設定が完了しています。

③既に、利用を想定しているドメイン (例: home.example.com) をConoHa DNSのAレコードに設定しています。

※動的に変更するためDNSのAレコードのTTLを短め60~120程度にしておいたほうが、IP変更時のダウンタイムを短く抑えられます。


処理の流れ


①以前の保存したグローバルIPを変数$OLD_IPに格納

curl -s http://api.ipify.orgにて、現在のグローバルIPを取得して変数$NEW_IPに格納

③上記の①と②の値が違う場合、以下の処理を行います。

  1. Conoha APIでトークンを取得

  2. Conoha APIでドメインIDを取得

  3. Conoha APIでレコードIDを取得

  4. Conoha APIで対象のAレコードを新しいIP($NEW_IP)に設定

  5. 成功時および失敗時にメールにて送信および、成功時に更新したIPをファイル (oldIp.txt)に書き込む (①で利用するため)
    ※ここは、完璧にするとキリがないため、適当に実装しています。



コードの解説


変数



EMAIL・・・エラー時に送りたいメールアドレスを設定


USER_NAME・・・ConoHaのAPIのユーザ名(ConoHaのアカウント名ではありません)

PASSWORD・・・ConohaのAPIのパスワード

TENANT_ID・・・ConohaのテナントID(管理画面のAPIのページで見れます)


IDENTITY_SERVICE_URL・・・アイデンティティサービスのURL(管理画面のAPIのページで見れます)

DNS_SERVICE_URL・・・DNSサービスのURL(管理画面のAPIのページで見れます)

※上記は、アカウントによって微妙に変わりますのでご注意ください


BASE_DOMAIN_NAME・・・自分の保有しているドメインネーム(例: example.com.)

UPDATE_DOMAIN_NAME・・・動的に更新したいドメインネーム(例: home.example.com.)


※ハマりポイントとして、ドメインネームの最後にドット「.」が必要です

#!/bin/bash

cd "$(dirname "$0")"

# Email Address
EMAIL="hogehoge@example.com"

# User Information
USER_NAME="xxxx9999999"
PASSWORD="********"
TENANT_ID="fffffffffffffffffffffffff"

# Service URL
IDENTITY_SERVICE_URL="https://identity.tyo2.conoha.io/v2.0/tokens"
DNS_SERVICE_URL="https://dns-service.tyo2.conoha.io/v1/domains"

# Domain Name
BASE_DOMAIN_NAME="example.com."
UPDATE_DOMAIN_NAME="home.example.com."

# IP
OLD_IP=$(cat ./oldIp.txt)
NEW_IP=$(curl -s http://api.ipify.org)

echo "***** Bach Start *****"
echo "Execusion date: `date`"

wait


function changeIp () {
        # Get Conoha Wing Token Information

        API_TOKEN=$(curl -X POST -H "Accept: application/json" \
                         -d "{\"auth\":{\"passwordCredentials\":{\"username\": \"$USER_NAME\",\"password\": \"$PASSWORD\"},\"tenantId\": \"$TENANT_ID\"}}" \
                         $IDENTITY_SERVICE_URL | jq -r '.access | .token | .id')
        wait

        echo "Obtrained Token: $API_TOKEN"

        # Get Conoha Wing Domain ID

        DOMAIN_ID=$(curl -X GET \
                         -H "Accept: application/json" \
                         -H "Content-Type: application/json" \
                         -H "X-Auth-Token: $API_TOKEN" \
                         $DNS_SERVICE_URL | jq -r ".domains[] | select(.name==\"$BASE_DOMAIN_NAME\") | .id")

        wait

        echo "Obtained Domain id: $DOMAIN_ID"

        # Get Record ID

        RECORD_ID=$(curl  $DNS_SERVICE_URL/$DOMAIN_ID/records \
                           -X GET \
                           -H "Accept: application/json" \
                           -H "Content-Type: application/json" \
                           -H "X-Auth-Token: $API_TOKEN" | jq -r ".records[] | select(.name==\"$UPDATE_DOMAIN_NAME\") | .id")


        echo "Obtained Record id: $RECORD_ID"


        # Update Conoha Wing DNS A record


        RESULT=$(curl $DNS_SERVICE_URL/$DOMAIN_ID/records/$RECORD_ID \
                      -X PUT \
                      -H "Accept: application/json" \
                      -H "Content-Type: application/json" \
                      -H "X-Auth-Token: $API_TOKEN" \
                      -d "{ \"data\": \"$NEW_IP\" }")

        echo "Update Resut: $RESULT"

        return 0
}


# Check Logic
if [ $OLD_IP = $NEW_IP ]; then
    echo "Global IP has not changed yet!"
else

    # Call Function
    changeIp
    if [ $? != 0 ]; then
       echo -e "Subject: Failed to Change Global IP\n\nFailed to Change Dynamic Global IP $OLD_IP to $NEW_IP!" | tee >(ssmtp $EMAIL)
       exit 1
    fi

    echo -e "Subject: Dynamic Global IP has Changed\n\nYour Global IP has changed $OLD_IP to $NEW_IP!" | tee >(ssmtp $EMAIL)
    echo $NEW_IP > ./oldIp.txt
fi

echo "***** Batch End *****"



CRON


上記のbashを設定したい家庭内もしくは企業内のサーバーでCRONを使って定期実行します。

CRONは、以下のように1分毎に実行しています。logが不要ならば、/dev/nullに捨てたほうが良いと思います。


ConoHaのDNSのAレコードのTTLも同様に短くしているので、接続不可になる時間を短くできます。

MAILTO=""
*/1 * * * * bash /[配置先]/dynamicDns.sh >> /[配置先]/log.txt


まとめ



上記にてConoHaのAPIを使ってダイナミックDNSを実装しました。

Web APIを使ったシェルなので、長くなり設定が複雑です。


設定される場合は、バッチ化する前に十分テストをすることをお勧めします。

また、ConoHaのAPIの理解も必要になります。

不明点やコードの改善等ありましたら、お気軽にご指摘いただけますと幸いです。

本設定の他に自宅や企業内のネットワークにアクセスするには、ポートフォワーディングの設定も必要になります。

ConohaWINGの契約をしたい場合は、当リンクから申し込みいただけますと幸いです

ここまで、読んでくださりありがとうございました。




コメント投稿フォーム

メールアドレスが公開されることはありません。 が付いている欄は必須項目です