使用 Caddy 給 localhost 設定子網域 | Setup subdomain for localhost with Caddy

最近試了很多開源的專案,像是 n8n、comfyUI、flowise、windmill 等等。這類服務在本地端啟動時,通常都會有一組特定的 port,以 n8n 來說,預設的 port 就是 :5678;而 ComfyUI 則是 :8188題外話——上次看到一篇貼文說 :5173 成了最家喻戶曉的 port 號碼,你覺得呢?

正好最近在 X 上看到一則關於 localhost 與子網域的貼文。按照貼文中的使用介紹,可以給 localhost 加上子網域變成這種格式:http://n8n.localhost:5678

這似乎可以解決 port 編號越來越多,有點混亂的問題。當然其實可以直接把這些網址設定為書籤,所以這可能是偽命題。總之基於好奇,我試著了解下實現方式。

修改 hosts 檔案

以下皆以 macOS 為例,最簡單的方式就是修改 /etc/hosts,例如:

127.0.0.1		localhost n8n.localhost
255.255.255.255		broadcasthost
::1		localhost

由於 hosts 檔案並不支援在 address 後面加上 port,實際使用上還是必須給 n8n.localhost 後面加上 port number:http://n8n.localhost:5678

不過既然都設定了 subdomain,目的自然是不想要去記 port number,於是我看到另外一篇來自 2022 年的 X 貼文:https://x.com/wesbos/status/160014579069290086

解決方式很單純,就是反向代理 n8n.localhost127.0.0.1:5678。使用這個做法,可以在不改動 /etc/hosts 的情況下,實現於 Chrome 中輸入 https://n8n.localhost 網址導向 http://127.0.0.1:5678。不過因為 Safari 瀏覽器的限制,這個做法只能作用於 Chrome,如果希望對 Safari 也有效,還是要改動 /etc/hosts,這個細節於後面會說明。

Caddy 反向代理

接下來更多是 Caddy 在 macOS 上的踩坑與使用說明,以下都預設 n8n 已經被啟動,並且使用預設的 :5678 port number。

  1. 安裝 Caddy,可以直接使用 homebrew 安裝:

    brew install caddy
  2. 安裝完畢之後,使用以下指令就可以實現反向代理:

    caddy reverse-proxy --from n8n.localhost:443 --to 127.0.0.1:5678

    接著用「Chrome 瀏覽器」打開這個網址,應該就能成功導向 n8n: https://n8n.localhost

    :443 在這裡設定 443 是為了 https。另外過程中可能會跳出需要輸入系統密碼的提示,這是為了在 macOS KeyChain 裡面設定信任 localhost 憑證。如果跳過的話,在瀏覽器輸入 https://n8n.localhost 的時候,會跳出「不安全」的警告。

  3. 可以寫一個 Caddyfile(Caddyfile 這個名稱雖然可以)放在「下指令」的目錄,假設終端機預設在 ~/ 目錄,那就在該目錄放置名稱為 Caddyfile 的檔案(這個檔案名稱雖然是可以自己指定的,但是不建議,因為有很多指令都會預設尋找這個檔案,如果改變名稱的話,會讓指令變得繁瑣)

    n8n.localhost:443 {
    	reverse_proxy 127.0.0.1:5678
    }

    接著在該目錄,直接執行 caddy run,就可以得到相同的效果。caddy 還有一個 start 指令,會讓 caddy 在背景運行,並且可以透過 stop 來停止。

Caddy 開機自動啟動

其實到以上就算實現需求了,再來是關於自動啟動,有些細節要注意。

為了讓 caddy 在開機時自動啟動,可用這個指令: brew services start caddy。但是第一次啟動的時候通常會有錯誤,當我們接著再使用 brew services 查看 services 狀態的時候,會發現 caddy 啟動失敗了。

原因是因為 brew services start caddy 預設會尋找 /opt/homebrew/etc/Caddyfile 檔案。但是這個檔案需要自行新增,可以使用跟剛才一樣的檔案內容:

n8n.localhost:443 {
	reverse_proxy 127.0.0.1:5678
}

此時再重新啟動 caddy 服務,應該就能看到 service 正常運作: brew services restart caddy

還有一個可以注意的點,是關於前面提到這句:

過程中可能會跳出需要輸入系統密碼的提示,這是為了在 macOS KeyChain 裡面設定信任 localhost 憑證。如果跳過的話,在瀏覽器輸入 https://n8n.localhost 的時候,會跳出「不安全」的警告。

這個過程設定的憑證,其實跟 brew services 啟動 caddy 時使用的憑證是不一樣的,所以可能會發生「caddy run 代理的 n8n.localhost 正常,但是使用 brew services 時,瀏覽器會跳出不安全」的情況。由於使用 brew services start caddy 時,不會出現設定憑證的提示,所以需要手動新增到 KeyChain 裡面。

這個檔案放在 /opt/homebrew/var/lib/caddy/pki/authorities/local/root.crt,打開該檔案會自動跳轉到 KeyChian 應用程式,並且新增名為 Caddy Local Authority 憑證。在 KeyChain 雙擊點開該憑證,將「信任 > 使用此憑證時」改為永遠信任,就可以避免自己的瀏覽器跳出不安全警告。

Safari 無法使用?

實際上依照規範 hosts 本來就是不支援 wildcards 的 (*.localhost) ,之所以 Chrome 可以打開 n8n.localhost 是因為它有針對 localhost 網域做特別處理,而沒有另外特別處理的 Safari 自然是打不開 n8n.localhost 這個路徑。

為了要讓 Safari 可以把 n8n.localhost 導向到 127.0.0.1 這個 IP,還是要回去調整 hosts 檔案,將 n8n.localhost 加入到 127.0.0.1 的映射清單中。