Skip to content

安装

WireGuard

配置解析

WireGuard的配置示例

ini
[Interface] # 路由器(家里)
PrivateKey = 2FRm2lH1JAePxk9/fYOgv622y/W/2KYq4atwihOQom4=
Address = 192.168.100.1/32
ListenPort = 51820
MTU = 1280
DNS = 1.1.1.1, 8.8.8.8
PreUp = ip rule add ipproto tcp dport 22 table 1234
PostUp = wg set %i private-key /etc/wireguard/wg0.key <(some command here)
PreDown = echo "$(date +%s) WireGuard Going Down" >> /var/log/wireguard.log
PostDown = echo "$(date +%s) WireGuard Going Down" >> /var/log/wireguard.log

[Peer]
PublicKey = t4sXRq2YT4gRyr1s2TKndFuP3hYyZ1AuU01zAUiuSw0=
Endpoint = home.example.com:51820
AllowedIPs = 192.168.5.0/24, 192.168.6.0/24, 192.168.100.0/2
PersistentKeepalive = 25

[Peer]
PublicKey = M1coQS07FKAOzoq3i07ZrFQZJhbHCPurGuXDKewMk10=
AllowedIPs = 192.168.100.12/32

接口

接口IP

ini
[Interface]
Address = 192.168.100.1/32

就是自身在虚拟局域网中的IP。应该包含网络范围。一般地,IPv4使用的子网前缀是32


节点

对端

ini
[Peer] # 对方在互联网
Endpoint = home.example.com:51820
ini
[Peer] # 对方在局域网
Endpoint = 192.168.5.1:51820

指对方的网络地址,值为IP + 端口。可以使用IP或域名。

INFO

只需在对方能直接连接时使用。适用于在内网(物理)或有公网IP的对端。

允许的IP

ini
[Peer]
AllowedIPs = 192.168.5.1/32, 192.168.6.0/24, 192.168.100.0/24

功能:引导流量发送到VPN,限制VPN流量进入。

  • 对于从本地发送到网络的流量,如果目标IP在 “允许的IP”中,则会引导流量进入VPN。
  • 对于接收到的数据包,会检查来源IP,如果在“允许的IP”中,就接受,否则丢弃(忽视)。

对各种类型的对端应使用的值

  • 终端:它的 VPN IP
  • 路由器(无公网 IP):它的 VPN IP;如果要其内网设备能被远程访问,应该包含它的物理局域网IP段。
  • 路由器(有公网 IP):所有IP段

INFO

同一个设备的配置中,不同对端的AllowedIPs不应该重叠。如果重叠,冲突的网段仅对顺序向下的第一个对端生效。

WARNING

如果在某个运行了WG的自己的路由器下,不应该将其网段包含在任何对端的AllowedIPs中。否则会造成本地流量的绕路、不必要的加、解密。

总的来说,只要让这项的值为,对方会使用的IP即可。

连接保活间隔

ini
[Peer]
PersistentKeepalive = 25

关:如果没有数据需要传输,就没有任何网络活动。
开:间隔一段时间,在隧道中传输一些数据。让外界看起来一直有网络活动

WG默认的行为:启动后,没有数据传输就不建立连接;不保活。
这可能产生一些问题:

  • 隧道刚启动时不可用(我也不清楚)
  • 长时间的沉默后需要重连,这导致首批数据包的延迟。
  • 在调试时,在启动后,不能立刻知道能否连通。

PreUp, PostUp, PreDown, PostDown

功能:在指定的时机执行指定的命令。可以指定多个相同的键,按顺序执行。

  • PreUp: 在建立接口前执行命令
  • PostUp: 在建立接口后执行命令
  • PreDown: 在移除接口前执行命令
  • PostDown: 在移除接口后执行命令

创建配置

INFO

假设: 你会在家里和宿舍间活动,并且有一些设备要接入VPN。
网络范围

  • 家里:192.168.5.X/24
  • 宿舍:192.168.6.X/24
  • VPN:192.168.100.X/24

设备 VPN IP

  • 路由器(家里):192.168.100.1
  • 路由器(宿舍):192.168.100.2
  • 笔记本:192.168.100.10
  • 手机:192.168.100.11
  • 电脑:192.168.100.12

创建密钥对

WireGuard for Windows

WireGuard > 新建隧道 > 新建空隧道,然后就可以复制弹窗中的公私钥。

路由器

ini
[Interface] # 路由器(家里)
PrivateKey = 2FRm2lH1JAePxk9/fYOgv622y/W/2KYq4atwihOQom4=
Address = 192.168.100.1/32
ListenPort = 51820

