index.html

V2Ray 反向代理分流实现VPN效果

Word count: 3kReading time: 12 min
2020/02/24 Share

背景

有台内网服务器,承载了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

CATALOG
  1. 1. 背景
  2. 2. 目标
  3. 3. 配置反向代理
    1. 3.1. VPS(公网服务器)
    2. 3.2. iServer(内网服务器)
    3. 3.3. Client(公网访问者)
    4. 3.4. 流量重定向
      1. 3.4.1. 方法一 (推荐)
      2. 3.4.2. 方法二
      3. 3.4.3. 方法三
        1. 3.4.3.1. 修改hosts
        2. 3.4.3.2. 添加loopback接口
  4. 4. 配置分流
  5. 5. 添加更多内网服务器
    1. 5.1. 新的主机与iServer不同LAN
      1. 5.1.1. 思路
      2. 5.1.2. 步骤
    2. 5.2. 新的主机与iServer同一LAN
      1. 5.2.1. 思路
      2. 5.2.2. 步骤
    3. 5.3. 结合以上两种方法的可扩展组网方案 (推荐)
  6. 6. 其它方案
    1. 6.1. FRP
    2. 6.2. VPN
    3. 6.3. V2Ray反代
  7. 7. 其它文章