Apple TV 的網路任意門
TL;DR
因為我覺得比較有用的內容開始之前有一大段廢話,所以就先寫把總結放在前面。總之就是為了避免家裡的 IoT 裝置因為 Apple TV 連了 VPN 服務造成 Apple Home Hub 斷線,用了一個 Linux VM 當 NordVPN gateway + 用 UniFI 的 Policy Based Routing + Shortcuts 透過 SSH 下指令到 Linux VM 切換 VPN egress 國家來解決。讓 Apple TV 直接有一個可以隨時用手機控制的網路任意門。(直接跳到解決方法)
故事的開始
現在 streaming service 這麼多,大部分的服務其實都會按照使用者的地區來提供不同的節目內容 (大概就是什麼版權啊之類的問題),相信應該不少人都知道可以使用 VPN 來讓自己看起來像是在某個特定地區來解鎖更多的內容吧。 (就算沒再用肯定也要知道吧,各大網紅的鯊魚業配密度之高,很多人都覺得 VPN 只是拿來看影片用的而已 🤔)
長期 Apple TV 的使用者應該都知道,其實以前要在 Apple TV 上面使用 VPN 可是很麻煩的。因為 tvOS 並不支援 VPN app,所以大家肯定是要透過各種其他的方式轉個彎來使用,像是在自己的 router 設定 VPN 然後讓 Apple TV 透過那個 router 連上網之類的,其實現在在網路上應該都還是可以找到一些以前寫的各種教大家如何讓 Apple TV 使用 VPN 的怪招。

不過就在 tvOS 17 推出之後,Apple TV 正式支援 VPN 了,各家 VPN provider 也紛紛推出 tvOS 的 App,看起來在 Apple TV 上面使用 VPN 的問題應該就解決了吧 🎉 我那時候的確也是這樣想的,所以第一時間手刀下載了 NordVPN,用起來的確很爽,終於可以在電視上用遙控器跳到任意國家了!F1 TV 看起來更舒服了,車子也跑得更快了!😏

原來 Apple TV 還是 Home Hub 啊
就在一切看起來都很順利的時候突然 Apple Home 的通知跳出來說家裡前門的攝影機離線了,過了一會又有其他東西離線了。突然之間整個 Apple Home 裡面的很多裝置都無法回應了 😱 就在我想著為什麼會這樣的時候,「該不會是連了 VPN 造成的吧」這個想法突然出現。啊!對啦!我的 Apple TV 是 Home Hub 啊。

