使用frp和Shadowsocks实现安全访问内网服务

前言

初期自建服务器进度完成后,第二步便是实现外网对内网服务的访问(不然岂不是太过鸡肋w)。但苦于没有公网ip,传统内网穿透(如frp)把自身服务公开到公网又觉得太不安全,zerotier虚拟局域网又要频繁切换vpn很不方便,总是找不到个万全的方法,因而一直处于搁置状态。如今看到b站@靛青K大佬通过ss实现内网服务安全访问的方法,咱灵光一闪,想到通过frp解决没有公网ip问题,进而通过ss实现内网安全访问的思路,于是便有了这篇文章——

主体思路

通过clash实现基于域名的分流,当匹配到特定域名后缀后将流量发往ss服务端,ss服务端通过frp实现内网穿透,从而实现安全而又便捷的内网访问功能。相较于传统公网ip和frp在公网暴露服务的风险隐患,本方法只允许知晓ss账号的人通过ss访问内网服务,而相对于zerotier则连通性更好,还免去了zerotier和clash不能共存的麻烦,方便很多。

流量整体转发路径如下

外网访问 => clash规则匹配分流(ss客户端) => frps => frpc => ss服务端 => (ADGuard Home 自建DNS) => 反向代理服务器 => 目标服务

Shadowsocks 服务端搭建

本人使用Shadowsocks-rust版本,通过docker安装。其中【宿主机地址】替换为本地保存ss配置文件的目录。

1
docker run -d -p 9000:9000 -p 9000:9000/udp --name shadowsocks-rust --restart=always -v 【宿主机目录】:/etc/shadowsocks-rust teddysun/shadowsocks-rust

在【宿主机目录】下新建config.json文件,内容如下。password0替换为你的密码,键dns的值192.168.1.1替换为你的dns服务器地址。method的值aes-256-gcm换为你的加密方式(用咱这个就行,不用动)。

1
2
3
4
5
6
7
"server":"0.0.0.0",
"server_port":9000,
"password":"password0",
"timeout":300,
"method":"aes-256-gcm",
"dns":"192.168.1.1",
"mode":"tcp_and_udp"

重启shadowsocks-rust服务,ss服务端设置完成。

使用frp实现内网穿透

建立frp隧道

推荐使用SAKURA FRP提供的免费内网穿透服务,普通用户能通过签到每日免费获取流量,内网服务的简单访问足够了(大流量或对网络要求更高的用户请自行购买流量包和VIP)。

(申请账号后)登录进入主面版,点击穿透-节点状态查看所有节点。免费用户节点有限,挑个能用的国内节点就行。

转到用户-用户信息-账号信息处,找到访问密钥,记录备用。