[Peer] # 路由器(宿舍)
PublicKey = MfGgsYp++kB43L8SQ3db6K19xwCckJz8YQdqvvqJFjI=
AllowedIPs = 192.168.100.2/32, 192.168.6.0/24

[Peer] # 笔记本
PublicKey = Aqo/uxzO2HN0HFLO8mB67bBU9C47P1H5e7P7SWvPLB8=
AllowedIPs = 192.168.100.10/32

[Peer] # 手机
PublicKey = +4AoJPnaouLk1Sbubc2Mo6WQKCtm7wDefU0Fw11FFQI=
AllowedIPs = 192.168.100.11/32

[Peer] # 电脑
PublicKey = M1coQS07FKAOzoq3i07ZrFQZJhbHCPurGuXDKewMk10=
AllowedIPs = 192.168.100.12/32

解析

为了客户端连接方便,应该采用固定的端口。

因为它有公网环境,所以它应该是所有设备交换的中枢。因为每个设备都会主动连接它,所以它的配置文件应该包含对端的信息。

对于笔记本、手机、电脑,因为它们没有公网IP,就不用设置它们的对端地址。等它们主动连接即可。

允许的IP(路由的IP):此设备的VPN IP。

为了立刻建立VPN连接、持续保持连接,应该启用保活。即设置保活间隔。

手机

ini
[Interface] # 手机
PrivateKey = ILaRZ4y8+ztDGZXWVFpuFUcK8Fmh1C7q4KAmJXFisXM=
Address = 192.168.100.11/32

[Peer] # 路由器(家里)
PublicKey = t4sXRq2YT4gRyr1s2TKndFuP3hYyZ1AuU01zAUiuSw0=
Endpoint = home.example.com:51820
AllowedIPs = 192.168.5.0/24, 192.168.6.0/24, 192.168.100.0/24
PersistentKeepalive = 25

因为它没有公网IP,不会有其他设备主动连接它。所以它的配置文件只需包含路由器(家里)

允许的IP(路由的IP):应为家里的网段、宿舍的网段、VPN 网段。 即发往这3个区域的流量都有家里的路由器处理。家里的路由器会转发数据到正确的地方。

为了立刻建立VPN连接、持续保持连接,应该启用保活。即设置保活间隔。

路由器(宿舍)

ini
[Interface] # 路由器(宿舍)
PrivateKey = iCZM3AjBuCnWpB6H1uG6ICzrKYfFq+lBVMem1ZObL2g=
Address = 192.168.100.2/32

[Peer] # 路由器(家里)
PublicKey = t4sXRq2YT4gRyr1s2TKndFuP3hYyZ1AuU01zAUiuSw0=
Endpoint = home.example.com:51820
AllowedIPs = 192.168.5.0/24, 192.168.6.0/24, 192.168.100.0/24
PersistentKeepalive = 25

笔记本

ini
[Interface] # 笔记本
PrivateKey = ILaRZ4y8+ztDGZXWVFpuFUcK8Fmh1C7q4KAmJXFisXM=
Address = 192.168.100.10/32

[Peer] # 路由器(家里)
PublicKey = t4sXRq2YT4gRyr1s2TKndFuP3hYyZ1AuU01zAUiuSw0=
Endpoint = home.example.com:51820
AllowedIPs = 192.168.5.0/24, 192.168.6.0/24, 192.168.100.0/24
PersistentKeepalive = 25

电脑

ini
[Interface] # 电脑
PrivateKey = uHxEh+4NZK1MY6VXckHDuI0XItwsWGUp8fMTYxercXg=
Address = 192.168.100.12/32

[Peer] # 路由器(家里)
PublicKey = t4sXRq2YT4gRyr1s2TKndFuP3hYyZ1AuU01zAUiuSw0=
Endpoint = home.example.com:51820
AllowedIPs = 192.168.5.0/24, 192.168.6.0/24, 192.168.100.0/24
PersistentKeepalive = 25

导入配置

Windows

主界面 > 新建隧道

OpenWRT

WebUI > 网络 > 接口 > wg > 编辑 > 对端 > 添加对端
手动输入信息。

Android

打开软件(WireGuard),点击右下角的 +

通过打洞连接无公网 IP v4 的对端

前情提要:如果你很不幸,没有公网IPv4;但又幸运地获得了较好的 NAT 环境:完全锥型。那么可以试试本方案。

INFO

原理:通过STUN打开一个上层(公网)到本机的通道;通过DDNS和对象存储获得最新的通道入口。

