之前有寫到一篇介紹 Surge 根據 WiFi 環境變化來自動選擇使用 DNS Server 的文章

每次域名查詢都要去跑一次 Script,先不論有無額外效能損耗,這樣似乎有點不太優雅

前兩天在 Surge 支援論壇裡面,看到某大神寫的一段範例,剛好可以完美解決這個自動切換 DNS 需求

Surge 只有在網路發生變化的時候才會觸發一次,並根據環境自動將 DoH 啟用或者關閉,非常不錯

所以就稍微拿來改一下,用了幾天沒出現什麼問題,就順便在此篇分享並記錄下來

先說一下我自己的需求,我在家中以及常待的辦公室都有自建 AdGuard Home 在 WiFi 局域網內

所以在認識的 WiFi SSID 下的時候,就用 DHCP Server 指定的 AdGuard Home 即可

只有外出使用行動網路或者不認識 WiFi 時候會需要自動切換啟用 NextDNS DoH 服務

清楚明白自己需求後,就可以開始實作了 😚

👆 Surge 的 DNS 設定改成預設,DoH 留空白不填

接著新建一個本機模組,可以啟用 / 關閉 NextDNS DoH 的模組

Surge App -> 模組 -> 建立本機模組,模組內容如下:

1
2
3
4
5
#!name=NextDNS
#!desc=啟用 DoH 加密解析

[General]
doh-server = https://apple.dns.nextdns.io/########

以上第 5 行 ## 部分請自己改成自己的 NextDNS ID,如果你不是用 NextDNS 也可以改成其他 DoH 網址

新加好以後會如下圖

這邊設定好以後,可以先自己手動測試看看模組有沒有正常工作

試著啟用模組跟關閉模組,確認有沒有正確切換到 DoH 與系統預設 DNS,如無問題就可以繼續往下設定

接下來到 Surge 的腳本編輯器,新建一個 autodns.js,內容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const dns_module = "NextDNS";
const http_api = "localhost:6996";
const http_api_key = "SomeCoolKey996";

let request = {
  url: `http://${http_api}/v1/modules`,
  headers: {"X-Key": http_api_key},
  body: {},
}


getModuleStatus(dns_module).then(main)


function main(enable) {
  let home = ($network.wifi.ssid == 'SSID1' || $network.wifi.ssid == 'SSID2');
  if (home && enable) {
	//在家,卻啟用 NextDNS => 關閉
	$notification.post("關閉 NextDNS","","")
	enableModule(false);
  } else if (!home && !enable){
	//不在家,卻沒啟用 NextDNS => 開啟
	$notification.post("啟用 NextDNS","","")
	enableModule(true);
  } else {
	//重複觸發 => 結束
	//$notification.post("重複觸發","","")
	$done();
	}
}

function getModuleStatus(dns_module) {
  return new Promise(resolve => {
	$httpClient.get(request, (error, response, data) => {
	  let enabled = JSON.parse(data).enabled;
	  resolve(enabled.includes(dns_module));
	});
  });
}

function enableModule(enable) {
  request.body[dns_module] = enable;
  $httpClient.post(request, () => $done());
}

如上第 16 行的 SSID1、SSID2 部分請自行新增或者刪減、修改

第 2、3 行的 API Port 與 API Key 也可以依照你自己的設定修改

第 1 行的 NextDNS 名稱需要跟上面 DoH 模組的第一行名稱對應

修改保存好以後,到 Surge -> 進階設定 -> HTTP API,打開並修改成上面 2、3 行對應的設定值

最後在 Surge 設定檔裡面 Script 區域加入一行

[Script]
AutoDNS = type=event,event-name=network-changed,script-path=autodns.js

以上設定完畢後,每當 Surge 偵測到有網路變化時候,例如 WiFi 斷線切換到行動網路之類的

就會自動執行一次 autodns.js 的腳本,這個腳本可以根據 SSID 來決定要不要打開或者關閉 DoH 模組

👆 切換 DoH 的時候會有通知提醒

使用的是 Surge HTTP API 來控制模組的開關,在 Surge 官方推出自動 DNS 切換功能以前,這個方案基本上完美解決我的需求 🖖