就這樣,只要我看 F1 的時候,我家很多裝置就會變智障 🤔,經過被家人抱怨幾次後,覺得還是要好好的解決這件事情。有過蠻多想法的:
- 買一台獨立的 Apple TV 專門拿來當作 Home Hub,這樣看電視的 Apple TV 就要連什麼都可以了 – 太奢華了 🫣
- 使用 DHCP option 來設定 static route 來避免 default gateway 被 VPN 改掉後會斷線 – 試過了似乎沒用,我覺得他應該是直接把整個 routing table reset 之後只留下 default gateway。所以就只剩下相同 subnet 的會通而已。
- 使用 UniFi gateway 直接連上 VPN,然後建立一個獨立的網路 + Policy Based Routing 讓那個網路出去的裝置都從那個 VPN 連出去 + 一個獨立的 Wi-Fi SSID – 可以很方便的切換要不要使用 VPN,但是要切換不同地區的時候神麻煩,主要的還是因為 NordVPN 使用的 WireGuard 設定檔要自己生 🤨
其實上面提到的第 3 個我還真的就這樣用了 1 年多的時間,其實大部分的時候我只有要跳去美國 🇺🇸 的需求而已,所以其實還算是不錯用。而且如果忘記切回來,直接看 Apple TV 當下連著哪個 Wi-Fi 也很直覺。不過隨著想看的內容越來越多,需要跳的國家也就越來越多了 (英國的 ITV,澳洲的 9Now 看網球)。然後再加上其實同一個 server 有時候也會突然變成爛線,這時候要換個 server 也是很麻煩的,基本上只要換 server 就要重新產生一次 WireGuard 設定。
越來越不方便之後,就開始思考,到底有沒有什麼方法是可以快速開關 VPN 而且還可以很方便的重抽 server 或者改變國家,最好是可以一個地方就完成操作,然後最好可以用最少的步驟就完成,然後...
解決方案
花了一點時間兜出了上面 demo 的這個解決方案,操作起來蠻簡單的。已經用了差不多半個月了大致上還算好用。功能大致上有:
- 連線:可以選擇國家,也可以選擇特定城市連線。連線選單最上面還留著最近連過的 3 個國家/城市來方便快速選擇或者重抽 server。
- 斷線:就斷線。
- 狀態:顯示目前連線狀態,包括連到哪個國家、IP、傳輸量之類的。
用到了下面這些東西:
- Linux VM – NordVPN Linux client 就跑在這個上面,負責連線到 NordVPN 跟把 Apple TV 的 egress traffic route 出去。VM 是使用 Proxmox VE 建的,Homelabber 必備。
- UniFI Cloud Gateway Fiber – 家裡實際上的網路 router。搭配 UniFi Network 裡面的 Policy Based Routing 功能就可以把特定 client 的所有 traffic 倒去特定的 WAN link 或者 VPN。很多 router 應該都有類似功能,只是身為 UniFI 信徒,網路 infra 的唯一選擇。
- 捷徑 Shortcuts App – iOS 裡面拿來做各種奇怪小工具的超好用 no/low code 工具。這次整個 UI 都直接用這個做。
使用的流程大致就是:
- 執行用 Shortcuts 做的 Apple TV VPN Control workflow。
- Workflow 會 present 一個 menu 讓我選要幹嘛。
- 連線,斷線,跟狀態其實就對應到 NordVPN Linux client 的 3 個 command。
- 如果選擇連線的話,會使用 NordVPN client 取得國家跟城市的清單,然後一樣讓 Shortcuts 用 menu 吐出來。
- 用 Actions 這個 Shortcuts 工具箱把最近選過的地區存起來,下次可以快速使用。
- 拿到全部的 parameter 之後,直接用 Run script over SSH 這個 action 來操作 Linux VM 裡面跑的 NordVPN client。
那接下來就稍微簡單說明一下整個東西怎麼設定起來吧!
設定
先來講一下整體的架構規劃好了,我們的 Linux VM 其實就是一個 VPN gateway,把所有進來的流量用 VPN 送出去。所以基本上他會有 2 張網卡,一個就是他的 LAN port 一個是他的 WAN port (把他當成一台分享器想比較好懂),兩個 port 要放到不同的 VLAN 裡面把他們完全切開。而我們要把 Apple TV 的流量經過 Linux VM 提供的外網連出去,所以需要把 UniFi Gateway 的 WAN2 port 接到跟 Linux VM 的 LAN port 一樣的 VLAN 上面。最後再用 Policy Based Routing 把 Apple TV 的所有流量用 WAN2 送出去。
接線方式
Gateway
| Port | 裝置 |
|---|---|
| 1 | Switch #8 |
| WAN1 | 光世代 ONT |
| WAN2 | Switch #7 |
Switch
| Port | VLAN | 裝置 |
|---|---|---|
| 1 | Default | Apple TV |
| 2 | Default+VPN | Linux VM |
| 7 | WAN2 | Gateway WAN2 |
| 8 | Default | Gateway #1 |
Linux VM 虛擬網卡
| NIC | VLAN | 用途 |
|---|---|---|
| ens18 | Default | 預設網路 |
| ens19 | WAN2 | 與 WAN2 對接 |
| nordlynx | NordVPN tunnel |
Linux VM
在你的環境裡面準備一個 Linux 環境,我是用 Proxmox 開了一個獨立的 Linux VM,用的 distro 是 Debian 13。注意因為這台 VM 需要當作 NAT gateway,在設定時候建議直接給他 2 張在不同 VLAN 的網卡,我們會把一個當 egress port,另外一個會直接跟 UniFi Gateway 的 WAN port 對接。
安裝 NordVPN Linux Client
首先先來安裝 NordVPN 的 Linux client。在這裡要 huge shout-out to NordVPN 🎉!我其實看了好幾個 VPN provider,就 NordVPN 的 Linux client 有 CLI 的,而且超級 scriptable!直接用下面這行安裝:
sh <(curl -sSf https://downloads.nordcdn.com/apps/linux/install.sh)安裝好了之後應該就有 nordvpn 這個 command 可以用了,可以直接來試試看:
$ nordvpn version
NordVPN Version 4.4.0接下來就要登入你的 NordVPN 帳號了,CLI 的話官方文件是建議使用 token 的方式登入。先登入 Nord Account 後台,然後在 Advanced settings 下面的 Access token 那裡就可以產生一個可以拿來登入使用的 token 了。這裡我直接做了一個不會 expire 的 token 這樣就不用一段時間還要重新再來設定一次。
拿到 token 之後使用下面指令登入 NordVPN:
nordvpn login --token 你的token登入成功的話,應該就可以看看你的 account 狀態了:
$ nordvpn account
Account information
Email address: ********@********.***
Account created: Jul 5, 2020
Subscription: Active until Jul 5, 2026
Dedicated IP: Inactive
Multi-factor authentication (MFA): Turned off這樣 NordVPN 就算是設定完成了。
設定網路和 nftables
再來要設定讓 Linux VM 可以當成 NAT gateway 的部分。首先我們要先確定 IP forwarding 有打開,把下面的內容存在 /etc/sysctl.d/99-ip-forwarding.conf:
net.ipv4.ip_forward=1接著執行下面的指令載入那個設定檔:
sudo sysctl -p /etc/sysctl.d/99-ip-forwarding.conf現在 Linux 主流是使用 nftables 設定 firewall,所以我們可以把下面這個 script 放在 /etc/nftables.conf,記得把 ens18 跟 ens19 替換成你的網卡名稱:
#!/usr/sbin/nft -f
flush ruleset
# Define Interface Variables
define mgmt_if = "ens18"
define unifi_wan_if = "ens19"
define vpn_if = "nordlynx"
table ip global_router {
# Protect the Debian Server itself
chain input {
type filter hook input priority 0; policy drop;
# Basic health and maintenance
ct state established,related accept
iif "lo" accept
ip protocol icmp accept
# TRUSTED MANAGEMENT: Allow all from management NIC
iifname $mgmt_if accept
# OPTIONAL: Allow UniFi to ping its "ISP" (the Debian server)
iifname $unifi_wan_if ip protocol icmp accept
}
# Handle the routing between UniFi and NordVPN
chain forward {
type filter hook forward priority 0; policy drop;
# TCP MSS Clamping: Essential for VPN tunnel stability
oifname $vpn_if tcp flags syn tcp option maxseg size set rt mtu
# ROUTING RULES
# 1. Allow Management NIC to use the VPN
iifname $mgmt_if oifname $vpn_if accept
# 2. Allow UniFi WAN to exit via NordVPN
iifname $unifi_wan_if oifname { $vpn_if, $mgmt_if } accept
# 3. Allow established return traffic from the internet
iifname { $vpn_if, $mgmt_if } ct state established,related accept
}
}
table ip nat_table {
chain postrouting {
type nat hook postrouting priority 100;
# MASQUERADE: Hide UniFi's traffic behind the NordVPN IP address
oifname $vpn_if counter masquerade
# FALLBACK
oifname $mgmt_if counter masquerade
}
}這個 script 的 masquerade 出了做了從 NordVPN 出去的 nordlynx 網卡之外也做了 ens18。這樣如果 NordVPN 斷線的時候,外網也可以正常地從 ens18 不經過 VPN 出去。
接下來就重啟 nftables 套用上面的 script:
sudo systemctl restart nftables也可以用下面的指令確認一下 nftables 的狀態:
$ sudo nft list table ip nat_table
table ip nat_table {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "nordlynx" counter packets 22165 bytes 2240787 masquerade
oifname "ens18" counter packets 501166 bytes 68577241 masquerade
}
}最後,來把會跟 Gateway WAN2 連結的 ens19 設定一個 IP 吧,編輯 /etc/network/interfaces 然後加入這段:
allow-hotplug ens19
iface ens19 inet static
address 172.30.101.1
netmask 255.255.255.0存檔之後執行下面的指令套用網卡設定:
sudo ifup ens19Linux VM 就先到這裡吧,等等還要再回來設定從 iPhone Shortcuts 連回來的 SSH Key。
UniFi Network
將實體網路線按照上面寫的接好,然後就可以進入 UniFi Network 來進行接下來的設定。
建立 Network
在 UniFi Network 的 Settings > Networks 裡面建立一個專門給 Linux VM 跟 WAN2 連結的 VLAN:

