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に格納
③上記の①と②の値が違う場合、以下の処理を行います。
- Conoha APIでトークンを取得
- Conoha APIでドメインIDを取得
- Conoha APIでレコードIDを取得
- Conoha APIで対象のAレコードを新しいIP(
$NEW_IP
)に設定 - 成功時および失敗時にメールにて送信および、成功時に更新した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の契約をしたい場合は、当リンクから申し込みいただけますと幸いです。
ここまで、読んでくださりありがとうございました。