想从公网访问NAS?买不起群晖?不想做内网穿透?动态IP没法备案?怕被查水表封宽带?看过来!
NAS的网络困境
我是一个NAS玩家,说白了就是有一台放在家里的私人文件服务器。NAS最大的问题就是公网访问。如果一台NAS只有在家的时候能用,那必然是非常的不爽。想从公网访问家里的NAS,方法无非是两种:
- 内网穿透(包括ngrok、FRP、群晖AnyConnect等)。原理是从NAS向一台具有公网IP,能被公网访问的外部服务器发起连接,通过这条连接建立隧道,外网服务器把收到的访问全部转发到隧道里从而到达内网的NAS。
- 端口映射。原理是在网关处设置转发规则,到达网关的数据包会被根据端口映射规则转发给NAS处理。
内网穿透的优点是不需要家里有公网IP,也不需要拥有网关控制权;缺点则是稳定性和速度。端口映射的优缺点正好相反。如果你是移动宽带,则不需要考虑端口映射方案,因为移动家庭宽带没有公网IP。公网IP是采用端口映射方案的前提条件,因为没有公网IP意味着还存在上级NAT,而普通用户是不具备运营商NAT网关的控制权的。
为了追求稳定性,我采用端口映射的方案。内网穿透在此不多加赘述。电信/联通宽带用户如果发现没有公网IP,都可以打电话要求分配。
如果你使用自己的路由器,查询是否具有公网IP时,要在光猫上查看。现代光猫默认配置为NAT模式,相当于一个在路由器上级的网关。
确认光猫获取到了公网IP(而非100开头的运营商级内网IP)后,需要在光猫上进行端口映射或者将光猫设置为桥接模式(建议后者)。打电话给客服要求桥接光猫即可,如果ISP不同意,可以考虑自行破解光猫或更换自购光猫,此处也不加赘述。
因此,现在假设你使用电信或联通宽带,已经获得了公网IP并桥接了光猫,具体表现为路由器拨号且路由器WAN口IP为公网IP。
自建Web服务的问题
众所周知,在我国境内架设Web服务器(HTTP(S)协议)需要备案,而普通家庭宽带的动态IP是无法备案的。据网上资料显示,在不备案的情况下将NAS开放到公网有被查水表的风险。一旦被查水表,ISP就会切断宽带并要求你下线Web服务后再申请恢复。第二次查到Web服务则会永久停止服务。
运营商获知你有私自架设Web服务的方式据网友分析有二:从DDNS下手,或扫描开放的端口。被查水表的网友多使用国内DDNS服务,如花生壳。因此为了我们网络连接的安全,首先要确保不使用国内DDNS。然而即使使用了国外的DDNS来解析域名,第二个问题依然存在。运营商只需要对每一个开放的端口建立HTTP(S)连接就能确认此端口是否非法提供Web服务。
应对方案和难题
应对的思路也很简单,就是根据HTTP包头部信息屏蔽所有不使用域名建立的连接。比如你的公网IP是1.2.3.4
,域名是example.com
,那么只接受Host
字段值为example.com
的连接,这样当使用HTTP(S)协议访问1.2.3.4
时,数据包被直接丢弃,就不会识别到Web服务的存在了。
不建立1.2.3.4
的虚拟主机并不能实现这一方案。当访问1.2.3.4
时,请求依然会到达Web服务器。没有资料表明有Web服务器具有根据访问地址过滤请求的功能,只要这个请求到达了Web服务器,服务器就一定会接受连接并以HTTP(S)协议作出回应,这样就暴露了。因此我们需要一个能够解析HTTP包的防火墙。
V2Ray的妙用
普通的防火墙软件也并不具备这一功能。因此我想到了V2Ray这一神器。V2Ray本是用来做梯子的,为了实现分流内建了一个路由模块,可以嗅探HTTP(S)数据包里的目标地址并根据匹配规则做出对应的反应。这一功能的使用情景通常是对本地发出的数据包进行分流,但我们只要将这一功能“反向”应用,就能实现对发往本地的数据包进行分流。
完整的实现思路如下:
- 数据包到达V2Ray对
0.0.0.0
监听的端口,进入V2Ray。 - V2Ray嗅探出Host字段的值,并进行路由判断。
- V2Ray把数据包转发给Web服务器对
127.0.0.1
监听的端口,或者将其丢弃。
配置文件样例
我知道你们想要什么(滑稽):
{
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"inboundTag": "https_filter",
"type": "field",
"domain": [
"domain:【你的域名】”
],
"outboundTag": "https_in"
}
]
},
"inbounds": [
{
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
},
"listen": "0.0.0.0",
"protocol": "dokodemo-door",
"settings": {
"address": "",
"port": 0
},
"tag": "https_filter",
"port": 2333
}
],
"outbounds": [
{
"tag": "reject",
"protocol": "blackhole"
},
{
"tag": "https_in",
"protocol": "freedom",
"settings": {
"domainStrategy": "AsIs",
"redirect": "127.0.0.1:443"
}
}
]
}
此处创建了两个出口,reject
采用blackhole
协议,用于处理被拒绝的连接,https_in
采用freedom
,用于转发被接受的连接。入口采用dokodemo-door
协议,并开启嗅探功能。路由规则只有一条,即匹配目标是预设域名的连接并交由https_in
处理。由于reject
是第一个出口,所有不符合这条规则的访问都会被拒绝。这个拒绝发生在V2Ray,而非Web服务器,V2Ray直接丢弃了收到的数据包,因此完全不会暴露Web服务器的存在。
配置完V2Ray后,记得将你要开放的公网端口转发到NAS的2333
端口(按照此处的配置文件),而非443
端口(默认的Web服务器端口)。这样所有访问Web服务器的请求都会先经过V2Ray的过滤。
注:dokodemo-door
的设计初衷是用于简单端口转发的,因此自带转发功能,即settings
中的配置。笔者推测这个转发相当于一个与dokodemo-door
绑定的outbound
,如果不用路由模块“拦截”来自dokodemo-door
的流量,则这个入口收到的数据包会被自动通过此”outbound
“转发。当配置了相应的路由模块时,自带转发不生效,但是缺少settings.address
和settings.port
会导致V2Ray不认这个inbound
,因此settings
不可省略,但是值填什么并没有关系。
效果
配置好端口转发并启动V2Ray和Web服务器后,可以尝试用浏览器直接访问IP地址(记得加上https://
前缀和端口)(都2020年了不会还有人不用HTTPS吧?),应该能看到类似这样的画面:
用curl
连接应该得到这样的提示:
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 【你的IP:你的公网端口】
使用你设置的域名应该可以正常访问到网站。