V2Ray 反向代理分流实现VPN效果 Feb 24th 2020 Words: 3.7k

背景

有台内网服务器,承载了Web、文件、流媒体等服务,希望在公网环境下的PC、移动端能方便地访问资源。

最初它放在内网,可以通过hostname方便地访问,例如浏览器输入http://iServer即可以访问Web服务。

我想到这台服务器装了V2Ray用于访问国际互联网,而我的手机、平板、PC也都装了V2Ray。如果利用V2Ray 4.0+的反向代理,配合强大的路由功能,应该可以做到在客户端直接通过hostname访问内网服务器,和VPN效果相似。

目标

主角命名: 内网主机——iServer,国内公网主机——VPS,客户端——Client。

Client开启V2Ray代理后,可通过域名iServer.vpn或IP10.10.1.1访问iServer。

iServer和Client仍可通过V2Ray访问互联网,并且可以在本地分流。

配置反向代理

Portal 和 bridge 所用的domain参数只是用来区分流量的,最好选用不存在的域名,以免路由规则发生冲突。
因此,我使用的vpn并不是有效的顶级域名,10.10.1.0/24也不是已经存在的内网。

VPS(公网服务器)

很多教程这里开了2个inbound分别用来接收bridge和公网访问的流量,我这里用user分流是因为觉得在NGINX反代WS的方案下,这样配置更简洁。
如果只需要内网穿透,只需要一个inbound,把全部流量转发到portal就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
{
// VPS
"reverse": {
"portals": [
{
"tag": "portal",
"domain": "grei0w75.gov"
}
]
},
"inbounds": [
{
"port": 1984,
"listen": "127.0.0.1",
"protocol": "vmess",
"settings": {
"clients": [
{
// 此用户接收Client流量,作国内分流
"id": "0d14cc45-df32-48d7-9d69-a2dee4c2eee0",
"level": 0,
"alterId": 16,
"email": "[email protected]"
},
{
// 此用户接收Bridge或Client流量,所有流量转发至iServer
"id": "8ecbcaf5-d8cf-4c30-b9bd-12aa7651722c",
"level": 0,
"alterId": 16,
"email": "[email protected]"
}
]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/v2ray/"
}
}
}
],
"outbounds": [
{
// 默认outbound,流量直接出站,可作国内代理
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
// [email protected]用户访问 iServer.vpn 的流量转发至iServer
"type": "field",
"user": [
"[email protected]"
],
"domain": [
"domain:iServer.vpn"
],
"outboundTag": "portal"
},
{
// [email protected]用户访问 10.10.1.1 的流量转发至iServer
"type": "field",
"user": [
"[email protected]"
],
"ip": [
"10.10.1.1"
],
"outboundTag": "portal"
},
{
// [email protected]用户的所有流量转发至iServer
"type": "field",
"user": [
"[email protected]"
],
"outboundTag": "portal"
}
]
}
}

iServer(内网服务器)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
{
// iServer
"reverse": {
"bridges": [
{
"tag": "bridge",
"domain": "grei0w75.gov"
}
]
},
"outbounds": [
// 默认outbound,直接连接,由此出口的流量可访问内网资源
{
"tag": "direct",
"protocol": "freedom"
},
// 此outbound用于连接VPS上的portal
{
"tag": "tunnel",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "vps.mydomain.net",
"port": 443,
"users": [
{
"alterId": 16,
"id": "8ecbcaf5-d8cf-4c30-b9bd-12aa7651722c",
"security": "none"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlssettings": {
"allowInsecure": false,
"serverName": "mydomain.net"
},
"wssettings": {
"connectionReuse": true,
"headers": {
"Host": "mydomain.net"
},
"path": "/v2ray/"
}
}
}
],
"routing": {
"rules": [
{
// 所有从bridge去往portal的流量走tunnel连接VPS
"type": "field",
"inboundTag": [
"bridge"
],
"domain": [
"full:mr14wfx0pyv6.gov"
],
"outboundTag": "tunnel"
},
// 所有从bridge收到的流量直接出站,访问内网资源
{
"type": "field",
"inboundTag": [
"bridge"
],
"outboundTag": "direct"
}
]
}
}

