使用 WireGuard 將流量經遠端伺服器上網 (VPN)

前提:準備一台位於目標地區的 VM

請先準備一台位於你希望作為 VPN 出口之目標地區的 VM,並可透過 SSH 管理,可以參考這篇文章(作者不是我)。

外部文章分享:終身免費的 VM 服務!Google Cloud 免費方案分享

VM準備好後檢查VM所在的VPC防火牆策略有沒有放通對應的UDP port

使用GCP 注意:使用Web Console進行SSH 需要放通35.235.240.0/20 -> tcp 22

快速部署:使用一鍵腳本安裝

使用 wireguard-setup.sh。腳本會在 Server (Debian/Ubuntu)安裝及配置 WireGuard,並將各 Client 的配置輸出到 ~/wireguard-client/。

# 在Server 執行:
curl -fLO https://raw.githubusercontent.com/siumx/wireguard-setup/main/wireguard-setup.sh
sudo bash wireguard-setup.sh
# 如果已存在 /etc/wireguard/wg0.conf,腳本會進入新增 Peer mode,沿用既有的 Server 金鑰、UDP Port 與 VPN 網段。

腳本跑完後會 列出生成的.conf檔位置,如使用GCP可以在Web SSH Console上點擊下載,或其他下載工具如scp等自行下載。然後在client端直接導入即可,每個設備一份,不要共用同一個conf。

