使用docker+frp做内网穿透

为什么要做这件事?

  1. 家里有一个闲置的树莓派3B+,想把它利用起来,做一个私有云网盘
  2. 在做微信开发/对接各种支付产品时,使用过免费的内网穿透工具,稳定性欠佳
  3. 希望能通过SSH远程控制家里的树莓派,执行一些任务
  4. 于是就想自己解决这个问题.但是树莓派在家里无法被外网直接访问到,要解决这个问题,就要用到内网穿透也叫NAT穿透.

工具选择

内网穿透工具有很多,国内最有名的应该就是花生壳了吧,下面我罗列一些比较有名的工具.我并没有一一试用,排名不分先后

  • 花生壳
  • Ngrok
  • frp
  • nsloop
  • 网云穿
  • 一些内网穿透的硬件

我的选择

我就是想把闲置的树莓派利用起来,所以需要买硬件的排除,而且硬件主要是为了服务小白用户,不符合我的预期.

一些连带服务器都免费提供的工具,有各种限制.限制连接的/限制流量的/限制端口的/限制速度的,而且免费版稳定性不太有保障,所以也排除.

我个人有一个阿里云的服务器,可以支撑我独立搭建服务端,因此我最终确定了两个候选产品,也是目前最主流的两个开源内网穿透应用,Ngrok和frp.

https://github.com/inconshreveable/ngrok

https://github.com/fatedier/frp

互联网上好多内网穿透的工具都是基于Ngrok的,可见Ngrok之优秀,github上的star也相当多,有18.1K(2020-02-29),frp在github上声明目前还处于开发阶段,不建议使用在生产环境,但是它的star竟然达到了33.3K(2020-02-29)!

单看官方文档,Ngrok比较容易上手,frp的配置有一箩筐.最终有两点让我选择了frp,一个是frp有官方的中文文档(这可能也是star超级多的原因),还有它提供了一个点对点内网穿透的功能,可以传输大量数据而不经过服务器,虽然这个功能还处于初级开发阶段,但是我准备玩一玩,正好符合我搭建私有云的需求.

部署

自从学会了docker,我就在搭建各种环境的时候就有了洁癖:服务器上的各种软件,必须使用docker来搭建.

去hub.docker.com上搜了一下,有现成的镜像,我选择了snowdreamtech/frpssnowdreamtech/frpc.

https://hub.docker.com/r/snowdreamtech/frps

https://hub.docker.com/r/snowdreamtech/frpc

下面两个也很不错,但是由于客户端不支持arm架构,导致客户端在树莓派上无法使用,虽然服务端还是可以用的,但是为了保持统一,我也放弃了服务端.

https://hub.docker.com/r/cloverzrg/frps-docker

https://hub.docker.com/r/cloverzrg/frpc-docker

启动服务端

首先需要配置阿里云的ECS安全组

找到准备搭建frp服务端的ECS->管理->本示例安全组->配置规则->添加安全组规则->将计划使用的端口加入到规则中

如果不确定具体端口,或后期还要增加更多业务,可以打开一个范围内的端口,如10000/11000

配置文件frps.ini


[common]
bind_port = 17000
token = myToken
vhost_http_port = 10080
vhost_https_port = 10443

dashboard_port = 17500
dashboard_user = admin
dashboard_pwd = admin


tcp_mux = true
max_pool_count = 10

启动脚本docker-compose.yml


version: '3'
services:

    frps:
        image: snowdreamtech/frps
        ports:
            - "17000:17000"
            - "27500:17500"
            - "10022:10022" #用于ssh连接
            - "10080:10080" #用于开放给外网访问
            # 更多端口根据实际需求增加
        volumes:
            - ./frps.ini:/etc/frp/frps.ini container_name: frps

启动服务端


docker-compose -f docker-compose.yml up -d 

注:加上-d参数直接后台运行,无如下log(可通过docker logs frps查看),下面是我去掉-d参数得到的输出,建议首次启动不要加-d参数,观察一下log,确认启动是否成功.


root@docker:~/frps-conf# docker-compose -f docker-compose.yml up
Starting frps ... done
Attaching to frps
frps    | 2020/02/29 18:57:13 [I] [service.go:152] frps tcp listen on 0.0.0.0:17000
frps    | 2020/02/29 18:57:13 [I] [service.go:194] http service listen on 0.0.0.0:10080
frps    | 2020/02/29 18:57:13 [I] [service.go:215] https service listen on 0.0.0.0:10443
frps    | 2020/02/29 18:57:13 [I] [service.go:251] Dashboard listen on 0.0.0.0:17500
frps    | 2020/02/29 18:57:13 [I] [root.go:205] start frps success

启动客户端

编辑配置文件/usr/local/frp/frpc.ini


[common]
server_addr = x.x.x.x #服务器ip
server_port = 17000
token = myToken

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 10022
use_encryption = true
use_compression = true

[pi.mydomain.com]
type = http
local_port = 80
custom_domains = pi.mydomain.com

我配置了一个ssh和一个web通道.

编辑docker-compose.yml

version: '3'
services:

    frpc:
        image: cloverzrg/frpc-docker
        volumes:
            - ./frpc.ini:/conf/frpc.ini
        container_name: frpc
        network_mode: host #很重要,原因见下面的说明

启动

docker-compose -f docker-compose.yml up -d

首次建议不加-d,先查看一下输出日志

network_mode: host #很重要,为什么这么设置?

容器中的network driver默认为bridge,如果保持默认,使用web服务需要导出端口号,使用sshd服务需要将local_ip设置为宿主机的内网IP,如果把网络模式设置为host,就和主机保持在同一网络

告一段落

  • 访问域名http://pi.mydomain.com:10080,可以正常访问网页(前提是客户端所在机器启动http服务器,并监听80端口)
  • 执行命令ssh -p 10022 [email protected]可以在任意PC登录树莓派
  • 访问IPhttp:x.x.x.x:17500,可以看到仪表盘,里面显示了各个客户端的连接情况

至此,一个简单的frp服务端和frp客户端已经搭建成功.