透過 Cloudflare API 實現 Cloudflare DDNS
本文教學在 Linux 下如何透過免費的 Cloudflare DNS 服務組合 Cloudflare API 實現 Cloudflare DDNS 的效果,如果伺服器可能會有動態的網路位置 (比如 PPPoE 連線) 就可以透過定時更新 DNS IP 來達到動態網址對應的效果,同時也附上 Cron Shell Script 動態更新程式碼,只要透過 Linux Cron 執行 Script 就可以自動更新 Server DNS 對應的 IP 了。讓需要 PPPoE 撥接上網的浮動 IP 也可以方便地管理主機位置。
什麽是 DDNS 動態域名系統?
DDNS (Dynamic Domain Name System) 中文為動態域名系統,是指一種讓使用者可以透過一個固定的域名來連接到一個網路裝置的服務。
傳統的 DNS 系統會將域名解析成一個固定的 IP 位址,當該網路裝置的 IP 位址變動時,使用者就無法透過原本的域名連接到該網路裝置。而使用 DDNS 服務,可以讓該網路裝置透過定期更新 DNS 記錄,來確保該域名始終對應到該網路裝置的最新 IP 位址,讓使用者可以繼續透過該域名來連接到該網路裝置。這對於需要透過動態 IP 位址的網路裝置,如家用路由器、IP 監控攝影機等,非常有用。
由於我們透過 Cloudflare API 實作了 DDNS 的效果,所以也就稱為 Cloudflare DNS。
Cloudflare DNS 是什麽樣的服務?
Cloudflare DNS 是一種由 Cloudflare 提供的 DNS 服務,它是一個快速、安全且免費的網際網路解析服務。使用 Cloudflare DNS 的好處之一是它的快速性能,因為 Cloudflare 具有分布式的全球節點,可以更快地解析域名,加快網站載入速度,改善用戶體驗。此外,Cloudflare DNS 支持 DNS over HTTPS (DoH) 和 DNS over TLS (DoT) 協議,可以更安全地保護 DNS 查詢的隱私。
另外,Cloudflare DNS 還提供一些額外的安全功能,例如 DNSSEC(DNS 安全擴展)和 DDoS(分散式拒絕服務攻擊)保護,可保障網站的安全性和穩定性。
使用 Cloudflare DNS 也很容易,只需要將你的 DNS 伺服器設置更改為 Cloudflare DNS 的伺服器位址即可,並且它是完全免費的。總體而言,Cloudflare DNS 提供了更快速、安全、穩定的 DNS 服務,是一個值得推薦的 DNS 解析服務。
申請 Cloudflare Access Token
由於我們會透過 Cloudflare API 來更新 DNS 對應的 A Record,透過最小權限的 Access Token 來呼叫 API 是比較安全的作法。
登入 Cloudflare 進入 My Profile
需要申請 Access Token 首先先登入 Cloudflare,然後進入右上角的「My Profile」功能,如下:
建立 API 專用的 Token
接著選取「API Token」選單後按下「Create Token」按鈕
直接選擇「Edit zone DNS」按下「Use template」套用規則快速建立
設定 Token 的最小權限範圍
由於我們需要透過 API 更新 DNS Record,因此在這裡我們需要指定 Permissions 為 DNS Edit。為了實現「最小權限原則」讓系統更安全,我們需要在 Zone Resources 指定 Include Specific zone 表示這個 Token 只能對指定的 Domain 進行修改。
我原本來想要將權限縮小到指定某一個 Record 但是目前 Free Plan 沒有這樣的功能,只好放棄。完成設定以後按下「Continue to summary」
最後確認一下 Token 的設定即可按下「Create Token」按鈕
取得與保存 API Token
最後可以按下「Copy」先複製好產生的 Token,Cloudflare 還很貼心的附上測試 CURL Command,可以直接進行 Token 呼叫測試。
Cloudflare API 呼叫測試
最後我們拿上面的 CURL Command 測試一下,如果呼叫成功會收到 Success Json Response,如下:
ACCESS_TOKEN={Your API Token} curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type:application/json" | python -m json.tool
透過 Cloudflare API 取得 ZoneID 與 RecordID
Cloudflare 是遵循 REST API 進行設計 (想了解可以參考「淺談 REST 軟體架構風格」這一篇文章),接下來我們會透過 GET 與 PUT 進行 API 操作。
先透過 API 取得 DNS 的 ZoneID,在 Cloudflare 系統中每一個 Domain 代表一個 Zone,取得 ZoneID 的方法如下:
curl -X GET "https://api.cloudflare.com/client/v4/zones" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type:application/json" | python -m json.tool
上面就是這個 API 權限範圍可以操作的 Zone,一般來說只會有一個 Zone,所以就先記錄一下這裡的 Zone ID,接著透過 ZoneID 取的我們想要編輯的 RecordID,如下:
ZONE_ID={Your Zone ID} curl -X GET "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type:application/json" | python -m json.tool
這裡會列出所有 Zone 底下的 Record List,找到要管理的 Record (DNS) 記錄對應的 Record ID,接下來透過編輯 API 進行操作。
透過 Cloudflare API 更新 DNS IP 位置
上面拿到 Zone ID 與 Record ID 以後接著透過下面的 API 更新資料,如下:
RECORD_ID={Your Record ID} curl -X PUT "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${RECORD_ID}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ --data '{"type":"A","name":"ddns","content":"192.168.1.1","ttl":120,"proxied":false}' \ | python -m json.tool
設計透過 Cloudflare API 自動更新 DNS IP 的 Script
最後來一個組合技寫一個 Shell Script 透過 Crontab 定時執行,就可以把主機的 IP 動態進行更新了,這樣就可以實現全自動 Cloudflare DDNS 的效果。
這裡的程式更新以前會先確認 DNS Server Query 的 IP 是否不同,避免每次執行排程都更新 IP 的問題。Script 如下,同步放在 GitHub 上:
#!/bin/bash CF_TOKEN={YOUR_API_TOKEN} CF_ZONE_ID={YOUR_ZONE_ID} CF_RECORD_ID={YOUR_RECORD_ID} DNS={YOUR_DOMAIN} INTERNET_IP=`curl -s http://ipv4.icanhazip.com` INTERFACE_IP=`ip address show ppp0 | grep ppp0 | grep global | awk '{print$2}'` DNS_RECORD_IP=`dig ${DNS} | grep "${DNS}" | grep -v ';' | awk '{print$5}'` if [ "$INTERNET_IP" != "$DNS_RECORD_IP" ] then echo "Renew IP: ${DNS_RECORD_IP} to ${INTERNET_IP}" curl -X PUT "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/dns_records/${CF_RECORD_ID}" \ -H "Authorization: Bearer ${CF_TOKEN}" \ -H "Content-Type: application/json" \ --data '{"type":"A","name":"'${DNS}'","content":"'${INTERNET_IP}'","ttl":120,"proxied":false}' else echo "No change: ${INTERNET_IP}" fi
這裡是透過 ip address 命令取得 ppp0 進行更新,各位在使用上可能會需要修改一下,有興趣的請自行下載 cf-ip-renew.sh 使用,下次見...