新增 WAN
在新版的 UniFI Network 裡面,現在 Gateway 上面的每個 port 都可以拿來當 WAN port 使用了,所以這裡我就把 Port 4 當成 WAN port 來使用。在 Settings > Internet 裡面可以按 Add WAN 新增。這裡有幾個重點,第一個就是 Expected ISP Speeds 這裡填上大概的上下傳速度就可以了,下面的 IP address 因為我們的 Linux VM 沒有安裝 DHCP server 所以這裡就指定一個固定 IP。最下面的 DNS 記得要使用 NordVPN 的 DNS 來避免 DNS leak。NordVPN 的 DNS 是 103.86.96.100 跟 103.86.99.100。

設定到這裡,WAN2 應該就會連上線亮綠燈啦!接下來最後就要設定 Policy Based Routing 把 Apple TV 的所有流量都倒進 WAN2 了。
Policy Based Routing
點到 Settings > Policy Engine > Policy Table,然後 Create New Policy,找到你的 Apple TV,並且把所有的流量都倒進 WAN2 吧!

做完這一步之後,你現在看 Apple TV 的時候應該就是走 Linux VM 出去的囉!沒有連上 VPN 的時候會走本來的網路,而連上 VPN 的時候就會走你選擇的地區出去啦!我們可以回到 Linux VM 來手動連一下試試看。
SSH 回去 Linux VM 之後,使用 nordvpn command 連到美國吧:
$ nordvpn connect United_States
Connecting to United States #9990 (us9990.nordvpn.com)
You are connected to United States #9990 (us9990.nordvpn.com)!然後可以直接 verify 我們是不是連上了:
$ curl ifconfig.co/json
{
"ip": "157.97.134.211",
"ip_decimal": 2640414419,
"country": "United States",
"country_iso": "US",
"country_eu": true,
"region_name": "Washington",
"region_code": "WA",
"metro_code": 819,
"zip_code": "98160",
"city": "Seattle",
"latitude": 47.6034,
"longitude": -122.3414,
"time_zone": "America/Los_Angeles",
"asn": "AS147049",
"asn_org": "PacketHub S.A.",
"user_agent": {
"product": "curl",
"version": "8.14.1",
"raw_value": "curl/8.14.1"
}
}成功啦!這個時候你的 Apple TV 就會透過這個 IP 連線囉!nordvpn command 還有很多功能,有興趣的話可以使用 nordvpn help 看看。
用 Shortcuts 把全部連起來
終於到了最後一步啦!當然現在設定的這一切如果還要每次連線都要 SSH 到 Linux VM 上面感覺還是有點麻煩啊!還好,我們可以使用 Shortcuts 的 Run script over SSH 來 automate 這些步驟。
我已經把 Shortcuts 做好啦,不過這個 Shortcut 有使用到 Actions 這個 Shortcuts 百寶箱,記得要先安裝 Actions 噢!

