Physical Address

304 North Cardinal St.
Dorchester Center, MA 02124

利用 Cloudflare API v4 建立 DDNS

前幾篇提到透過 No-IP 來建立 DDNS 的做法,來避免被 fail2ban 擋下。後來在阿竣的建議下,研究了 Cloudflare 的作法。透過這種方法,可以讓 DDNS 使用自己的主要域名,而非 No-IP 或其他 DDNS 服務的子域名。

在網路上搜尋「DDNS Cloudflare」後,找到了網友分享的操作方式。以下內容都是根據他的說明進行延伸。

系統環境

  • macOS 10.15.2
  • 終端機環境 iTerm2 3.1.6
  • Cloudflare API v4

步驟一:建立一個子網域

首先,先前往 Cloudflare,建立一個用來作為 DDNS 用的 A 紀錄。以這次的例子,我建立了一個 ddns.huanyichuang.com 的子網域紀錄。

步驟二:取得所需的 Zone ID、API Token 與 Record ID

原文所使用的方法是利用 Global API Key 來進行,但基於安全考量,這篇文章會使用 API 存取權杖的方式,給予特定的 Zone 所需權限。

取得 Zone ID

首先,先到 Overview 分頁取得網域紀錄的 Zone ID。

取得存取權杖

接著,在同一頁下方點選 [Get your API Token],開始建立新的 API 存取權杖。

進到 API Tokens 的頁面後,按下 Create Token 以建立新權杖。

在權限部分,由於我們只需要修改 DNS 的權限,因此我們只要點選 [Start with a template],選擇 [Edit zone DNS],系統便會自動帶入預設的權限「Zone 層級、修改 (Edit) DNS 的權限」。接著,在 Zone Resources 的地方,指定特定的網域資源後,就能夠產生存取權杖。

取得 ddns.huanyichuang.com 的 Record ID

將存取權杖記下來後,我們接著要找到特定網域紀錄的 Record ID。這個步驟可以直接透過終端機執行,不需要另外寫成 Shell 檔案。

#!/bin/sh
ZONE_ID="你的 Zone ID"
API_TOKEN="剛才產生的存取權杖"
curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
     -H "Authorization: Bearer '$API_TOKEN'" \
     -H "Content-Type: application/json"

執行上述指令後,會回傳 JSON 格式的查詢結果,找到 “name” 與目標相符的紀錄。

步驟三:建立 Shell 指令碼並加以排程

得到 Zone ID、API Token 跟 Record ID 後,接著就用任何文字編輯器建立 Shell 的指令碼檔案。

#!/bin/sh
NEW_IP=`curl -s http://ipv4.icanhazip.com`
CURRENT_IP=`cat ~/tmp/current_ip.txt`
CURRENT_TIME=$(date +"%F %T")
DDNS="ddns.huanyichuang.com"
ZONE_ID="{{步驟二第一段取得的 Zone ID}}"
API_TOKEN="{{步驟二第二段取得的 API Token}}"
RECORD_ID="{{步驟二第三段取得的 Record ID}}"
if [ "$NEW_IP" = "$CURRENT_IP" ]
then
        echo "[$CURRENT_TIME] No Change in IP Adddress" >> ~/tmp/crontab_log.txt
else
curl -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":"'$DDNS'","content":"'$NEW_IP'","ttl":1,"proxied":false}' > /dev/null
echo $NEW_IP > ~/tmp/current_ip.txt
echo "[$CURRENT_TIME] IP changed to $NEW_IP" >> ~/tmp/crontab_log.txt
fi

這支程式會先從 icanhazip 的網站取得現在裝置的 IP,與之前用來暫存 IP 位置的檔案 ~/tmp/current_ip.txt 進行比對,如果兩組 IP 一樣,就不需要執行後續程式。如果偵測到 IP 位置改變,就會自動將新 IP 同步到 Cloudflare 上的網域紀錄中。

另外,根據網友的實測,TTL 的單位是「秒」,因此如果寫 1 的話,會變成自動 (從 Cloudflare 後台看,目前預設最小的值是 60 秒)。

將檔案儲存 (以我自己為例,~/bin/ddns.sh) 後,接著在終端機中輸入 crontab -e 編輯排程。在 macOS 的環境下執行,需要再 Shell 檔案前加上 bash 的指令,才會生效。以下是以「每五分鐘檢查一次」為例。

*/5 * * * * bash ~/bin/ddns.sh

後記

學習 DDNS 最早是希望能透過 FileZilla 用來存取 fail2ban 所保護的檔案,避免把自己給封鎖。但是網路上看到的 DDNS 應用通常是結合 NAS 系統,讓自己可以更容易連上家中的 NAS 系統,而不需要背 IP。

目前這個程式的寫法並不聰明,很多資料都還是要先透過 Cloudflare 的介面取得。有空的時候再把取得 Record ID 的步驟自動化好了。

Eric Chuang
Eric Chuang

正職是廣告行銷人員,因為 Google Tag Manager 的關係開始踏入網站製作的領域,進一步把 WordPress 當成 PHP + HTML + CSS + JavaScript 的學習教材。此外,因為工作的關係,曾經用 Automattic 的 Underscores (_s) 替客戶與公司官網進行全客製化佈景主題開發。

4 則留言

  1. 你好, 非常感謝您的文章, 實際測試時發現一個小問題, 更新DNS時傳入的屬姓
    “ttl”:1
    這邊的單位實際上是秒, 而非分鐘
    如果傳入 1 的話, 會導致 TTL 自動跳成 “自動”
    而非 1 分鐘

    以上提供修正

  2. […] 文章參考來源:利用 Cloudflare API v4 建立 DDNS – 桓桓鄉寇 (huanyichuang.com)主要補充了 Record ID 直接透過指令過濾出來,連貫運行接下來的 IP 修改作法同樣是抓出該域名下所有 DNS 紀錄,再針對要修改的域名 ,利用 jq 取得 Record IDjq 需事先安裝好,用法可以參考這邊:Shell:jq 循环 json 对象, jq 循环 json 数组 […]

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料