
自宅回線(動的IP)でも、MyDNSを使えば独自のホスト名で外部公開が可能です。この記事では、**グローバルIPの変化を検知してMyDNSへ自動更新(ログイン更新)**するシェルスクリプトと、cron/systemdでの定期実行方法、安全に運用するためのポイントを解説します。
この記事でできること
- 自分のグローバルIPアドレスを複数サービスで取得して照合
- IPが変わっていたら**MyDNSに更新(ログイン)**を投げる
- 1分おきなどで自動実行(cron / systemd)
- 認証情報を安全に扱うための実装例つき
前提条件
- Linux系OS(bash可動環境)
curlと(オリジナル同様)wgetのいずれか- MyDNSのアカウントを取得済み(ゾーン/ホスト設定済み)
⚠️ セキュリティ注意
記事やGitリポジトリにID/パスワードの平文を載せないでください。既に公開されてしまった場合は直ちにパスワード変更を。
仕組み(概要)
- 外部のIP照会サービスから現在のグローバルIPを取得
- 前回保存したIP(
oldip)と比較 - 変化があれば、MyDNSへBasic認証でアクセス(=更新トリガ)
- 正常終了後、
oldipを新しいIPで上書き
シンプル版スクリプト(元ロジック準拠・伏せ字済)
まずは「動く最小例」。後半に**強化版(HTTPS/リトライ/IPv6対策/ロック)**も用意しています。
#!/bin/sh
# MyDNS: グローバルIP変化時のみ更新(簡易版)
ACC="mydns_account" # ← あなたのアカウント名に置換
PASSWORD="********" # ← パスワードは直書きせず環境変数化推奨
STATE_FILE="/opt/oldip"
IPINFO="$(curl -s inet-ip.info)"
KAKUNIN="$(curl -s kakunin.teraren.com)"
GLOBALIP="$(curl -s globalip.me)"
# 初回ファイル作成
if [ ! -e "$STATE_FILE" ]; then
echo "0.0.0.0" > "$STATE_FILE"
echo "状態ファイルを作成: $STATE_FILE"
fi
OLDIP="$(cat "$STATE_FILE")"
UPDATE() {
# ※ 本番はHTTPS推奨。wgetでもcurlでもOK
/usr/bin/wget -O - "http://${ACC}:${PASSWORD}@www.mydns.jp/login.html" >/dev/null 2>&1
}
if [ "$IPINFO" != "$OLDIP" ]; then
UPDATE && echo "$IPINFO" > "$STATE_FILE" && exit 0
elif [ "$KAKUNIN" != "$OLDIP" ]; then
UPDATE && echo "$KAKUNIN" > "$STATE_FILE" && exit 0
elif [ "$GLOBALIP" != "$OLDIP" ]; then
UPDATE && echo "$GLOBALIP" > "$STATE_FILE" && exit 0
else
echo "グローバルIPの変更はありませんでした。"
fi
ポイント
- 取得先を3つ用意して取りこぼしを回避(どれかが落ちていてもOK)。
STATE_FILE(/opt/oldip)に前回IPを保存し、変化時のみ更新。- 可能なら HTTPS・環境変数(例:
$MYDNS_ACCOUNT/$MYDNS_PASSWORD)の利用を強く推奨。
セキュア & 堅牢な「改良版」スクリプト
- HTTPSでMyDNSへ接続
- 複数IPソースを順に試し、正規表現でIPv4を検証
- 環境変数でID/パスを注入(例:
MYDNS_ACCOUNT/MYDNS_PASSWORD) - ロックで多重起動防止、原子的書き込みで状態ファイルの破損防止
- IPv6経路での誤検出を避けるため**
curl -4**使用
#!/usr/bin/env bash
set -euo pipefail
#=== 設定 ===#
: "${MYDNS_ACCOUNT:?MYDNS_ACCOUNT を環境変数で指定してください}"
: "${MYDNS_PASSWORD:?MYDNS_PASSWORD を環境変数で指定してください}"
STATE_DIR="/var/lib/mydns"
STATE_FILE="$STATE_DIR/oldip"
LOCK_FILE="/run/mydns-updater.lock"
IP_SOURCES=(
"https://api.ipify.org"
"https://ifconfig.me/ip"
"https://inet-ip.info" # 通らない場合あり → フォールバックでカバー
"http://globalip.me"
"http://kakunin.teraren.com"
)
#=== 初期化 ===#
mkdir -p "$STATE_DIR"
[ -f "$STATE_FILE" ] || echo "0.0.0.0" > "$STATE_FILE"
#=== ロック ===#
exec 9>"$LOCK_FILE"
flock -n 9 || { echo "別プロセスが実行中のため終了"; exit 0; }
#=== IPv4判定(簡易) ===#
is_ipv4() {
[[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]
}
#=== IP取得 ===#
get_public_ip() {
for url in "${IP_SOURCES[@]}"; do
ip="$(curl -4sSf "$url" || true)"
ip="${ip//$'\r'/}"; ip="${ip//$'\n'/}"
if is_ipv4 "$ip"; then
echo "$ip"; return 0
fi
done
return 1
}
CURRENT_IP="$(get_public_ip || true)"
if [ -z "${CURRENT_IP:-}" ]; then
echo "IP取得に失敗しました"; exit 1
fi
OLD_IP="$(cat "$STATE_FILE")"
if [ "$CURRENT_IP" != "$OLD_IP" ]; then
# MyDNSへHTTPSでログイン(更新トリガ)
curl -4sSfu "${MYDNS_ACCOUNT}:${MYDNS_PASSWORD}" "https://www.mydns.jp/login.html" >/dev/null
# 原子的更新
tmp="$(mktemp)"
echo "$CURRENT_IP" > "$tmp"
mv "$tmp" "$STATE_FILE"
echo "$(date +'%F %T') MyDNS更新: $OLD_IP -> $CURRENT_IP"
else
echo "$(date +'%F %T') 変更なし: $CURRENT_IP"
fi
使い方(例)
# 一時的に環境変数で注入して実行
MYDNS_ACCOUNT="mydns_account" \
MYDNS_PASSWORD="secret_password" \
/usr/local/sbin/mydns-updater.sh
さらに安全にするなら、
~/.netrc(600権限)+curl -n利用も検討してください。
定期実行の設定
1) cronで1分おきに実行(/etc/cron.d)
sudo tee /etc/cron.d/mydns-updater >/dev/null <<'EOF'
* * * * * root MYDNS_ACCOUNT=mydns_account MYDNS_PASSWORD=secret_password /usr/local/sbin/mydns-updater.sh >> /var/log/mydns-updater.log 2>&1
EOF
いただいた例のように
run-partsを使う場合は、以下のようにスクリプトを配置します。
# 例:/etc/cron.1time を毎分実行
# (/etc/crontab に既に)
# */1 * * * * root run-parts /etc/cron.1time
sudo install -m 0755 /usr/local/sbin/mydns-updater.sh /etc/cron.1time/mydns-updater
2) systemdタイマー(安定運用向け)
# /etc/systemd/system/mydns-updater.service
[Unit]
Description=MyDNS updater
[Service]
Type=oneshot
Environment=MYDNS_ACCOUNT=mydns_account
Environment=MYDNS_PASSWORD=secret_password
ExecStart=/usr/local/sbin/mydns-updater.sh
# /etc/systemd/system/mydns-updater.timer
[Unit]
Description=Run MyDNS updater every minute
[Timer]
OnUnitActiveSec=60s
AccuracySec=10s
Unit=mydns-updater.service
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now mydns-updater.timer
sudo systemctl status mydns-updater.timer
動作確認
- スクリプトを手動実行してエラーがないか確認
STATE_FILE(例:/var/lib/mydns/oldip)のIPが更新されるか確認- 実際にMyDNSのホスト名へ名前解決して、新しいIPを引けることを確認
トラブルシュート
- 認証エラー:ID/パスに誤りがないか。環境変数のスコープ(cronやsystemd)に注意
- IPv6を拾ってしまう:
curl -4を付ける - IP取得に失敗:利用サイトが落ちている可能性 → 複数ソース+リトライで回避
- 多重起動:ロックファイル(
flock)で防止 - 権限エラー:
STATE_FILEを置くディレクトリの所有者/権限を見直し
まとめ(安全運用の要点)
- 認証情報は平文で直書きしない(環境変数、
.netrc、秘密管理) - MyDNSへの更新はHTTPS+Basic認証で
- IP取得は複数ソース+IPv4強制で安定化
- 定期実行はcron か systemd timerで好みを選択
- 公開記事・公開リポジトリに本物の資格情報を書かない(書いてしまったら即変更)
これだけ見とけばシェルマスター
リンク
リンク


コメント