在搜索引擎搜索内网穿透,出来的结果大多都是frp,zerotier,tailscale等,我本人也使用过frp和zerotier,这两种方式也还是有各自的缺点,不是特别满意。后续自己又不断搜索折腾,发现了另外两个方案,可能会稍微有些复杂,适合比较喜欢折腾的人。😄
还是先说说之前使用过的frp和zerotier让我不太满意的点吧。
首先是frp,简单来说frp是通过一台具有公网ip的服务器转发,来实现对内网服务的访问,所以内网穿透的质量就受限于中转服务器。之前使用的 Sakura Frp,普通用户免费,限速10Mb,流量5GB,每天签到可随机获取流量,服务器节点可以选择国内延迟也比较低,对于轻度使用来说勉强够用,但是想要跑满家用宽带的上传并且需要更多的流量的话,就需要使用钞能力了,因为国内带宽还是很贵的,如果用国外的服务器的话延迟又会变得比较高,所以速度和延迟在没有钞能力的情况下很难兼得呀。
然后是zerotier,其实这个方案我现在仍在使用也比较满意。zerotier在成功打洞建立起p2p连接的时候,延迟低且速度快,基本上是能跑满我的上传的。我的宽带网络NAT类型是Full Cone全锥型(下面一种方案也会要求有全锥型NAT),所以基本上每次都能打洞成功。但是如果不能打洞成功的话就会走zerotier的中转服务就很灾难了,因为zerotier中转服务器都在国外,国内连接质量非常差!延迟高!速度慢!自己建立moon节点也需要服务器且限制于服务器的网络。zerotier唯一让我不太满意的地方就是必须使用客户端才能建立连接,虽然zerotier的客户端涵盖了绝大部分的系统,但如果我想分享自己的服务给家人(๐•ᴗ•๐)就还需要让他们都下一个zerotier才行,实在有些劝退。
说了这么多。。。现在就正式开始分享另外两个我在使用的方案🤣
1. 利用ipv6和Cloudflare回源端口(需要ipv6,域名)
现在ipv6的普及度越来越高,大部分的家庭宽带都支持了ipv6,一般情况在光(๐•ᴗ•๐)和(๐•ᴗ•๐)由器上设置一下就ok,具体怎么开启可以参考 IPV6大显神通!移动宽带没有公网IP也能玩转PT站和群晖NAS 或者咨询下安装宽带的师傅吧。
在拥有了上图的ipv6的地址之后就可以开始后续的操作。
首先我们需要购买一个域名,腾讯云,阿里云等都可以购买,最便宜的应该十几块一年,具体购买流程就不介绍了。接下来我们去注册一个Cloudflare的账号,将刚刚购买的域名解析托管到Cloudflare,具体怎么设置可参考 如何将域名托管到cloudflare。
接下来我们就需要使用ddns服务将我们的域名解析到我们的ipv6地址上,推荐使用ddns-go,简单易操作,可以使用docker安装,我是在群晖中安装的,具体安装过程可参考 推荐一个好用的公网DDNS神器“DDNS-GO”。
安装完成之后我们选择服务商-Cloudflare
接下来要获取Cloudflare的token填进去,我这是填好的。可以点击蓝色连接跳转到token创建页面。
点击创建令牌
点击编辑区域dns
保存之后将token填写到ddns-go中
在ddns-go中启用ipv6,选择对应网卡并设置一个域名,我这里分配了一个子域名
保存之后你应该就能在Cloudflare中看到这条解析记录了
不出意外我们就能在浏览器中访问到我们的nas了。
到这里都是普通使用ipv6访问nas的步骤,那如果我们在公司或者在其他地方没有ipv6的话就访问不了家里的nas了,那么有没有办法能够使得我们在使用只有ipv4的网络的时候也能访问到家中的nas呢?答案是有的,但是也存在一些限制,那就是使用Cloudflare的免费代理。
上面是Cloudflare支持回源的端口号,也就是说只有这些端口可用(除80,443)。
你在Cloudflare中开启刚刚ddns-go中新增的解析记录的代理之后,在ipv4的网络中访问这几个特殊端口时会先访问到Cloudflare的代理服务器,因为不存在ipv4地址的解析记录就会通过代理回源到ipv6的地址,所以在只有ipv4的网络中也可以走通。但是这样又有一个问题出现,我们的自己的服务不一定运行在这几个特定的端口上对吧?所以要使用端口转发或者群晖的反向代理将数据转发到对应服务的端口上,我自己是在openwrt的(๐•ᴗ•๐)由器上也跑了一个ddns-go,分配了一个另子域名,然后使用socat转发到群晖上的plex端口上,实现外网也能访问到plex媒体库,就用这个来做一个示例。
给分配的子域名勾选上代理并保存
openwrt中socat新增
监听端口因为我配置了ssl证书所以选择了一个https的端口,没有配置就选择http的端口,目标地址我选择了群晖的内网ip,端口是plex的端口,大家可以按照自己的需求填写。
打开浏览器验证下
因为走了Cloudflare的代理服务国内也没有Cloudflare服务器所以延迟也会高一些,但是速度还行勉强能跑满我宽带的50Mb上传(没试过最高能到多少),且不限流量。
2. Natter/NATMap(需要全锥型网络)
可能有人会说刚刚的方案延迟有点高,有没有延迟低而且速度还能跑满上传,像体验和有公网IP一样的方案呢?确实还真有,前段时间在v2ex发现了大佬分享的开源工具,又让内网穿透的体验上了一次层次,体验上公网IP基本一致了。
先分享下两个开源工具的地址 Natter、NATMap
其中Natter是python实现的,需要python运行环境,NATMap是Natter的C语言版本实现,我选择了NATMap,因为大佬已经打包了openwrt的插件。
在4种典型NAT实现中,完全锥型(Full cone)类型NAT(也简称为NAT-1,是访问限制较为宽松的NAT实现。具体定义为:
所有从同一个私网IP地址和端口(IP1😛ort1)发送过来的请求都会被映射成同一个公网IP地址和端口(IP2😛ort2)。并且,任何外部主机通过向映射的公网IP2和端口Port2发送报文,都可以实现和内部主机IP1😛ort1进行通信。
所以从技术原理上,当NATMap从内网侧主动建立一(๐•ᴗ•๐)TCP连接或发起UDP访问,就能触发NAT建立私网侧与公网侧地址间的端口映射关系。在NATMap的维护下,NAT会话将能持续保持,也就能持续允许公网侧任意主机访问内部主机。访问效果上等同于拥有了一组公网IP:端口。
借用大佬文档里面原理描述可以知道,在端口映射关系建立之后我们可以就通过公网ip:端口的方式来访问内网服务。
openwrt中使用步骤如下:
openwrt中安装NATMap
opkg update
opkg install natmap
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
启动NATMap
natmap -d -s stun.isp.net.au -h qq.com -b 6001
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
这里我绑定的是openwrt的6001端口,如果顺利打洞建立映射关系的话会得到如下结果
这样我们就得到了一个ipv4的地址和端口号,然后如果把openwrt的6001端口转发到80的话,我们就可以通过这个ip和端口访问到我们的openwrt管理页面。
当然是不推荐这么干的。。。
每次成功建立起映射关系之后会获取到一个新的端口,虽然NATMap会维持会话,但免不了宽带重拨的时候需要去重新建立新的映射关系,所以Natter和NATMap都支持在映射关系发生变化时执行自定义hooks脚本,然后我们在hooks脚本去通知更新ip和端口号。
我自已的一个需求就是实现外网流畅(๐•ᴗ•๐)看plex中的内容,而plex中可以在配置中可以自定义服务器访问连接,所以只需要在外网访问ip或者端口变更时,将新的地址写入plex配置中就可以了。
下面分享下整个实现步骤。
以下步骤均建立在能成功打洞建立映射关系的基础上,可先行使用Natter测试。
首先说明下我的NATMap是跑在openwrt上的,openwrt上还有个ddns-go用于更新ipv4的ip,所以在hooks脚本中只用关心端口的变化。
通过ddns-go更新ipv4的ip
hooks脚本将新端口号写入plex配置文件
#!/bin/bash
config_path="/volume1/Plex/Library/Application Support/Plex Media Server/Preferences.xml"
new_link="https://plex.xxxxx.com:$2"
sshpass -p 群晖ssh登录密码 ssh -tt 群晖ssh账号@群晖内网ip<< reallssh
while(! grep -q "new_link" "config_path")
do
sed -i -e "s#https://plex.xxxxx.com:[0-9]*#new_link#" "config_path"
sleep 10
done
echo "替换链接成功"
synoservice --restart pkgc(๐•ᴗ•๐)-Plex\ Media\ Serverexit
reallssh
exit 0
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
这里是我自己写的一个简单的更新脚本,通过ssh登入群晖修改plex的配置文件并重启,需要在openwrt上安装openssh-client
和 sshpass
插件。域名使用自己在ddns-go给ipv4的ip分配的子域名,然后还需要根据自己的情况对脚本进行修改然后保存文本文档重命名为 自己喜欢的名字.sh
上传到openwrt中,我这里上传到了/usr/
目录下并命名为plex.sh
,然后再使用chmod 777 /usr/plex.sh
命令更改下脚本的执行权限。最后在plex设置中填写好地址,端口可以先随意填写一个,因为等会脚本会更新为正确的端口,如下:
最后我们再执行
natmap -d -s stun.isp.net.au -h qq.com -b 6000 -e /usr/plex.sh
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
把我们的更新脚本添加上去,没有意外的话打开plex的设置页面就可以看到访问地址的端口已经变了,但现在是仍旧访问不了的因为现在绑定的是openwrt的6000端口,需要再把这个端口转发的群晖的plex服务上去。
然后现在再用plex设置里的那个地址就可以顺利访问到我们plex了😍
使用plex的App就更简单了,会直接连接我们设置里的地址。
还有此方式也可以用于提升pt下载的连接性,推荐大佬的脚本 qb和tr脚本
暴露服务到公网有风险,请谨慎操作