Skip to content

Commit 7a2f923

Browse files
committed
Add document for wireguard EN
1 parent 0630bf4 commit 7a2f923

3 files changed

Lines changed: 368 additions & 0 deletions

File tree

docs/.vuepress/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ export default defineUserConfig({
397397
'/en_US/v5/config/proxy/hy2',
398398
'/en_US/v5/config/proxy/vless',
399399
'/en_US/v5/config/proxy/loopback',
400+
'/en_US/v5/config/proxy/wireguard',
400401
],
401402
},
402403
{

docs/en_US/v5/config/outbound.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,4 @@ Control whether how domain names in outgoing connection are processed. (v5.12.0+
6666
* [Trojan](proxy/trojan.md)
6767
* [HTTP](proxy/http.md)
6868
* [VLESS](proxy/vless.md)
69+
* [WireGuard](proxy/wireguard.md)
Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
# WireGuard
2+
3+
WireGuard is an outbound protocol that sends proxied traffic through a userspace WireGuard tunnel. (v5.48.0+)
4+
5+
The current V2Ray implementation is outbound only. It creates a virtual network stack inside V2Ray, then sends TCP and UDP traffic through the configured WireGuard peer.
6+
7+
:::warning
8+
In the current implementation:
9+
10+
* `settings.listenOnSystemNetwork` must be `true`.
11+
* `settings.wgDevice` is required.
12+
* `settings.stack` is required.
13+
* `settings.wgDevice.peers[].endpoint` should be a literal `IP:port` or `[IPv6]:port`.
14+
:::
15+
16+
## WireGuard Outbound
17+
18+
* Name: `wireguard`
19+
* Type: Outbound Protocol
20+
* ID: `outbound.wireguard`
21+
22+
### Structure
23+
24+
```json
25+
{
26+
"wgDevice": {
27+
"privateKey": "",
28+
"mtu": 0,
29+
"peers": [
30+
{
31+
"publicKey": "",
32+
"presharedKey": "",
33+
"allowedIps": [],
34+
"endpoint": "",
35+
"persistentKeepaliveInterval": 0
36+
}
37+
]
38+
},
39+
"stack": {
40+
"mtu": 0,
41+
"ips": [],
42+
"routes": [],
43+
"preferIpv6ForUdp": false,
44+
"dualStackUdp": false
45+
},
46+
"listenOnSystemNetwork": true,
47+
"domainStrategy": "USE_IP"
48+
}
49+
```
50+
51+
### Fields
52+
53+
> `wgDevice`: [DeviceObject](#deviceobject)
54+
55+
WireGuard device settings. This field is required.
56+
57+
> `stack`: [StackObject](#stackobject)
58+
59+
Virtual network stack settings. This field is required for WireGuard outbound.
60+
61+
> `listenOnSystemNetwork`: boolean
62+
63+
Create the underlying UDP socket on the system network. In the current implementation this must be `true`.
64+
65+
> `domainStrategy`: `"USE_IP"` | `"USE_IP4"` | `"USE_IP6"`
66+
67+
Controls how destination domains are resolved in this outbound's TCP dial path.
68+
69+
This field is separate from the top-level outbound `domainStrategy` in [OutboundObject](../outbound.md). The WireGuard settings use protobuf enum names such as `"USE_IP"`, not `"UseIP"`.
70+
71+
Use `"USE_IP"`, `"USE_IP4"`, or `"USE_IP6"` when the target is a domain name, because the gVisor dialer used by this outbound needs an IP address before dialing.
72+
73+
This field is not used by the current UDP path. If a UDP destination is still a domain name when it reaches this outbound, it is not supported.
74+
75+
## TCP Happy Eyeballs
76+
77+
For TCP connections, when this outbound resolves a domain name to multiple IP addresses, it uses a Happy Eyeballs style racing dialer.
78+
79+
The current implementation works as follows:
80+
81+
* It is only used on the TCP path.
82+
* It is only used when the WireGuard outbound itself resolves the destination domain through `settings.domainStrategy`.
83+
* A separate dial attempt is created for each resolved IP address.
84+
* The first successful TCP connection wins.
85+
* If both IPv4 and IPv6 addresses are present, the current implementation prefers IPv6. IPv6 attempts start immediately, and IPv4 attempts start 300 ms later.
86+
* If all resolved addresses are from the same family, there is no head start delay and all attempts start immediately.
87+
* Extra successful connections that lose the race are closed.
88+
89+
The outer outbound `domainStrategy` in [OutboundObject](../outbound.md) runs before the WireGuard proxy code. If that outer layer already resolves the destination to a single IP address, the WireGuard outbound receives an IP directly and this Happy Eyeballs logic is skipped.
90+
91+
## DeviceObject
92+
93+
### Structure
94+
95+
```json
96+
{
97+
"privateKey": "",
98+
"mtu": 0,
99+
"peers": []
100+
}
101+
```
102+
103+
### Fields
104+
105+
> `privateKey`: string
106+
107+
The local WireGuard private key, encoded as a base64 string. This is the same format used by standard WireGuard tools such as `wg genkey`.
108+
109+
For a usable client configuration, this field should be set.
110+
111+
> `mtu`: number
112+
113+
MTU for the WireGuard device. In most cases it should match `stack.mtu`.
114+
115+
> `peers`: \[ [PeerObject](#peerobject) \]
116+
117+
Remote WireGuard peers.
118+
119+
For a usable client configuration, define at least one peer.
120+
121+
## PeerObject
122+
123+
### Structure
124+
125+
```json
126+
{
127+
"publicKey": "",
128+
"presharedKey": "",
129+
"allowedIps": [],
130+
"endpoint": "",
131+
"persistentKeepaliveInterval": 0
132+
}
133+
```
134+
135+
### Fields
136+
137+
> `publicKey`: string
138+
139+
The peer public key, encoded as a base64 string.
140+
141+
If this field is empty, the peer entry is ignored by the current implementation.
142+
143+
> `presharedKey`: string
144+
145+
Optional preshared key, encoded as a base64 string.
146+
147+
> `allowedIps`: \[ string \]
148+
149+
The CIDR ranges routed to this peer in the WireGuard device configuration.
150+
151+
This field is especially important when there are multiple peers. The WireGuard device uses the destination address of each packet to decide which peer should receive it, based on these CIDR ranges.
152+
153+
For a single-peer full-tunnel client, this is typically `["0.0.0.0/0", "::/0"]`. For split routing or multi-peer setups, assign only the subnets that should go to that specific peer.
154+
155+
> `endpoint`: string
156+
157+
The peer endpoint in `IP:port` form, or `[IPv6]:port` for IPv6.
158+
159+
For a normal client configuration, this field should be set.
160+
161+
> `persistentKeepaliveInterval`: number
162+
163+
Persistent keepalive interval in seconds. A value such as `25` is commonly used when the client is behind NAT.
164+
165+
## StackObject
166+
167+
The `stack` object configures the virtual TCP/IP stack that V2Ray uses inside the WireGuard tunnel.
168+
169+
### Structure
170+
171+
```json
172+
{
173+
"mtu": 0,
174+
"ips": [
175+
{
176+
"ipAddr": "",
177+
"prefix": 0
178+
}
179+
],
180+
"routes": [
181+
{
182+
"ipAddr": "",
183+
"prefix": 0
184+
}
185+
],
186+
"preferIpv6ForUdp": false,
187+
"dualStackUdp": false,
188+
"socketSettings": {},
189+
"enablePromiscuousMode": false,
190+
"enableSpoofing": false,
191+
"tcpListener": []
192+
}
193+
```
194+
195+
### Fields
196+
197+
> `mtu`: number
198+
199+
MTU for the virtual stack. In most cases it should match `wgDevice.mtu`.
200+
201+
> `ips`: \[ [CIDRObject](#cidrobject) \]
202+
203+
The local tunnel IP addresses assigned to this client.
204+
205+
These are the addresses that exist on the virtual interface inside V2Ray. In a normal client configuration, use the addresses assigned by the WireGuard server or peer.
206+
207+
> `routes`: \[ [CIDRObject](#cidrobject) \]
208+
209+
Routes installed into the virtual stack.
210+
211+
For a full-tunnel client, use default routes such as `0.0.0.0/0` and `::/0`. For a split-tunnel client, list only the subnets that should go through WireGuard.
212+
213+
> `preferIpv6ForUdp`: boolean
214+
215+
Prefer IPv6 when both IPv4 and IPv6 are available for UDP.
216+
217+
> `dualStackUdp`: boolean
218+
219+
Enable dual-stack UDP handling inside the virtual stack.
220+
221+
> `socketSettings`: object
222+
223+
Optional socket settings for the virtual stack.
224+
225+
In the current implementation, only `rxBufSize` and `txBufSize` are applied.
226+
227+
> `enablePromiscuousMode`: boolean
228+
229+
Enable promiscuous mode on the virtual NIC inside the gVisor stack.
230+
231+
This is passed directly to the stack NIC with `SetPromiscuousMode`. It is an advanced option and is usually not needed for a normal client setup.
232+
233+
> `enableSpoofing`: boolean
234+
235+
Enable IP spoofing on the virtual NIC inside the gVisor stack.
236+
237+
This is passed directly to the stack NIC with `SetSpoofing`. It is an advanced option and is usually not needed for a normal client setup.
238+
239+
> `tcpListener`: \[ [TCPListenerObject](#tcplistenerobject) \]
240+
241+
Advanced option for exposing TCP listeners on the virtual stack.
242+
243+
Each listener opens a TCP port on the gVisor stack. Accepted connections are then forwarded to the outbound specified by that listener's `tag`, using the listener's local stack address and port as the forwarded destination.
244+
245+
This is mainly useful for specialized internal routing or virtual network topologies. It is usually not needed for a normal client setup.
246+
247+
## TCPListenerObject
248+
249+
### Structure
250+
251+
```json
252+
{
253+
"address": {
254+
"ipAddr": ""
255+
},
256+
"port": 0,
257+
"tag": ""
258+
}
259+
```
260+
261+
### Fields
262+
263+
> `address`: [ListenerAddressObject](#listeneraddressobject)
264+
265+
The local stack address to listen on.
266+
267+
The current implementation uses only the `ipAddr` value of this object when creating the listener.
268+
269+
> `port`: number
270+
271+
The TCP port to listen on inside the virtual stack.
272+
273+
> `tag`: string
274+
275+
The outbound tag used to forward accepted connections.
276+
277+
## ListenerAddressObject
278+
279+
### Structure
280+
281+
```json
282+
{
283+
"ipAddr": ""
284+
}
285+
```
286+
287+
### Fields
288+
289+
> `ipAddr`: string
290+
291+
The local IP address to listen on inside the virtual stack.
292+
293+
This object is used by `tcpListener.address`. Unlike [CIDRObject](#cidrobject), it does not use a prefix length.
294+
295+
## CIDRObject
296+
297+
### Structure
298+
299+
```json
300+
{
301+
"ipAddr": "",
302+
"prefix": 0
303+
}
304+
```
305+
306+
### Fields
307+
308+
> `ipAddr`: string
309+
310+
IP address of the CIDR block.
311+
312+
> `prefix`: number
313+
314+
Prefix length of the CIDR block.
315+
316+
## Example
317+
318+
The following example sends all traffic through a single WireGuard peer.
319+
320+
```json
321+
{
322+
"outbounds": [
323+
{
324+
"protocol": "wireguard",
325+
"tag": "wg-out",
326+
"settings": {
327+
"wgDevice": {
328+
"privateKey": "wYZ9AK9e418AUhqoXiGSSn+G5XdZzKyEGwLRpXUjHtM=", // replace with your private key
329+
"mtu": 1420,
330+
"peers": [
331+
{
332+
"publicKey": "wRaPC0mJWDNkD49zr+OH8zuHoavmQV3fDt57xMzy9uk=", // replace with the peer public key
333+
"presharedKey": "IoGHxUuE93FlkYp8S08vgy9zLxVocHeHcgo4L38TvSk=", // optional
334+
"endpoint": "198.51.100.10:51820",
335+
"allowedIps": ["0.0.0.0/0", "::/0"],
336+
"persistentKeepaliveInterval": 25
337+
}
338+
]
339+
},
340+
"stack": {
341+
"mtu": 1420,
342+
"ips": [
343+
{"ipAddr": "10.64.0.2", "prefix": 32},
344+
{"ipAddr": "fd00::2", "prefix": 128}
345+
],
346+
"routes": [
347+
{"ipAddr": "0.0.0.0", "prefix": 0},
348+
{"ipAddr": "::", "prefix": 0}
349+
],
350+
"dualStackUdp": true
351+
},
352+
"listenOnSystemNetwork": true,
353+
"domainStrategy": "USE_IP"
354+
}
355+
}
356+
]
357+
}
358+
```
359+
360+
## Notes
361+
362+
* `wgDevice.peers[].allowedIps` describes what the peer owns inside WireGuard.
363+
* `stack.routes` describes what traffic V2Ray should send into the WireGuard tunnel.
364+
* In a simple client configuration these two sets usually match, but they are not the same field and should not be confused.
365+
* If you only use IPv4, remove the IPv6 addresses and routes from both `allowedIps` and `stack`.
366+
* `settings.domainStrategy` is used by this outbound's TCP path. For UDP destinations that may still be domain names, use the outer outbound `domainStrategy` with values such as `"UseIP"`, `"UseIP4"`, or `"UseIP6"`.

0 commit comments

Comments
 (0)