使用 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 |
|
在【宿主机目录】下新建 config.json
文件,内容如下。password0
替换为你的密码,键 dns
的值 192.168.1.1
替换为你的 dns 服务器地址。 method
的值 aes-256-gcm
换为你的加密方式(用咱这个就行,不用动)。
1 |
|
重启 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 |
|
使用 portainer-ce 安装也可,值得注意的是运行时参数设置在 Advanced container settings - Command & logging 设置,command 设置为 override 并填入参数,如下图。
clash根据规则分流
我使用 subconverter 生成包含自定义规则的配置文件,subconverter 可以自己搭建也能用别人搭好的,这里推荐一个 ACL4SSR 在线订阅转换。远程配置使用自己的配置文件模板(可以参考大佬的模板),在 ruleset
和 proxy_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.list
拉取规则,并将匹配到的流量使用 🏠 家庭内网
中选中的节点转发。
proxy_group 设置
在配置模板中增加以下一行,将 GROUPID=1
的 1
换成自己订阅链接或节点的序号(序号从 0 开始计算)。
1 |
|
该条的含义是:创建一个名为 🏠 家庭内网
的代理组,使用 select
模式,添加第 2 条订阅和 DIRECT 到该节点组,延迟测速周期 60 秒,5 秒未响应即为超时,延迟容差为 50ms。
获取远程配置地址
以上两处修改完成后,GitHub 创建的远程配置文件页点击Raw
获取真实地址。
Shadowsocks 节点链接生成
一般使用的 ss 链接都经过了 base64 加密,我们这里先生成未加密的节点链接,再加密。
获得未加密的ss链接
模板:method:password@hostname:port
。
method
是你的 ss 的加密方式,password
是上面设置的密码,hostname
和 port
是上面 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 这里支持泛域名,好评!
内网流量转发设置
现在,你已经可以实现外网访问本地内网服务了。但内网设备 clash 也会绕这么大一圈来访问内网服务,这不符合我们的初衷。这就需要我们对内网流量转发做额外设置,
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
)。
设置完毕,此时如果我们回到家里,也不用手动切换为 DIRECT,访问内网服务的数据会自动导向反代服务器,进而转发到 ss 服务回到内网,无需担心浪费 frp 的流量。
结语
至此,本教程终于结束了。对于内外网两栖的设备在节点组需要选择自己的 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