在OpenWRT安装、启动插件Lucky。在其添加一个STUN规则

类型:UDP;目标地址:127.0.0.1;目标端口:OP上 WireGuard 的监听端口;

自动化更新 通道信息

完成上述操作,已经可以通过IP v4 连通对端了。只是手动获取信息再修改有点麻烦。 如果能什么都不用做就好了。

方案选择

  • DNS 法:用TXT记录保存"IP:端口"。通过解析指定的TXT记录获得端口。
  • 文件法: 保存端口信息到文件中。使得此文件能被从互联网下载。通过读它的内容来读端口。

DNS 法

Lucky > 动态域名 > 添加任务: 完成"DNS服务商设置", 添加同步记录,

  • 记录名"wg.example.com"
  • 记录类型:"TXT",
  • 记录内容:{ipv4Addr}:{STUN_name} # Lucky可以引用其模块STUN获得的端口, 变量名: "STUN_" + STUN规则名

文件法

需要通过某种手段将当前端口保存在某个文件、能在IP v4 通过某个URL下载它。内容示例:

text
721
设置脚本

这里提供一套我编写的脚本,功能是推送最新STUN信息。

放置这些脚本到Linux的某个位置(比如/etc/script):STUN 脚本, 邮件通知脚本, 邮件账号

使用说明:

  • account.yml:填写邮箱信息
  • stun_update.sh:填写 Alist 账号密码。如果需要设置Clash配置文件,还可以设置STUN规则名称与节点名称的映射关系。case的选项是STUN规则名称,Edit的参数是节点名。
调用脚本

Lucky > STUN > 添加规则: - 穿透通道本地端口: 0 # 随机端口可以使能手动触发更新 - 目标地址: WireGuard 服务器的 IP. 如果WG和插件都在OpenWRT,则是 "127.0.0.1" - 自定义脚本触发:开; - 自定义脚本:bash /etc/script/stun_update.sh ${ruleName} ${time} ${ip} ${port} ${ipAddr}

Wireguard for Windows

用PowerShell执行以下命令:允许 WireGuard 执行脚本;允许 PowerShell 执行本地脚本。

shell
reg add HKLM\Software\WireGuard /v DangerousScriptExecution /t REG_DWORD /d 1 /f # 允许 WireGuard 执行脚本
set-executionpolicy remotesigned # 允许 PowerShell 执行本地脚本

WARNING

请注意,此执行是以本地系统用户身份完成的,该用户以操作系统上的最高权限运行,因此是恶意软件的真正目标。因此,您应该以最大的恐惧启用此选项。

保存以下内容为PowerShell脚本(后缀为ps1)。至于位置,可以自己设定。修改其中的关键部分,比如URL,接口信息。

更新 EndPoint 的端口的脚本
ps1
# $Log_Path = "$env:TEMP/WireGuard_Helper.log"
# Start-Transcript -Path $Log_Path

function Test-PublicIPv6Address {
    <#
    .SYNOPSIS
        检查设备自身是否拥有公网 IPv6 地址。

    .DESCRIPTION
        此函数通过查询本地网络适配器的 IPv6 地址,并排除私有地址范围(Unique Local Addresses 和 Link-Local Addresses),
        来判断设备是否配置了公网 IPv6 地址。

    .EXAMPLE
        Test-PublicIPv6Address

        # 输出: True  (如果找到公网 IPv6 地址)
        # 输出: False (如果没有找到公网 IPv6 地址)

    .EXAMPLE
        if (Test-PublicIPv6Address) {
            Write-Host "设备拥有公网 IPv6 地址。"
        } else {
            Write-Host "设备没有公网 IPv6 地址。"
        }

    #>
    [CmdletBinding()]
    param (
        # No parameters needed for this function as it checks the local machine.
    )

    try {
        # 获取所有 IPv6 地址
        $IPv6Addresses = Get-NetIPAddress -AddressFamily IPv6 -ErrorAction Stop

        if ($IPv6Addresses) {
            foreach ($IPAddressObject in $IPv6Addresses) {
                $ip = $IPAddressObject.IPAddress

                # 排除私有 IPv6 地址范围
                if (
                    $ip -ne "::1" -and # 排除 Loopback 地址 (虽然 fe8* 也排除了 loopback,但显式排除更清晰)
                    $ip -ne "::" -and # 排除 未指定地址 (虽然 fe8* 也排除了 unspecified,但显式排除更清晰)
                    $ip -notlike "fe8*" -and # 排除 Link-Local 地址 (fe80::/10)
                    $ip -notlike "fc*" -and # 排除 Unique Local Addresses (fc00::/7)
                    $ip -notlike "fd*"    # 排除 Unique Local Addresses (fc00::/7)
                ) {
                    # 找到非私有 IPv6 地址,认为是公网 IPv6 地址
                    return $true
                }
            }
        }

        # 没有找到公网 IPv6 地址
        return $false

    }
    catch {
        # Get-NetIPAddress 可能出错,例如没有网络适配器或者权限问题
        Write-Warning "获取 IPv6 地址时出错: $_"
        return $false # 出错时也返回 False,表示无法确定是否有公网 IPv6
    }
}