Client(公网访问者)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
{
// Client
"inbounds": [
// 接受本机代理请求
{
"port": 1080,
"listen": "127.0.0.1",
"protocol": "socks",
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
},
"settings": {
"auth": "noauth",
"udp": true
}
},
{
"protocol": "http",
"port": 1081,
"listen": "127.0.0.1",
"settings": {}
}
],
"outbounds": [
{
// 默认outbound,直接访问
"tag": "direct",
"protocol": "freedom"
},
{
// 由此outbound发出的流量将转发至VPS。若用[email protected]用户,则流量在VPS分流;若用[email protected]用户,则流量在VPS会通过portal转发到iServer出站
"tag": "rproxy",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "vps.mydomain.net",
"port": 443,
"users": [
{
"alterId": 16,
"id": "0d14cc45-df32-48d7-9d69-a2dee4c2eee0", // [email protected]
"security": "none"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlssettings": {
"allowInsecure": false,
"serverName": "mydomain.com"
},
"wssettings": {
"connectionReuse": true,
"headers": {
"Host": "mydomain.com"
},
"path": "/v2ray/"
}
}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
// 所有访问 iServer.vpn 的流量通过rproxy发送到VPS(VPS再通过protal发送到iServer)
"type": "field",
"outboundTag": "rproxy",
"domain": [
"domain:iServer.vpn"
]
},
{
// 所有访问 10.10.1.1 的流量通过rproxy发送到VPS(VPS再通过protal发送到iServer)
"type": "field",
"outboundTag": "rproxy",
"ip": [
"10.10.1.1"
]
}
]
}
}

流量重定向

应用以上配置后,Client访问内网的流量会通过VPS转发给iServer,也就是前文图片中反向代理(红色)的那条路已经打通了。

但是现在还没法访问到iServer,因为访问请求的是iServer.vpn10.10.1.1,而iServer并不知道这就是本机。

要让iServer接受这些流量,有以下几种方法:

方法一 (推荐)

使用V2Ray freedom出站协议的Redirect

iServer的V2Ray配置再添加一个outbound:

1
2
3
4
5
6
7
{
"tag": "loopback"
"protocol": "freedom",
"settings": {
"redirect": "127.0.0.1:0"
}
}

路由rules也要改一下:

1
2
3
4
5
6
7
8
// 所有从bridge收到的流量直接出站,访问内网资源
{
"type": "field",
"inboundTag": [
"bridge"
],
"outboundTag": "loopback"
}

方法二

如果条件允许,将iServer的局域网段设为10.10.1.0/24,并为iServer分配静态IP10.10.1.1,内网DNS添加iServer.vpn的记录
影响范围:LAN
Bonus:10.10.1.0/24的其它主机无需配置也可以通过反代访问

方法三

修改hosts,将10.10.1.1设为环回地址
影响范围:本机

修改hosts

添加10.10.1.1 iServer.vpn

添加loopback接口

编辑/etc/network/interfaces

1
2
3
4
iface lo:0 inet static
address 10.10.1.1
network 10.10.1.0
netmask 255.255.255.255

各个服务的监听地址也需要相应调整下。
至此,反向代理的部分已经完成,在Client上通过V2Ray代理访问域名iServer.vpn或IP10.10.1.1就可以访问iServer的资源了。
虽然访问HTTP浏览器会提示不安全,但是流量已经通过V2Ray加密,无需担心。手机客户端用自定义配置文件就好。

配置分流

在Client和iServer添加用于访问国际互联网的outbound,并在routing尾部追加相应的分流规则即可,不再赘述。

添加更多内网服务器

