自建 GeoDNS 伺服器

前言廢話

自從第一次使用過 Amazon Cloudfront 後,就發現他的 DNS 是使用 GeoDNS,與一般如 Cloudflare Anycast 的不同,這種 GeoDNS 會依照用戶的地理位置來響應不同的 IP 位址。

我個人認為這個東西的用途非常廣泛,舉例遊戲來說,可以針對不同國家、ASN 的用戶,將其指向不同節點或是代理伺服器,進而增加網路品質。

不過市面上可以用到的 GeoDNS 幾乎都是付費方案,就算想體驗玩玩也不符合效益。因此,就讓我找到了 Github 上的 這個 項目。

成本

這篇文章介紹的工具,你在哪邊都能架,但不代表完全沒有成本。自架意味者你需要擔心要不要租伺服器、自動擴充、負載平衡、會不會被攻擊、備份及自行維護等等問題。此篇高度建議你對 DNS 已經有一定知識的人再來玩玩,初心者請繞道。

準備環境

更新系統。

sudo apt-get -y update

操作過程中,我們需要 wget、git、vim。

sudo apt-get install wget git vim

由於他是使用 golang 寫的,我們必須要先準備 golang,你可以參考以下又或是 官方最新版本的教學

sudo wget https://go.dev/dl/go1.20.5.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.5.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
go version

安裝 GeoDNS

由於我喜歡放在 /var,所以我們在該目錄開始操作。

cd /var

接著操作 git 取得檔案並 build。

git clone https://github.com/abh/geodns.git
cd geodns
go build

取得 GeoIP 資料

既然我們是使用 GeoDNS,我們當然也要每個 IP 位址的 國家、城市、ASN 囉!

這個 GeoDNS 使用 MaxMind 的 IP 資料庫,取得方式你可以到 這裡 查看,這裡就不多贅述。

檔案應為 .mmdb 的副檔名,請將下載完的資料放到 /usr/local/share/GeoIP/,資料夾若不存在請自行建立。

如果你對他完全沒概念,你對這些可能真的還沒有基礎,請繞道。

編輯 DNS 紀錄

/var/geodns/dns 底下,我們先處理 geodns.conf.sample 這個檔案,基本上內容不用改動,直接將他重新命名為 geodns.conf 即可。

sudo mv geodns.conf.sample geodns.conf

接著,我們需要建立一個檔案,檔名取決於你的網域名稱,假設說你想使用 geo.example.com 這個域名,則建立 geo.example.com.json 檔案。

sudo vim geo.example.com.json

內容大概如下:

{
    "serial": 3,
    "ttl": 10,
    "targeting": "country continent @ regiongroup region ip asn",
    "data": {
        "": {
            "ns": {"geo.example.com": null}
        },
        "test": {
            "a": [["1.1.1.1"]]
        },
        "test.tw": {"a": [["2.2.2.2"]]},
        "test.as3462": {"a": [["3.3.3.3"]]},
        "test.europe": {"a": [["4.4.4.4"]]},
        "test.[192.168.0.1]": {"a": [["5.5.5.5"]]}
    }
}

上述的文件基本上意思是:

test.geo.example.com 的預設回應 IP 為 1.1.1.1

當來源的國家為 tw,則回應 2.2.2.2

當來源的 ASN 是 as3462,則回應 3.3.3.3

當來源的地區為 europe (歐洲地區),則回應 4.4.4.4

當來源的 IP 為 192.168.0.1,則回應 5.5.5.5

這是一些基本的使用,詳細設定你可以到 Github 上了解。

建立服務

接著,我們將他打包成一個服務,我們在 /lib/systemd/system 建立 geodns.service 檔案。

sudo vim /lib/systemd/system/geodns.service

內容如下:

[Unit]
Description=GeoDNS
After=multi-user.target

[Service]
Type=simple
WorkingDirectory=/var/geodns
ExecStart=/var/geodns/geodns -port 53
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

存檔後退出,輸入以下指令讓服務生效。

sudo systemctl daemon-reload

現在你可以使用以下命令來控制這個服務。

sudo systemctl start geodns.service    #啟動服務
sudo systemctl restart geodns.service  #重新啟動服務
sudo systemctl stop geodns.service     #停止服務
sudo systemctl enable geodns.service   #開機自動執行此服務
sudo systemctl disable geodns.service  #開機不執行此服務

後續步驟

你需要將你的網域使用 NS 紀錄指向這台主機,來解析網域。

一樣,我在這裡不多介紹,因為他是對 DNS 維護非常基本的操作。

接著可以透過 ping.sx 測試你的結果囉!

結語

這就是一個簡易的 GeoDNS 架設。說真的,作為 Nameserver 主機,你需要注意非常多事情,例如最好支援 IPv6。

GeoDNS 非常仰賴 EDNS 或是 ECS 這些東西,所以用戶使用的公共 DNS 也必須要支援,才能使其正確解析。像是 8.8.8.8 就能解析的非常好,而不支援 EDNS 的 1.1.1.1 則解析的非常糟糕。