function Resolve-EndpointFromTxtRecord {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Domain
    )

    Write-Host "正在查询域名 '$Domain' 的 TXT 记录..."

    try {
        # 查询TXT记录
        $txtRecord = Resolve-DnsName -Name $Domain -Type TXT -ErrorAction Stop
        
        # 提取TXT记录字符串 (假设只有一个TXT记录且是我们需要的)
        $ipAndPortString = $txtRecord.Strings -join '' # 将字符串数组合并成一个字符串

        # 解析IP和端口
        if ($ipAndPortString -match "^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)$") {
            $ip = $Matches[1]
            $port = $Matches[2]
            $endpoint = "${ip}:$port"
            Write-Host "成功从TXT记录获取到IP: $ip, 端口: $port"
            return $endpoint # 返回解析出的endpoint字符串
        }
        else {
            Write-Error "无法解析TXT记录字符串 '$ipAndPortString' 格式为 'IP:端口' 。"
            return $null # 解析失败返回 null
        }
    }
    catch {
        Write-Error "查询TXT记录失败或域名不存在: $($_.Exception.Message)"
        return $null # 查询失败返回 null
    }
}



function Get-EndpointFromFileUrl {
    $url = "https://ddns-0721.cos.ap-chengdu.myqcloud.com/WireGuard.txt" 
    $port = Invoke-RestMethod -Uri $url
    return "home.example.xyz:$port"
}

function Get-EndpointFromTxtRecord {
    $domain = "wg.example.xyz"
    
    $endpoint = Resolve-EndpointFromTxtRecord -Domain $domain
    if (-not $endpoint) { Write-Error "获取 endpoint 失败。" ; exit 1 }
    return $endpoint
}


function  Set-Endpoint { 
    $Endpoint = Get-EndpointFromTxtRecord 
    
    # wg set <接口名称> peer <对端公钥> <属性> <值>
    wg set "test2" peer "dz0cYzp5TuQ3IniYmDHLLBYDY64bRtKkBsqEvLnJzB0=" endpoint $Endpoint 
    
}


if (Test-PublicIPv6Address) {
    Write-Host "设备拥有公网 IPv6 地址。"
}
else {
    Write-Output "设备没有公网 IPv6 地址。"
    Set-Endpoint
}


# Stop-Transcript
# Pause

在 WireGuard 的配置的节 Interface 下添加一个 接口建立后要执行的命令,内容是执行此脚本。

ini
[Interface]
PostUp = powershell "C:\Users\用户名\script\WG_Update.ps1"

Wireguard for Android

使用此分支以支持TXT记录:zhcode-fun/wireguard-android

完成

试试让 WireGuard 启动连接,看看是否生效吧。


解释

NAT

  • 全称:网络地址转换
  • 功能:在公网IPv4用尽的情况下,让设备得以连接互联网。
  • 原理:共用同一个IP,分配端口。用局域网IP区分下面的设备。
NAT 的分类

如果外部主机要使用ISP已为某个内部主机分配的公网端口和其通信,

  • 完全锥型(Full Cone):指允许不同的IP和NAT下的设备通信。
  • 地址限制锥型(Restricted Cone):来源IP必须相同。
  • 端口限制锥型(Port Restricted Cone):源IP和端口必须相同。

STUN

  • 功能:在NAT下开辟一(或多)条公网到本地的通道。有点像占用公物。
  • 原理:NAT下的设备向服务器发送数据包后,电信的路由器会为你分配一个入口(在公网中)。在管理宽松的情况下,互联网上的其他的设备也能通过这个入口,实现互相通信。

打洞

使用协议STUN的过程。

DDNS

全称:动态域名解析
作用:将某个设备的,动态变化的IP,绑定到固定的域名

对象存储

云服务商为开发者提供的文件存储服务。类似网盘。特点是贵,服务好(不限速、容量)。