通过id(上面节点#后即为id)选取节点,转到穿透-隧道列表-新建隧道创建隧道。选择穿透节点,tcp、udp隧道各创建一个。
隧道名随意设置,本地ip为ss服务器ip,本地端口均为9000(与上面ss的配置文件一致),穿透节点、远程端口均一致,开启压缩和加密。

创建完成后,在隧道列表页获取隧道id

点其中一条隧道最后三个点(操作项),选择配置文件,找到[common]server_addr项,复制frp服务器地址备用。

通过docker安装frpc

因为使用的是SAKURA FRP提供的服务,所以这里不能使用官方版frpc,应在dockerhub拉取natfrp/frpc镜像。

注意不同于官方frpc,natfrp使用用户密钥和隧道id拉取配置文件,所以要设置启动参数。格式为<启动密钥>:<隧道ID1>,隧道ID2,隧道ID3,...,其中启动密钥即上一步的访问密钥,隧道id即上一步的两个隧道id。

使用命令行安装如下:

1
docker run -d --name frpc-natfrp --restart=always natfrp/frpc -f <启动参数>

使用portainer-ce安装也可,值得注意的是运行时参数设置在Advanced container settings-Command & logging设置,command设置为override并填入参数,如下图。

clash根据规则分流

我使用subconverter生成包含自定义规则的配置文件,subconverter可以自己搭建也能用别人搭好的,这里推荐一个ACL4SSR 在线订阅转换。远程配置使用自己的配置文件模板(可以参考大佬的模板),在rulesetproxy_group对应添加节点和规则。配置完成后转换合并订阅即可。

subconverter 配置文件模板

subconverter可以通过设置远程配置实现定制自己需要的规则分流。咱这里使用GitHub存储远程配置文件。这里推荐直接复制大佬的模板,然后在此基础上修改。

推荐几个基础模板:
ACL4SSR_Online 默认版 分组比较全(与Github同步)
ACL4SSR_Online_Full 全分组 重度用户使用(与Github同步)

subconverter订阅转换设置细则可参考官方使用文档,这里只讲本教程需要的内容。

Github 创建仓库

(注册并)登录Github,创建仓库,创建远程配置文件config.ini这里太过简单直接跳过罢

ruleset 设置

咱这里使用GitHub保存规则文件,同仓库下创建ruleset.list,填入要匹配的的域名或ip。具体规则在这里
我们这里直接填DOMAIN-SUFFIX,your-domain.com,将your-domain.com替换为你的域名,此行意为以your-domain.com为后缀的域名被匹配。最后保存,点击Raw获得真实地址。

复制大佬的配置模板,在配置模板中增加以下一行,=后面替换为你的proxy_group名称+规则地址。proxy_group和ruleset名称必须完全一致,否则会报错。注意,规则从上往下匹配,所以最好添加到一列ruleset的最上方

1
ruleset=🏠 家庭内网,https://raw.githubusercontent.com/your_account/your_project/main/rulesets/ruleset.list

该条的含义是:从ruleset.list拉取规则,并将匹配到的流量使用🏠 家庭内网中选中的节点转发。

proxy_group 设置

在配置模板中增加以下一行,将GROUPID=33换成自己订阅链接/节点的序号(序号从0开始计算)。

1
custom_proxy_group=🏠 家庭内网`select`!!GROUPID=3`[]DIRECT`http://www.gstatic.com/generate_204`60,5,50

该条的含义是:创建一个名为🏠 家庭内网的代理组,使用select模式,添加第4条订阅和DIRECT到该节点组,延迟测速周期60秒,5秒未响应即为超时,延迟容差为50ms。

获取远程配置地址

以上两处修改完成后,GitHub创建的远程配置文件页点击Raw获取真实地址。

Shadowsocks 节点链接生成

一般使用的ss链接都经过了base64加密,我们这里先生成未加密的节点链接,再加密。

获得未加密的ss链接

模板:method:password@hostname:port

method是你的ss的加密方式,password是上面设置的密码,hostnameport是上面frp服务的地址和远程端口,分别替换对应内容。替换后示例aes-256-gcm:barfoo@hostname:8388

通过base64加密获得ss链接

通过这里可以便捷地实现base64加密,然后加上ss://大功告成,可以额外添加#节点名称来给自己的ss节点命名。

通过 subconverter 生成全新订阅

使用推荐的ACL4SSR 在线订阅转换生成全新订阅。
在订阅链接处按次序填好机场订阅链接和ss链接,在订阅转换的远程配置处粘贴上面得到的远程配置地址,点生成订阅链接即可。

DNS 服务器设置

这里使用ADGuard Home做DNS服务,ADGuard Home的DNS重写可以看作自定义hosts功能。选择过滤器-DNS重写,添加DNS重写,ip为反向代理服务器的ip。ADGuard Home这里支持泛域名,好评!

这样所有对该域名的DNS请求都会将目标指向反向代理服务器所在ip,DNS设置完毕。

内网流量转发设置

现在,你已经可以实现外网访问本地内网服务了。但内网设备clash也会绕这么大一圈来访问内网服务,这不符合我们的初衷。这就需要我们对内网流量转发做额外设置,假装在这个过程中访问了frp服务器并成功转发流量

DNS 服务器设置

梅开二度,我们又回到了DNS重写,添加域名为frp服务器的域名,ip为反代服务器的ip。

反代设置 Streams 流量转发

这里通过Nginx Proxy Manager设置,没有搭建的同学可以查看咱之前的搭建教程:《使用docker搭建nginx proxy manager实现反向代理和SSL证书申请》

Nginx的Stream模块工作在第四层,我们可以用来转发tcp、udp数据包。登录管理页面,点击Streams-Add Stream,Incoming Port填frp隧道的远程端口Forward Host填ss服务端的ip,Forward Port填ss服务端的端口(即上面设置的9000)。

结语

至此,本教程终于结束了。对于内外网两栖的设备在节点组需要选择自己的ss节点,而内网设备直接选择DIRECT即可,DNS和反代服务器会将流量转发到正确的服务ip和端口。相对于@靛青K大佬直接使用ddns和公网ip搭建ss服务端,这个方法肯定麻烦许多,但对于当前ipv6未全面铺开的情况和大内网的我来说,终归是够用了。所以ipv6时代什么时候来啊(#`O′)/

参考资料

使用 Shadowsocks 访问家庭内网
使用 docker 管理 frpc 运行 - SAKURA FRP
subconverter 官方使用文档
规则编辑 - Clash for Windows
shadowsocks 生成二维码 URI
URI与二维码 - shadowsocks-libev


使用frp和Shadowsocks实现安全访问内网服务
https://sunjx97.github.io/posts/264d1c83/
作者
sunjx97
发布于
2022年2月16日
许可协议