This post is created 2 years ago, the content may be outdated.
背景
有台内网服务器,承载了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
| { "reverse": { "portals": [ { "tag": "portal", "domain": "grei0w75.gov" } ] }, "inbounds": [ { "port": 1984, "listen": "127.0.0.1", "protocol": "vmess", "settings": { "clients": [ { "id": "0d14cc45-df32-48d7-9d69-a2dee4c2eee0", "level": 0, "alterId": 16, "email": "[email protected]" }, { "id": "8ecbcaf5-d8cf-4c30-b9bd-12aa7651722c", "level": 0, "alterId": 16, "email": "[email protected]" } ] }, "streamSettings": { "network": "ws", "wsSettings": { "path": "/v2ray/" } } } ], "outbounds": [ { "tag": "direct", "protocol": "freedom" }, { "tag": "block", "protocol": "blackhole" } ], "routing": { "domainStrategy": "IPIfNonMatch", "rules": [ { "type": "field", "user": [ "[email protected]" ], "domain": [ "domain:iServer.vpn" ], "outboundTag": "portal" }, { "type": "field", "user": [ "[email protected]" ], "ip": [ "10.10.1.1" ], "outboundTag": "portal" }, { "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
| { "reverse": { "bridges": [ { "tag": "bridge", "domain": "grei0w75.gov" } ] }, "outbounds": [ { "tag": "direct", "protocol": "freedom" }, { "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": [ { "type": "field", "inboundTag": [ "bridge" ], "domain": [ "full:mr14wfx0pyv6.gov" ], "outboundTag": "tunnel" }, { "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
| { "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": [ { "tag": "direct", "protocol": "freedom" }, { "tag": "rproxy", "protocol": "vmess", "settings": { "vnext": [ { "address": "vps.mydomain.net", "port": 443, "users": [ { "alterId": 16, "id": "0d14cc45-df32-48d7-9d69-a2dee4c2eee0", "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": [ { "type": "field", "outboundTag": "rproxy", "domain": [ "domain:iServer.vpn" ] }, { "type": "field", "outboundTag": "rproxy", "ip": [ "10.10.1.1" ] } ] } }
|
流量重定向
应用以上配置后,Client访问内网的流量会通过VPS转发给iServer,也就是前文图片中反向代理(红色)的那条路已经打通了。
但是现在还没法访问到iServer,因为访问请求的是iServer.vpn
或10.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
| { "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.1
和uServer.vpn
访问。
思路
新增一路与iServer平行的反代配置,在Client上把10.10.2.1
和uServer.vpn
的流量转发到VPS,再由VPS转发给uServer。
步骤
在VPS额外添加一个portal及对应的路由规则,假设这个portal的tag为portal-1
VPS添加portal:
1 2 3 4
| { "tag": "portal-1", "domain": "qawertyhuifg.gov" }
|
VPS添加用户:
1 2 3 4 5 6 7
| { "id": "04faea4d-4cd5-4dc5-b30d-55cfef07f75b", "level": 0, "alterId": 4, "email": "[email protected]" }
|
在VPS添加路由,将uServer.vpn
和10.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
| { "type": "field", "user": [ "[email protected]" ], "domain": [ "domain:uServer.vpn" ], "outboundTag": "portal-1" }, { "type": "field", "user": [ "[email protected]" ], "ip": [ "10.10.2.1" ], "outboundTag": "portal-1" }, { "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
| { "reverse": { "bridges": [ { "tag": "bridge", "domain": "qawertyhuifg.gov" } ] }, "outbounds": [ { "tag": "direct", "protocol": "freedom" }, { "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": [ { "type": "field", "inboundTag": [ "bridge" ], "domain": [ "full:mr14wfx0pyv6.gov" ], "outboundTag": "tunnel" }, { "type": "field", "inboundTag": [ "bridge" ], "outboundTag": "direct" } ] } }
|
uServer选用一种方法实现流量重定向
不再赘述
Client添加规则,将domain:vpn
和10.10.2.0/24
转发到VPS
Client添加路由规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| { "type": "field", "outboundTag": "rproxy", "domain": [ "domain:uServer.vpn" ] }, { "type": "field", "outboundTag": "rproxy", "ip": [ "10.10.2.1" ] }
|
新的主机与iServer同一LAN
假设这台主机的内网IP为192.168.1.102
,Client希望通过10.10.1.2
和uServer.vpn
访问。
思路
把10.0.1.0/24
和domain:vpn
整个转发到iServer,在iServer上将去往10.0.1.2
和uServer.vpn
的流量重定向至192.168.1.102
。
步骤
在VPS上把去往10.10.1.0/24
和domain: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
| { "type": "field", "user": [ "[email protected]" ], "domain": [ "domain:vpn" ], "outboundTag": "portal" }, { "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
| { "type": "field", "inboundTag": [ "bridge" ], "ip": [ "10.10.1.2" ], "outboundTag": "192-168-1-102" } { "type": "field", "inboundTag": [ "bridge" ], "domain": [ "domain:uServer.vpn" ], "outboundTag": "192-168-1-102" }
|
Client转发domain:vpn
和10.10.1.0/24
到VPS
Client修改路由规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| { "type": "field", "outboundTag": "rproxy", "domain": [ "domain:vpn" ] }, { "type": "field", "outboundTag": "rproxy", "ip": [ "10.10.1.0/24" ] }
|
结合以上两种方法的可扩展组网方案 (推荐)
将domain:vpn
和10.10.0.0/16
作为内网穿透的标记。
Client设置转发domain:vpn
和10.10.0.0/16
的流量到VPS。
VPS依照二级域名或子网段将此流量路由到不同的portal。
每个内网只要有一台V2Ray作bridge就行,由它负责内网中其它主机的流量重定向。
下图的箭头表示portal流量。
其它方案
我依个人经验对比了用过的几套方案
FRP
FRP是目前我用过最好的内网穿透代理工具,它彻底盖上了ngrok的棺材板板。
FRP优点:
- 配置简单
- 无需客户端(除了STCP)
- 增改客户端无需修改服务端配置
- 不影响客户端其它代理工具
FRP缺点:
- 每个服务都需要手动添加映射
- 端口管理不便,尤其当反代的服务特别多时,很难记住
- 类似FTP这种古老的协议不好反代(需要反代端口区间,反代后因为目标地址对不上FTP客户端还会警告)
- 有些协议公网访问不安全,比如HTTP、FTP、SMB
- UDP协议的服务因为到客户端这一段是裸奔,受网络环境影响大
- 2-5都可以通过建立STCP解决,然而FRP暂时没有好用的移动端
VPN
也试过用strongSwan搭IPSec/IKEv2的VPN
VPN优点:
- 安全性高
- 无需客户端(大部分OS自带主流协议)
- 可选用2层VPN,各种服务的兼容性好
VPN缺点:
- 难配置
- 客户端各种兼容问题
- 大部分协议使用UDP,被ISP搞
- 流量特征明显,常被干扰
- 不好做分流
V2Ray反代
这是才刚用不久的方案
V2Ray反代优点:
- 可与现有客户端共存
- 路由规则灵活
- 安全性可以
V2Ray反代缺点:
- 配置繁琐,添加客户端需要改动服务端
- 兼容问题,不是所有的应用都会走代理
其它文章
在配置过程中参考了不少大佬的文章:
EOF