分情况可以有不同配置方案

新的主机与iServer不同LAN

且称这台内网服务器为uServer,希望通过10.10.2.1uServer.vpn访问。

思路

新增一路与iServer平行的反代配置,在Client上把10.10.2.1uServer.vpn的流量转发到VPS,再由VPS转发给uServer。

步骤

在VPS额外添加一个portal及对应的路由规则,假设这个portal的tag为portal-1

VPS添加portal:

1
2
3
4
{
"tag": "portal-1",
"domain": "qawertyhuifg.gov" //另选一个domain
}

VPS添加用户:

1
2
3
4
5
6
7
{
// 此用户接收Bridge或Client流量,所有流量转发至uServer
"id": "04faea4d-4cd5-4dc5-b30d-55cfef07f75b",
"level": 0,
"alterId": 4,
"email": "[email protected]"
}

在VPS添加路由,将uServer.vpn10.10.2.1的流量通过portal-1转发到uServer

VPS添加路由规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
// [email protected]用户访问 *.vpn 的流量转发至uServer
"type": "field",
"user": [
"[email protected]"
],
"domain": [
"domain:uServer.vpn"
],
"outboundTag": "portal-1"
},
{
// [email protected]用户访问 10.10.2.1 的流量转发至uServer
"type": "field",
"user": [
"[email protected]"
],
"ip": [
"10.10.2.1"
],
"outboundTag": "portal-1"
},
{
// [email protected]用户的所有流量转发至uServer
"type": "field",
"user": [
"[email protected]"
],
"outboundTag": "portal-1"
}

在uServer上部署V2Ray,和iServer配置相似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
{
// uServer
"reverse": {
"bridges": [
{
"tag": "bridge",
"domain": "qawertyhuifg.gov"
}
]
},
"outbounds": [
// 默认outbound,直接连接,由此出口的流量可访问内网资源
{
"tag": "direct",
"protocol": "freedom"
},
// 此outbound用于连接VPS上的portal
{
"tag": "tunnel",
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "vps.mydomain.net",
"port": 443,
"users": [
{
"alterId": 16,
"id": "04faea4d-4cd5-4dc5-b30d-55cfef07f75b",
"security": "none"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlssettings": {
"allowInsecure": false,
"serverName": "mydomain.net"
},
"wssettings": {
"connectionReuse": true,
"headers": {
"Host": "mydomain.net"
},
"path": "/v2ray/"
}
}
}
],
"routing": {
"rules": [
{
// 所有从bridge去往portal的流量走tunnel连接VPS
"type": "field",
"inboundTag": [
"bridge"
],
"domain": [
"full:mr14wfx0pyv6.gov"
],
"outboundTag": "tunnel"
},
// 所有从bridge收到的流量直接出站,访问内网资源
{
"type": "field",
"inboundTag": [
"bridge"
],
"outboundTag": "direct"
}
]
}
}

uServer选用一种方法实现流量重定向

不再赘述

Client添加规则,将domain:vpn10.10.2.0/24转发到VPS

Client添加路由规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
// 所有访问 uServer.vpn 的流量通过rproxy发送到VPS(VPS再通过protal发送到iServer)
"type": "field",
"outboundTag": "rproxy",
"domain": [
"domain:uServer.vpn"
]
},
{
// 所有访问 10.10.2.1 的流量通过rproxy发送到VPS(VPS再通过protal发送到iServer)
"type": "field",
"outboundTag": "rproxy",
"ip": [
"10.10.2.1"
]
}

新的主机与iServer同一LAN

假设这台主机的内网IP为192.168.1.102,Client希望通过10.10.1.2uServer.vpn访问。

思路

10.0.1.0/24domain:vpn整个转发到iServer,在iServer上将去往10.0.1.2uServer.vpn的流量重定向至192.168.1.102

步骤

在VPS上把去往10.10.1.0/24domain:vpn的流量全部通过portal转发到iServer

