SSD Nodes Learn 8GB 記憶體 — 每年 $66
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-01

Docker 安裝 wg-easy:WireGuard 網頁管理介面教學

使用 Docker Compose 部署 wg-easy。本文說明 v15 版本設定變更、NET_ADMIN 權限需求、sysctl 參數配置,以及如何透過 QR code 快速完成手機 VPN 連線設定。

您將建置的內容

wg-easy 是一個具備網頁介面的 WireGuard,以單一 Docker 容器執行。它會為您管理 WireGuard 介面,並新增一個瀏覽器 UI 以便建立用戶端。您建立的每個用戶端都會獲得一個設定檔與 QR code,因此手機只需透過相機掃描螢幕即可加入 VPN。

通道本身即為一般的 WireGuard。封包由核心模組處理,因此傳輸效能與手動設定相同。您獲得的好處是簡化的用戶端生命週期管理:無需透過 SSH 編輯設定檔即可新增、停用與刪除節點。您放棄的是對該設定檔的直接控制權,這部分內容請參閱 手動設定 VPS 上的 WireGuard

您需要一台具備公開 IPv4 位址的 KVM VPS、安裝 Docker Engine 與 Compose 外掛程式,並擁有 root 存取權。共用主機核心的容器虛擬化技術(例如 OpenVZ 或 LXC)通常無法載入 WireGuard 模組,這會導致容器無法啟動介面。

Version 15 已將設定移出環境變數

您找到的大多數指南皆針對 wg-easy 14 編寫,當時您需將 WG_HOST 設定為伺服器位址,並將 PASSWORD_HASH 設定為管理員密碼的 bcrypt雜湊值,兩者皆透過環境變數設定。Version 15 經過重新編寫。官方遷移說明明確指出,v15 不再使用與 v14 相同的環境變數,且大多數設定已移至網頁介面中的管理面板。

因此,WG_HOSTPASSWORD_HASH 已不再生效。若您複製舊的 compose 檔案,容器會啟動並忽略這些行,隨後要求您在瀏覽器中建立管理員帳號。這並非錯誤,而是新的設定流程。

截至 2026 年 7 月,應鎖定的主要標籤為 15。請鎖定主要版本而非使用 latest,因為主要版本升級會變更磁碟上的設定格式,且無法順利還原。

Compose 檔案

建立一個目錄存放此堆疊,並將官方的 compose 檔案寫入其中。這是未經修改的上游檔案。

sudo mkdir -p /etc/docker/containers/wg-easy
sudo curl -o /etc/docker/containers/wg-easy/docker-compose.yml \
  https://raw.githubusercontent.com/wg-easy/wg-easy/master/docker-compose.yml

內容如下所示:

volumes:
  etc_wireguard:

services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:15
    container_name: wg-easy
    networks:
      wg:
        ipv4_address: 10.42.42.42
        ipv6_address: fdcc:ad94:bacf:61a3::2a
    volumes:
      - etc_wireguard:/etc/wireguard
      - /lib/modules:/lib/modules:ro
    ports:
      - "51820:51820/udp"
      - "51821:51821/tcp"
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv6.conf.all.disable_ipv6=0
      - net.ipv6.conf.all.forwarding=1
      - net.ipv6.conf.default.forwarding=1

networks:
  wg:
    driver: bridge
    enable_ipv6: true
    ipam:
      driver: default
      config:
        - subnet: 10.42.42.0/24
        - subnet: fdcc:ad94:bacf:61a3::/64

etc_wireguard 是一個具名儲存卷(named volume),用於存放伺服器金鑰以及您建立的每個客戶端。請務必備份該儲存卷,否則重建時會遺失所有節點。若您偏好將這些檔案存放在主機檔案系統中,可將其替換為綁定掛載(bind mount);在執行此操作前,請先閱讀 綁定掛載與具名儲存卷的差異,因為兩者的權限行為有所不同。

為何需要 NET_ADMIN、SYS_MODULE 與 sysctl

預設情況下,容器不允許存取網路堆疊,而上述每一行設定皆是為了移除特定的限制。

NET_ADMIN 允許容器建立 wg0 介面、指派位址並寫入路由。若缺少此權限,容器啟動後會在嘗試啟用介面時終止,因為 ip link add wg0 type wireguard 會回傳 Operation not permitted