安裝完 Action 之後,就可以直接用手機按下面的按鈕加入到你的 Shortcuts 裡面。
加入 Shortcut 的時候會需要設定 Linux VM 的 IP 跟使用者名稱,大家再按照自己的 Linux VM 設定。


另外,因為這個 Shortcut 是使用 SSH Key 來登入跟執行 SSH 指令,所以請小心的往下滑到任何一個執行 SSH 的 action,並且把 public key copy 出來,然後在 Linux VM 上面執行:


echo 'ssh-public-key' >> ~/.ssh/authorized_keys把 public key 加到你的 Linux VM 帳號裡面就可以順利執行 SSH command 囉!
Privacy 相關
在執行這個 Shortcut 的時候,你或許會遇到一些跟權限相關的 pop-up,這個時候再按下 Always Allow,之後就不會再問啦!

加到 Control Center
最後別忘了把這個 Shortcut 加到 Control Center 裡面,這樣只要從右上角拉下 Control Center 就可以快速的讓 Apple TV 瞬間移動到任何地方啦!⚡️
結語
因為想要解決 Home Hub 斷線看起來似乎繞了好大一圈,不過還好最後的結果還蠻滿意的。趁還記得怎麼弄起來的時候趕快記錄下來,也分享給有需要的人囉!如果使用上有問題的話歡迎在下面留言告訴我。

Comments ()