VPS修改路由规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
// [email protected]用户访问 *.vpn 的流量转发至iServer
"type": "field",
"user": [
"[email protected]"
],
"domain": [
"domain:vpn"
],
"outboundTag": "portal"
},
{
// [email protected]用户访问 10.10.1.0/24 的流量转发至iServer
"type": "field",
"user": [
"[email protected]"
],
"ip": [
"10.10.1.0/24"
],
"outboundTag": "portal"
},

在iServer上为不同的内网主机设置redirect规则(流量重定向-方法二)

iServer添加Outbound:

1
2
3
4
5
6
7
{
"tag": "192-168-1-102"
"protocol": "freedom",
"settings": {
"redirect": "192.168.1.102:0"
}
}

iServer添加Routing rules:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
// 目的地为10.10.1.2的流量转发至192.168.1.102
"type": "field",
"inboundTag": [
"bridge"
],
"ip": [
"10.10.1.2"
],
"outboundTag": "192-168-1-102"
}
{
// 目的地为uServer.vpn的流量转发至192.168.1.102
"type": "field",
"inboundTag": [
"bridge"
],
"domain": [
"domain:uServer.vpn"
],
"outboundTag": "192-168-1-102"
}

Client转发domain:vpn10.10.1.0/24到VPS

Client修改路由规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
// 所有访问 *.vpn 的流量通过rproxy发送到VPS(VPS再通过protal发送到iServer)
"type": "field",
"outboundTag": "rproxy",
"domain": [
"domain:vpn"
]
},
{
// 所有访问 10.10.1.0/24 的流量通过rproxy发送到VPS(VPS再通过protal发送到iServer)
"type": "field",
"outboundTag": "rproxy",
"ip": [
"10.10.1.0/24"
]
}

结合以上两种方法的可扩展组网方案 (推荐)

domain:vpn10.10.0.0/16作为内网穿透的标记。

Client设置转发domain:vpn10.10.0.0/16的流量到VPS。

VPS依照二级域名或子网段将此流量路由到不同的portal。

每个内网只要有一台V2Ray作bridge就行,由它负责内网中其它主机的流量重定向。

下图的箭头表示portal流量。

其它方案

我依个人经验对比了用过的几套方案

FRP

FRP是目前我用过最好的内网穿透代理工具,它彻底盖上了ngrok的棺材板板。

FRP优点:

  1. 配置简单
  2. 无需客户端(除了STCP)
  3. 增改客户端无需修改服务端配置
  4. 不影响客户端其它代理工具

FRP缺点:

  1. 每个服务都需要手动添加映射
  2. 端口管理不便,尤其当反代的服务特别多时,很难记住
  3. 类似FTP这种古老的协议不好反代(需要反代端口区间,反代后因为目标地址对不上FTP客户端还会警告)
  4. 有些协议公网访问不安全,比如HTTP、FTP、SMB
  5. UDP协议的服务因为到客户端这一段是裸奔,受网络环境影响大
  6. 2-5都可以通过建立STCP解决,然而FRP暂时没有好用的移动端

VPN

也试过用strongSwan搭IPSec/IKEv2的VPN

VPN优点:

  1. 安全性高
  2. 无需客户端(大部分OS自带主流协议)
  3. 可选用2层VPN,各种服务的兼容性好

VPN缺点:

  1. 难配置
  2. 客户端各种兼容问题
  3. 大部分协议使用UDP,被ISP搞
  4. 流量特征明显,常被干扰
  5. 不好做分流

V2Ray反代

这是才刚用不久的方案

V2Ray反代优点:

  1. 可与现有客户端共存
  2. 路由规则灵活
  3. 安全性可以

V2Ray反代缺点:

  1. 配置繁琐,添加客户端需要改动服务端
  2. 兼容问题,不是所有的应用都会走代理

其它文章

在配置过程中参考了不少大佬的文章:

EOF