# 可以使用以下命令查看所有.conf檔完整路徑
realpath ~/wireguard-client/*

=== 附錄:手動逐步設定 ===

本文使用 Ubuntu 遠端伺服器作為 WireGuard VPN 出口,讓 Mac/iPhone 的 TCP、UDP、ICMP 與 DNS 流量經遠端伺服器上網。適用於 Wi-Fi、4G/5G 等網路。

範例網路配置:

  • WireGuard Server:10.66.66.1/24, fd66:66:66::1/64
  • Mac Client:10.66.66.2/32, fd66:66:66::2/128
  • iPhone Client:10.66.66.3/32, fd66:66:66::3/128
  • WireGuard 內部 IPv6:fd66:66:66::/64
  • WireGuard UDP Port:51820
  • 遠端公網介面:eth0(請按實際環境修改)

IPv6 說明:本例假設遠端伺服器沒有公網 IPv6。做法不是將 IPv6 轉換成 IPv4,而是把 Client 的 IPv6 一併導入 Tunnel 並阻擋,同時利用 DNS 過濾 AAAA 記錄,讓一般雙棧網站改用 IPv4,避免 4G/5G 的原生 IPv6 繞過 VPN。

步驟 1:Ubuntu 安裝和配置 WireGuard

# 1. 安裝Wireguard
sudo apt update
sudo apt install -y wireguard

# 2. 確認出公網的Network Interface
ip route get 1.1.1.1

# 輸出中的 dev 後方名字就是出公網的Interface,在後面設置Iptables 的NAT規則時會用到
 # 範例輸出:1.1.1.1 via ... dev eth0 src ...
 # 若不是 eth0,後續 NAT 規則必須改成實際介面名稱。
# 3. 產生 Server 的 Key-Pair
sudo install -m 700 -d /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/server.key'
sudo sh -c 'wg pubkey < /etc/wireguard/server.key > /etc/wireguard/server.pub'

# 查看 Server Public Key
 # server.key 是私鑰,不可公開;server.pub 需要填入 Client 的 WireGuard Config。
sudo cat /etc/wireguard/server.pub
# 4. 開啟 IPv4 Forwarding(直接寫入設定檔)
sudo tee /etc/sysctl.d/99-wireguard.conf >/dev/null <<'EOF'
net.ipv4.ip_forward=1
EOF
sudo sysctl --system
sysctl net.ipv4.ip_forward
# 預期輸出:net.ipv4.ip_forward = 1
# 5. 先在 Client WireGuard App 選擇「Add Empty Tunnel」,取得 Client Public Key。
# Server Private Key 不可公開;下列指令只在 Server 本機查看。
sudo cat /etc/wireguard/server.key
[Interface]
Address = 10.66.66.1/24, fd66:66:66::1/64
ListenPort = 51820
 # 填入上一步取得的 Server Private Key
PrivateKey = <SERVER_PRIVATE_KEY>

# 若公網介面不是 eth0,請在這兩個 NAT 規則替換為實際介面名稱。
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i %i -j REJECT
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i %i -j REJECT

[Peer]
# Mac
# 填入 Mac Client Public Key
PublicKey = <MAC_CLIENT_PUBLIC_KEY>
AllowedIPs = 10.66.66.2/32, fd66:66:66::2/128

[Peer]
# iPhone
PublicKey = <IPHONE_CLIENT_PUBLIC_KEY>
# 每個 Client 使用獨立 Tunnel IP,不可複用。
AllowedIPs = 10.66.66.3/32, fd66:66:66::3/128

# ...Other Client Peers...
# 6. 設定權限並啟動服務
sudo chmod 600 /etc/wireguard/wg0.conf
sudo systemctl enable --now wg-quick@wg0

# 確認服務、Peer 與 wg0 介面狀態。
sudo systemctl status wg-quick@wg0
sudo wg show
ip address show wg0
# 7. 若使用 UFW,開放 WireGuard UDP Port。
sudo ufw allow 51820/udp

# 雲端 Security Group/防火牆也需加入入方向規則:UDP 51820,來源 0.0.0.0/0。
# 確認服務正在監聽:
sudo ss -lunp | grep 51820

步驟 2:IPv6 配置(dnsmasq)

行動電信網路通常優先使用 IPv6。若遠端沒有公網 IPv6,Client 的 ::/0 會把 IPv6 導入 Tunnel,Server 明確拒絕轉送;dnsmasq filter-AAAA 讓雙棧網站改用 IPv4,避免 IPv6 繞過 VPN。

# 1. 安裝 dnsmasq
sudo apt update
sudo apt install -y dnsmasq

# 2. 建立 WireGuard 專用 DNS 配置;bind-dynamic 可處理 wg0 稍後才建立的情況。
# dnsmasq 僅監聽 WireGuard 位址,可與監聽 127.0.0.53 的 systemd-resolved 共存。
sudo tee /etc/dnsmasq.d/wireguard.conf >/dev/null <<'EOF'
interface=wg0
listen-address=10.66.66.1
bind-dynamic
filter-AAAA
server=1.1.1.1
EOF

# 3. 檢查並啟動 dnsmasq
sudo dnsmasq --test
sudo systemctl restart dnsmasq
sudo systemctl enable dnsmasq
sudo systemctl status dnsmasq

# 若啟動失敗,檢查 53 埠是否被其他服務佔用。
sudo ss -lntup | grep ':53'

顯示 Active: active (running) 且監聽 10.66.66.1:53 即正常;下列 loopback 警告不代表啟動失敗:

resolvconf: Dropped protocol specifier '.dnsmasq' from 'lo.dnsmasq'
resolvconf: Failed to set DNS configuration: Link lo is loopback device

只要 dnsmasq 與 systemd-resolved 分別監聽不同位址,兩者可以共存。

# 4. 驗證 AAAA 過濾
dig @10.66.66.1 example.com A
dig @10.66.66.1 example.com AAAA

A 查詢應返回 IPv4;AAAA 應為 NOERROR 且 ANSWER: 0。

限制:filter-AAAA 不是 IPv6-to-IPv4 轉換。只有 AAAA、沒有 A 記錄的網站無法存取;如需 IPv6-only 目的地,遠端必須有真正的 IPv6 上游或另一個 IPv6 Tunnel。

步驟 3:Mac 配置(使用 WireGuard App)

1. 建立 Tunnel

  1. 安裝並開啟 WireGuard App,選擇「Add Empty Tunnel」。
  2. App 會自動產生 Mac Client Private Key 與 Public Key。
  3. 將 Public Key 填入 Server wg0.conf 的 [Peer];Private Key 只保留在 Mac,不要公開。

2. 填入 Mac Tunnel 配置

[Interface]
# 填入 Mac App 自動產生的 Private Key
PrivateKey = <MAC_CLIENT_PRIVATE_KEY>
Address = 10.66.66.2/32, fd66:66:66::2/128
# 使用遠端 dnsmasq,避免取得 AAAA 記錄。
DNS = 10.66.66.1
# 適合較複雜的 4G/5G 路徑,可減少碎片問題。
MTU = 1280

[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
# IPv4 與 IPv6 都導入 Tunnel,避免 IPv6 繞過。
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = <SERVER_PUBLIC_IP_OR_DOMAIN>:51820
# 維持行動網路與 NAT 後方的連線映射。
PersistentKeepalive = 25

3. 啟用並驗證 Tunnel

# IPv4 應顯示遠端伺服器公網 IP
curl -4 https://api.ipify.org
echo

# 遠端沒有 IPv6,因此此項應超時或失敗
curl -6 --max-time 5 https://api64.ipify.org
echo

# DNS 應由 10.66.66.1 回應,AAAA 應為 ANSWER: 0
dig example.com A
dig example.com AAAA

# IPv6 目的流量應指向 WireGuard 的 utun 介面
route -n get -inet6 2606:4700:4700::1111

# 在 Server 查看連線狀態。
sudo wg show

成功時應有 latest handshake、Client Endpoint 與持續增加的 transfer。

步驟 4:同一台 Server 加入 iPhone

Server 可同時接受多台裝置,但每台裝置必須使用獨立金鑰與 Tunnel IP。不可將 Mac 完整配置匯入 iPhone,否則相同 IP 與金鑰會互相搶佔 Endpoint。

Mac:    10.66.66.2/32、fd66:66:66::2/128
iPhone:10.66.66.3/32、fd66:66:66::3/128

1. 在 iPhone WireGuard App 建立 Tunnel

  1. 選擇「Add a Tunnel」/「Create from Scratch」。
  2. App 會產生 iPhone 專用 Private Key 與 Public Key。
  3. 記下 Public Key;Private Key 只保留在 iPhone。

2. 在 Server 加入 iPhone Peer

[Peer]
# iPhone
# 填入 iPhone App 顯示的 Public Key
PublicKey = <IPHONE_PUBLIC_KEY>
AllowedIPs = 10.66.66.3/32, fd66:66:66::3/128
# 重新載入 WireGuard 並確認 iPhone Peer 已加入。
sudo systemctl restart wg-quick@wg0
sudo wg show

3. 填入 iPhone Tunnel 配置

[Interface]
# 填入 iPhone App 自動產生的 Private Key
PrivateKey = <IPHONE_PRIVATE_KEY>
Address = 10.66.66.3/32, fd66:66:66::3/128
DNS = 10.66.66.1
MTU = 1280

[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <SERVER_PUBLIC_IP_OR_DOMAIN>:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

4. 驗證 iPhone 連線

# 開啟 iPhone Tunnel 後,在 Server 驗證。
sudo wg show

iPhone Peer 應有 latest handshake、目前 4G/5G 或 Wi-Fi 的 endpoint,以及持續增加的 transfer。

iPhone 本機 Listen Port 與 Server 所見 Client Endpoint Port 可隨行動網路 NAT 改變,屬正常現象;Server 仍統一監聽 UDP 51820。

故障排查

  • 沒有 handshake:檢查兩端 Public Key、Endpoint、公網 UDP 51820 與雲端 Security Group。
  • 有 handshake 但只有數百 Bytes:確認 Client Peer 的 AllowedIPs = 0.0.0.0/0, ::/0。
  • 有 handshake 但不能上網:檢查 Client AllowedIPs、net.ipv4.ip_forward、公網介面名稱與 MASQUERADE 規則。
  • DNS 無法解析:檢查 dnsmasq 狀態及 10.66.66.1:53 是否監聽。
  • 仍顯示原生 IPv6:確認 AllowedIPs 有 ::/0,停用後重啟 Tunnel;Mac 可檢查 IPv6 route 是否指向 utun。

留言