Starlink(スターリンク)用のDDNS環境をGCP使って構築しました!
2024年04月03日 水曜日
CONTENTS
Starlinkのネットワークにインターネットからアクセスする
筆者は日頃Starlink配下の機器に直接インターネットからIPv6経由でアクセスして実験や検証をしています。Starlink Routerを介さず、直接アンテナ配下に接続すると使えるのはIPv6アドレスだけですが直接通信できます。Starlink Routerは細かいカスタマイズができないので、このような使い方をしています。USに設置している機器はStarlink Routerの配下にあるため、Wireguardを使ったVPNで接続しています。
IPv6アドレスは暗記できるものでもないのでDNSサービスを紐づけて名前でアクセスできるようにしていますがStarlinkのIPv6アドレスは知らないうちに変更される事があります(正確にはPrefixが変更される)。そこでアドレスが変更された事を検出してDNS情報を自動的に更新するようなシステムを作っていました。
Google DomainsとDDNS機能の提供終了について
筆者が使っているDNSサービスはGoogle Domainsです。ここはDDNSの機能を提供しておりAPI経由でDNS情報を更新する事ができました。Google Domainsに対応した更新プログラム、ddclientを組み合わせて使っていました。
Google Domainsは2014年からあるサービスでしたが、2023年の6月にSquarespaceに売却されてしまいました。筆者のドメインはSquarespace へのサービス移管が進んでいる最中(というか契約的には終わっている)になっています。
筆者はGoogle Domainsで利用できるすべての機能がSquarespaceに引き継がれると思っていましたが、1月26日にメールの案内があり、DDNS機能はSquarespaceでは提供されない事が判明しました。しかもあなたのドメインはあと1ヶ月ぐらいで移管されるとあり、急いで代わりのシステムを考えなくてはならなくなりました。
DDNSが使える別のDNSサービスへドメイン含めて乗り換えも考えましたが、Google Work Spaceも使っており移行先の検討時間も足りず乗り換えは敷居が高いと感じました。
そこで久しぶりに
- 自前でDNSサーバを立ち上げ、
- 今のドメインのサブドメインとして運用し、
- DDNS機能を使って参照したい機器のIPアドレスを更新する。
形を考えました。ドメイン全体を自前のDNSサーバにするわけではなく、サービスが止まっても名前でアクセスできないだけなので自分が使う分にこれでいいかなと思いました。
DNSサーバの構築
今回はWireguardを動かしているGCP上の仮想サーバに相乗りさせる事にしました。月額117円しかかかっていない仮想サーバですが、まだ余裕はあります。システムはBIND9を使うことにしました。
BINDと聞くと「うーん」となる人が最近は多いかもしれませんが、他に選択肢がなかった時代から使っているので慣れていた事や今もメンテナンスされており情報取得にも不安はなかったのでこれにしました。
Google DomainsはDNSSECに対応しているので、自分のシステムも対応させています。細かい構築手順は省略しますがBIND : 外部ネットワーク向けの設定を参考に、設定ファイルを作成し、空のサブドメインを立ち上げ、鍵情報をGoogle DomainsのDNSレコードに登録します。
空のサブドメインはDDNSによる更新を有効にし、DNSレコードの登録や削除に必要なnsupdateコマンド用の共通鍵を設定します。この鍵があれば、インターネットのどこからでもDNSレコードの更新ができるようになります。
Cloud Functions の活用
DNSの準備ができたので、次はDNSレコードの登録システムの構築です。これまではDNSレコードの更新はddclientを使っていました。ddclientは便利なツールですが、今回はnsupdateコマンドを使った、スクリプトを作成する事にしました。結果的にこの方がシンプルで見通しが良くなったと思っています。
自分のIPアドレスを確認する方法として実際にインターネットに接続してIPアドレスを確認する外部サービスを使う事を考えました。自分のIPアドレスを確認できる無償サービスは沢山ありますが、Google Domainsをみた後なので、無償サービスは避け、またサービス提供側にIPアドレスの記録が残るので自分で作成して情報を閉じた方がいいだろうと思いました。
サービスを何でつくるかですが、以前から興味があったCloud Functionsを使ってみる事にしました。これを使うと関数を書く感覚でネットワークサービスを作る事ができます。しかも月間200万回呼び出しまで無償で利用できます!。
ここでは関数を2個作りました。一つはアクセス元のIPアドレス情報を出力する関数です。もう一つは「何もしない」関数ですが、単純にDNS情報の更新記録を保管するために使っています。いずれも標準のテンプレートをベースに最小限の改修で作る事ができました。非常に楽ができます。
const functions = require('@google-cloud/functions-framework'); functions.http('helloHttp', (req, res) => { const ipAddress = req.headers["x-forwarded-for"] || req.ip; res.send( ipAddress ); });
const functions = require('@google-cloud/functions-framework'); functions.http('helloHttp', (req, res) => { res.send(``); });
更新スクリプトの作成とsystemdへの登録
DNSの更新スクリプトはこんな感じになります。$TTLで示した秒数を基準にしてdigコマンドと$IPCMDの結果を比較します。違っていたらnsupdateコマンドを使ってDNS側のレコードを更新し、$LOGCMDを使って更新記録を残します。
#!/bin/bash BASE=/usr/local/etc/ddns KEYFILE=ddnskey NAMESERVER="DNSサーバの名前" ZONE="更新するゾーン名" IPCMD="IPアドレス用Cloud FunctionsのURL" LOGCMD="log記録用Cloud FunctionsのURL" TTL="300" while true do OLDIPADDR=`dig +short $ZONE aaaa` IPADDR="`curl -6 -s $IPCMD/$ZONE`" if [ "$OLDIPADDR" != "$IPADDR" ]; then DATE="`date +'%F\ %T'`" ( echo "server $NAMESERVER" echo "update delete $ZONE AAAA" echo "update add $ZONE $TTL AAAA $IPADDR" echo "send" ) | nsupdate -k $BASE/$KEYFILE curl -6 -s $LOGCMD/$ZONE fi sleep $TTL done
あとは作成したスクリプトをsystemdに登録して完成です。
登録用のテンプレートはこんな感じになります。
[Unit] Description=Update DNS After=network-online.target [Service] ExecStart=/usr/local/etc/ddns/ddns-update Restart=always User=実行ユーザID Group=実行グループID [Install] WantedBy=default.target
これで、StarlinkのIPv6 Prefixが変更されても自動的に追従する仕組みの完成です。このシステムはIPv6の更新を念頭に入れて作っていますが、IPアドレスの確認部分を改修すればIPv4にも対応します。
最近のStarlink
XのStarlinkアカウントからも投稿がありましたが、Starlinkの性能改善が着々と進んでいます。自分の観測でも遅延の改善・通信速度の向上を確認しています。複数のStarlink衛星をレーザーリンクで接続しメッシュネットワークのような形でジッターを改善した事で実測値が設計上の理論値に徐々に近づいてきています。地球上を回っているStarlink衛星自体にも性能差があるので、掴んだ衛星による変動があります。今後も性能が高い衛星が増えるいくことで性能向上が期待できそうです。