一般家用的ADSL最多都只能搭配一組固定IP,如果想要再多一個網域來架設網站的話,那第二組網域就只能使用浮動IP了。但一般購買網域時,在網域供應商的管理網站中,也只能用手動的方式去設定你的網域所要對應的Public IP,這組Public IP如果是固定的就還好,只要設定一次就好。但如果是浮動的,總不可能定期來去查看及手動更新吧。
於是就用AI查找了一下,發現有部份的網域供應商是有提供API的功能,讓你能透過呼叫API的方式來更新網域的IP。而Cloudflare就是其中一家支援API更新網域的供應商之一。為了測試利用浮動IP配合網域來架站的想法,於是就在cloudflare上找了一個想要的域名,看看價格也還可以接受,就下單買了一組域名,開始進行相關的測試。
以下就來記錄一下這次測試的經驗,供自己及他人參考。
購買網域
這部份比較單純,直接在Cloudflare上註冊及登入後,輸入你想要的網域名稱,cloudflare便會列出可使用的建議項目,找好目標,付費後就可以開始管理你的網域了。
網域DNS基本設定
因為我們是要透過cloudflare的API功能來自動更新網域的Public IP,跟其它API使用方式類似,都是要去設定一組Token(有點像是密碼的概念)來搭配使用cloudflare 的API來進行自動化管理。
準備API
如果直接參考cloudflare API的說明文件,就會看到要更新DNS中某一筆記錄時基本上就需要三個參考:
$ZONE_ID : 指的就是你的網域(因為每個人可能同時可以購買多組網域,所以需要取得你要管理的網域的ID)
$DNS_RECORD_ID : 你要更改的那筆DNS記錄的ID
$CLOUDFLARE_API_TOKEN : 你的API Token
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$DNS_RECORD_ID \
-X PATCH \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-d '{
"name": "example.com",
"ttl": 3600,
"type": "A",
"comment": "Domain verification record",
"content": "198.51.100.4",
"private_routing": true,
"proxied": true
}'
取得ZONE_ID的方式,主要就是到Cloudflare的管理頁面中,可在右下角的部份找到相關資訊。你會看到「區域識別碼」這個資訊,這就是你的ZONE_ID。
在「區域識別碼」的下方就有一個「取得您的API Token」的連結,進入後就可設定API Token。
右上方有「建立Token」,進入後,你可以自行設定,或是使用範本。以下就會用使用「編輯區域DNS」的範本來說明。
在「建立Token」的頁面中,唯一要設定的就是在「區域資源」這裏最右邊的下拉選單中,選取你要管理的網域名稱。其它可保留不用設定,最後按下下方的建立,之後會出現一個畫面,這個畫面中有你所需要的Token,請將它複製及保存好,因為它只會顯示這一次,之後就再也無法查到了。
至於DNS_RECORE_ID就要花點小心思了,因為在Cloudflare的管理頁面中無法直接查到這項資訊,為了要先測試更新的功能,我這邊會建議你可以用找到的ZONE_ID及Token,用查詢DNS Records的API來先列出你目前所有的DNS Records,直接由傳回的資料中來查找你所需要的DNS_RECORD_ID。
查找所有DNS Record一樣可參考API文件,找到後可以先在你的電腦中執行以下的API呼叫,不過,要記得將其中的參數替換成剛剛查找到的資訊。順利的話,應該就會由傳回的資料中(它會是一份Json格式)找到你要的DNS_RECORD_ID了。
curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"
找到DNS_RECORD_ID後,你也可以利用更新DNS Record的API也測試一下是否能正常更新。測試完後,接著就是要想辦法讓它能自動化了。
編寫自動化更新腳本
如果你有一台Linux的電腦,或是NAS,你應該就可以寫一份bash shell來設定排程,以便定時取得目前的浮動IP並呼叫更新DNS Record。因為大家的環境可能不同,我這邊的主要是使用NAS,而NAS可以透過ADSL撥號的方式來建立一組PPOE的IP。就看大家自己的環境不同,先想好概念後,接下來就是要準備自動化更新腳本了。
當然目前應該不用自己來寫,只要善用AI的工具,準備好相關的prompt,AI就能幫你完成這份自動化腳本。以下這份是我的範本,先供大家參考:
#!/bin/sh
# --- 設定區域 ---
API_TOKEN=""
ZONE_ID=""
RECORD_NAME=""
INTERFACE="ppp0"
RECORD_ID=""
LOG_FILE="/var/log/updateip.log"
# ---------------
# 重定向所有輸出到日誌檔案
exec >> "$LOG_FILE" 2>&1
# 1. 獲取本地 PPPoE IP
CURRENT_IP=$(ip addr show $INTERFACE | grep "inet " | awk '{print $2}' | cut -d/ -f1)
if [ -z "$CURRENT_IP" ]; then
echo "$(date '+%Y%m%d %H:%M:%S') 錯誤:無法從 $INTERFACE 獲取 IP。"
exit 1
fi
# 2. 獲取該 Zone 下的所有 DNS 紀錄 (不使用過濾參數)
# 預設每頁顯示 20 筆,若你的紀錄超過 20 筆可加上 &per_page=100
RESPONSE=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?per_page=100" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json")
#echo $RESPONSE
# 3. 使用 Python 解析 JSON 並過濾名稱與類型
# 這段指令會找出名稱符合且類型為 A 的紀錄,並輸出成 ID|IP|PROXIED 格式
READ_DATA=$(echo "$RESPONSE" | python3 -c "
import sys, json
try:
data = json.load(sys.stdin)
for r in data.get('result', []):
if r['name'] == '$RECORD_NAME' and r['type'] == 'A':
print(f\"{r['id']}|{r['content']}|{str(r['proxied']).lower()}\")
break
except Exception:
pass
")
if [ -z "$READ_DATA" ]; then
echo "$(date '+%Y%m%d %H:%M:%S') 錯誤:找不到符合 $RECORD_NAME 的 A 紀錄。"
exit 1
fi
# 分解提取出的資訊
RECORD_ID=$(echo "$READ_DATA" | cut -d'|' -f1)
OLD_IP=$(echo "$READ_DATA" | cut -d'|' -f2)
PROXIED=$(echo "$READ_DATA" | cut -d'|' -f3)
# 4. 檢查 IP 是否變動
if [ "$CURRENT_IP" = "$OLD_IP" ]; then
echo "$(date '+%Y%m%d %H:%M:%S') IP 未變動 ($CURRENT_IP),跳過更新。"
exit 0
fi
# 5. 執行更新
echo "$(date '+%Y%m%d %H:%M:%S') 偵測到變動,準備更新 $RECORD_NAME:$OLD_IP -> $CURRENT_IP"
UPDATE_RESPONSE=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
--data "{\"type\":\"A\",\"name\":\"$RECORD_NAME\",\"content\":\"$CURRENT_IP\",\"ttl\":120,\"proxied\":$PROXIED}")
# 使用 Python 檢查更新是否成功
SUCCESS=$(echo "$UPDATE_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin).get('success', False))")
if [ "$SUCCESS" == "True" ]; then
echo "$(date '+%Y%m%d %H:%M:%S') 更新成功!目前 IP 為 $CURRENT_IP"
else
echo "$(date '+%Y%m%d %H:%M:%S') 更新失敗。完整回應:$UPDATE_RESPONSE"
fi
自動化更新腳本測試完成後,接著就是在你合適的環境中設定相關的排程讓它能定時執行就好了。這樣就可以固定時間查看Public IP是否有變更,有的話就去更新DNS Record。