SYS_MODULE 加上唯讀的 /lib/modules 掛載,允許容器在宿主機尚未載入 WireGuard 核心模組時自行載入。該模組位於宿主機核心而非映像檔內,因此必須掛載宿主機目錄。在現代核心中,該模組通常已內建,您可在宿主機上使用 sudo modprobe wireguard && echo ok 進行確認。

net.ipv4.ip_forward=1 會讓核心轉發非目的地為該機器的封包。若缺少此設定,客戶端雖能成功完成交握,但所有發往網際網路的封包都會被丟棄,導致 ping 1.1.1.1 超時,儘管 VPN 看起來處於連線狀態。

net.ipv4.conf.all.src_valid_mark=1 是最容易讓人感到意外的設定。WireGuard 會標記其輸出的封包,以避免這些封包被路由回隧道內。嚴格的反向路徑過濾(reverse path filtering)會偵測到來源位址與預期路由不符的封包並將其丟棄。此 sysctl 設定會告知核心接受這些已標記的封包,這是維持完整隧道運作而不中斷的關鍵。

啟動服務並建立管理員帳號

cd /etc/docker/containers/wg-easy
sudo docker compose up -d
sudo docker compose logs -f

請使用 docker compose updocker compose down,而非 startstop。上游開發者警告,若在不同設定下建立容器並執行 start,會導致網路狀態不一致。若您希望在重啟後恢復堆疊,restart: unless-stopped 已涵蓋此需求,而 Compose 服務的開機行為 則說明了該策略的保證範圍與限制。

網頁介面監聽 TCP 51821 連接埠。首次存取時會顯示設定頁面,您需在此建立管理員帳號,並確認用戶端連線至伺服器時所使用的宿主位址。該宿主位址會寫入每個用戶端設定檔的 Endpoint 行,因此必須為 VPS 的公用 IP 或 DNS 名稱。若設定錯誤,提供給手機的 QR Code 將指向無法連線的位置,導致握手失敗。

關於該連接埠還有一點:wg-easy 15 會拒絕純 HTTP 連線,除非您設定 INSECURE=true。透過不受信任的憑證以 HTTPS 存取,或在前端反向代理伺服器終止 TLS 皆可正常運作。若使用預設設定透過 http:// 存取則無法連線。

請勿將 UI 連接埠公開至網際網路

此 compose 檔案會將 51821 連接埠發佈至所有介面上。這是可路由您網路流量的設備登入頁面,不應對外開放。在 Docker 中發佈連接埠會將規則寫入 DOCKER 鏈,該鏈的評估優先於 ufw,因此 ufw 的拒絕規則無法將其關閉。此陷阱值得深入了解,為何 Docker 發佈的連接埠會忽略 ufw 一文對此有完整說明。

最簡單的修正方式是將 UI 綁定至 loopback 介面,並透過 SSH 通道進行存取:

    ports:
      - "51820:51820/udp"
      - "127.0.0.1:51821:51821/tcp"
    environment:
      - INSECURE=true

接著在您的筆記型電腦上執行:

ssh -L 51821:127.0.0.1:51821 youruser@your.server.address

在筆記型電腦的瀏覽器中開啟 http://127.0.0.1:51821。流量會經由 SSH 加密,該連接埠不會回應其他來源,且 INSECURE=true 在此處是安全的,因為純 HTTP 的傳輸從未離開過 loopback 介面。

開放 UDP 51820 並檢查兩層防火牆

WireGuard 本身需要從網際網路存取 UDP 51820。雖然 Docker 會發布該連接埠,但許多服務供應商會在 VPS 前端設置獨立的網路防火牆,而 Docker 無法感知該防火牆的存在。請務必在兩處皆開放此連接埠。若您使用 ufw 管理主機防火牆,基本的 VPS ufw 規則 比手動編寫 nftables 更為簡便。

請檢查容器是否確實正在監聽:

sudo ss -ulnp | grep 51820

您應能看到一個監聽中的 UDP socket。若該行未顯示任何內容,表示容器未能啟動介面,此時 sudo docker compose logs wg-easy 將會說明原因。

建立用戶端並在手機上掃描

在 UI 中建立一個用戶端,並為其命名以便日後識別,例如使用該裝置的名稱。wg-easy 會自動分配下一個可用的通道位址並為您產生金鑰對。每個用戶端列都會提供一個 QR Code 以及可供下載的 .conf 檔案。

在手機上安裝官方的 WireGuard 應用程式,選擇從 QR Code 新增通道,並將相機對準螢幕上的代碼。該通道會以您輸入的名稱顯示。將其開啟後,UI 中的用戶端列便會開始顯示傳輸計數器以及最近的交握時間。

若用戶端在啟用後未顯示交握,表示其完全無法連線至伺服器。這通常指向 UDP 51820 連接埠的問題,可能是供應商防火牆阻擋,或是設定檔中寫入的端點位址錯誤。若用戶端顯示已交握但無法存取網際網路,則問題在於轉發設定或 DNS。

在桌機上,請下載 .conf 檔案並將其匯入 WireGuard 用戶端,不要手動重新輸入。該檔案中的私鑰僅會產生並顯示一次。請務必將此檔案視同 SSH 私鑰進行管理。

何時該捨棄 UI

當您的對等節點僅為個人與手機時,wg-easy 是合適的工具。UI 的操作速度快於編輯設定檔,且撤銷遺失的手機存取權僅需點擊一次即可完成。

當您需要 UI 未提供的功能時,便會觸及此工具的限制。站對站(Site to site)路由通常是第一個遇到的瓶頸,此時對等節點的 AllowedIPs 需涵蓋整個遠端子網路,而非單一 IP 位址。接下來則是具備個別對等節點路由規則的分離通道(Split tunnels),或是由您的配置工具所產生的設定。此時,手動設定並不會更困難,只是方式不同;WireGuard 基礎指南 展示了如何使用 wg0.conf 建立相同的通道。若您希望完全停止自行維運控制平面,WireGuard 與 Tailscale 比較 涵蓋了託管服務的選項。

若上述的 compose 語法對您而言比 WireGuard 本身更陌生,VPS 上的 Docker Compose 基礎 解釋了該檔案格式與日常指令。

FAQ

為什麼 wg-easy 忽略了我的 WG_HOST 和 PASSWORD_HASH?

這些變數屬於 wg-easy 14。版本 15 經過重寫,上游開發者已將幾乎所有設定移至網頁介面的管理面板中。容器不會讀取這些變數,因此它會正常啟動,並在首次存取時要求您建立管理員帳號。請改在該設定頁面上設定客戶端使用的宿主位址。

如果我的核心已經有 WireGuard,我還需要 SYS_MODULE 嗎?

不需要。SYS_MODULE/lib/modules 掛載的存在是為了讓容器在宿主機未載入模組時進行載入。在 sudo modprobe wireguard 已經成功的宿主機上,該權限不會被使用。移除它是合理的強化步驟,且無論如何 NET_ADMIN 仍然是必要的。

客戶端已連線但無法存取網際網路,出了什麼問題?

握手成功但沒有流量,幾乎總是代表轉發設定有誤。請確認 net.ipv4.ip_forward=1net.ipv4.conf.all.src_valid_mark=1 仍在 compose 檔案中,因為手動編輯的副本經常會遺失這些設定。如果轉發已開啟,請檢查客戶端接收到的 DNS 伺服器。如果通道將所有流量透過 VPN 發送,但指向一個無法存取的 DNS 伺服器,在瀏覽器中看起來就像連線中斷。

我該如何備份我的客戶端設定?

所有資料都存放在 etc_wireguard 命名卷中的 wg0.json 檔案內。使用者介面也有一個備份按鈕,可匯出相同的資料。在進行任何升級前,請將該檔案複製到伺服器以外的地方。還原時,只需在全新容器的設定步驟中上傳該檔案即可。

我可以在反向代理後方執行 wg-easy 嗎?

可以。將代理伺服器放置在 TCP 51821 前方,在該處終止 TLS,並在容器上設定 INSECURE=true,以便它能接受來自代理伺服器的純 HTTP 請求。請保持 UDP 51820 直接對外開放,因為 VPN 流量是 UDP,無法透過 HTTP 代理傳輸。