如果你有云服务器,就可以考虑自己部署内网穿透服务,这篇文章就来说下 frp — 一个简单、高效的内网穿透工具。
本文测试使用的服务器是腾讯云服务器,系统为 64 位的 CentOS 7.6;客户端是 macOS;测试的 frp 版本为 v0.34.3。
frp 简介
frp 是一个开源项目, 采用 C/S 模式,将服务端部署在具有公网 IP 的机器上,客户端部署在内网或防火墙内的机器上,通过访问暴露在服务器上的端口,反向代理到处于内网的服务。在此基础上,frp 支持 TCP, UDP, HTTP, HTTPS 等多种协议,提供了加密、压缩,身份认证,代理限速,负载均衡等众多能力。
项目地址:https://github.com/fatedier/frp
文档地址:https://gofrp.org/docs
frp 部署要求有一定的 Linux 基础知识,而且需要有一台公网服务器作为服务端。如果是纯小白或没有服务器,可以直接看上一篇文章「免费内网穿透服务推荐」,动手能力或者好奇心强的继续往下看。
frp 基本用法
frp 下载
下载地址:https://github.com/fatedier/frp/releases
服务端和客户端在一个压缩包里,但是由于服务端和客户端系统不一样,可能要下载两个包才行。我这里下载了 frp_0.34.3_linux_amd64.tar.gz
和 frp_0.34.3_darwin_amd64.tar.gz
。
服务端安装
将 frp_0.34.3_linux_amd64.tar.gz
解压,并将 frps
和 frps.ini
上传到服务器,我这里上传到了 /usr/local/frp
下。
启动 frp 服务端:
<span class="code-snippet_outer"><span>.</span><span>/frps -c ./</span><span>frps</span><span>.</span><span>ini</span></span><span class="code-snippet_outer"><span>.</span><span>/frps -c ./</span><span>frps</span><span>.</span><span>ini</span></span>./frps -c ./frps.ini
客户端安装
将 frp_0.34.3_darwin_amd64.tar.gz
解压,用到的文件其实只有 frpc
和 frpc.ini
。
启动 frp 客户端:
<span class="code-snippet_outer"><span>.</span><span>/frpc -c ./</span><span>frpc</span><span>.</span><span>ini</span></span><span class="code-snippet_outer"><span>.</span><span>/frpc -c ./</span><span>frpc</span><span>.</span><span>ini</span></span>./frpc -c ./frpc.ini
启动完服务端和客户端,就可以用了吗?当然不可以,默认的配置都没有修改,接下来就来看看怎么修改。
自定义域名访问内网 Web 服务
这里,我们以「自定义域名访问内网 Web 服务」为例,对服务端和客户端的配置文件(.ini 文件)进行修改。
修改 frps.ini 如下:
<span class="code-snippet_outer"><span>[</span><span>common</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>common</span><span>]</span></span>[common]
<span class="code-snippet_outer"><span>bind_port </span><span>=</span><span> </span><span>7000</span></span><span class="code-snippet_outer"><span>bind_port </span><span>=</span><span> </span><span>7000</span></span>bind_port = 7000
<span class="code-snippet_outer"><span>vhost_http_port </span><span>=</span><span> </span><span>80</span></span><span class="code-snippet_outer"><span>vhost_http_port </span><span>=</span><span> </span><span>80</span></span>vhost_http_port = 80
这里的 vhost_http_port 是 HTTP 服务绑定的端口,可以修改为其他端口,使用 80 端口的好处是访问的时候域名后不用加端口。
修改 frpc.ini 如下:
<span class="code-snippet_outer"><span>[</span><span>common</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>common</span><span>]</span></span>[common]
<span class="code-snippet_outer"><span>server_addr </span><span>=</span><span> </span><span>42.194</span><span>.</span><span>190.195</span></span><span class="code-snippet_outer"><span>server_addr </span><span>=</span><span> </span><span>42.194</span><span>.</span><span>190.195</span></span>server_addr = 42.194.190.195
<span class="code-snippet_outer"><span>server_port </span><span>=</span><span> </span><span>7000</span></span><span class="code-snippet_outer"><span>server_port </span><span>=</span><span> </span><span>7000</span></span>server_port = 7000
<code><span class="code-snippet_outer"><span>[</span><span>web</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span></code><code><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>80</span></span></code><code><span class="code-snippet_outer"><span>custom_domains </span><span>=</span><span> j</span><span>.</span><span>963564449.xyz</span></span></code><code><span class="code-snippet_outer"><span>[</span><span>web</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span></code><code><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>80</span></span></code><code><span class="code-snippet_outer"><span>custom_domains </span><span>=</span><span> j</span><span>.</span><span>963564449.xyz</span></span></code>
<span class="code-snippet_outer"><span>[</span><span>web</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>web</span><span>]</span></span>[web]
<span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span>type = http
<span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>80</span></span><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>80</span></span>local_port = 80
<span class="code-snippet_outer"><span>custom_domains </span><span>=</span><span> j</span><span>.</span><span>963564449.xyz</span></span><span class="code-snippet_outer"><span>custom_domains </span><span>=</span><span> j</span><span>.</span><span>963564449.xyz</span></span>custom_domains = j.963564449.xyz
这里的 server_addr 就是你服务器的 IP,local_port 是本地程序的端口,custom_domains 是自定义的域名。
还要做几件事情:
•将域名 j.963564449.xyz 解析到 42.194.190.195•云服务器安全组要放通 7000 端口•启动本地 80 端口的程序•分别启动服务器和客户端
然后访问 http://j.963564449.xyz 即可。

这就是 frp 内网穿透的基本用法,如果觉得够用了下面的不看也可以,但如果觉得不够安全、一个映射不够用等等,那就接着往下看。
frp 进阶玩法
身份认证
为了防止有人随意使用你的 frp 服务,可以添加身份认证,最简单的就是 token 认证。
设置方法:在 frps.ini 和 frpc.ini 的 [common] 段落中配置上相同的 token 参数即可。
例如:
<span class="code-snippet_outer"><span>[</span><span>common</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>common</span><span>]</span></span>[common]
<span class="code-snippet_outer"><span>token </span><span>=</span><span> juemruen</span></span><span class="code-snippet_outer"><span>token </span><span>=</span><span> juemruen</span></span>token = juemruen
当然还有更高级的认证,可以参考文档:「frp 身份认证 」。
设置自启动
前面说到的服务端是通过命令启动的,一旦关闭远程连接,服务就会关闭,那怎么让服务保持后台运行呢?
frp_0.34.3_linux_amd64.tar.gz
解压之后可以看到一个 systemd
目录,将其中的 frps.service
文件复制到服务器的 /etc/systemd/system/
目录下,并修改 ExecStart=/usr/local/frp/frps -c /usr/local/frp/frps.ini
,完整配置文件如下:
<span class="code-snippet_outer"><span>[</span><span>Unit</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>Unit</span><span>]</span></span>[Unit]
<span class="code-snippet_outer"><span>Description</span><span>=</span><span>Frp</span><span> </span><span>Server</span><span> </span><span>Service</span></span><span class="code-snippet_outer"><span>Description</span><span>=</span><span>Frp</span><span> </span><span>Server</span><span> </span><span>Service</span></span>Description=Frp Server Service
<span class="code-snippet_outer"><span>After</span><span>=</span><span>network</span><span>.</span><span>target</span></span><span class="code-snippet_outer"><span>After</span><span>=</span><span>network</span><span>.</span><span>target</span></span>After=network.target
<code><span class="code-snippet_outer"><span>[</span><span>Service</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>Type</span><span>=</span><span>simple</span></span></code><code><span class="code-snippet_outer"><span>User</span><span>=</span><span>nobody</span></span></code><code><span class="code-snippet_outer"><span>Restart</span><span>=</span><span>on</span><span>-</span><span>failure</span></span></code><code><span class="code-snippet_outer"><span>RestartSec</span><span>=</span><span>5s</span></span></code><code><span class="code-snippet_outer"><span>ExecStart</span><span>=</span><span>/usr/</span><span>local</span><span>/</span><span>frp</span><span>/</span><span>frps </span><span>-</span><span>c </span><span>/</span><span>usr</span><span>/</span><span>local</span><span>/</span><span>frp</span><span>/</span><span>frps</span><span>.</span><span>ini</span></span></code><code><code><span class="code-snippet_outer"><span>[</span><span>Install</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>WantedBy</span><span>=</span><span>multi</span><span>-</span><span>user</span><span>.</span><span>target</span></span></code></code><code><span class="code-snippet_outer"><span>[</span><span>Service</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>Type</span><span>=</span><span>simple</span></span></code><code><span class="code-snippet_outer"><span>User</span><span>=</span><span>nobody</span></span></code><code><span class="code-snippet_outer"><span>Restart</span><span>=</span><span>on</span><span>-</span><span>failure</span></span></code><code><span class="code-snippet_outer"><span>RestartSec</span><span>=</span><span>5s</span></span></code><code><span class="code-snippet_outer"><span>ExecStart</span><span>=</span><span>/usr/</span><span>local</span><span>/</span><span>frp</span><span>/</span><span>frps </span><span>-</span><span>c </span><span>/</span><span>usr</span><span>/</span><span>local</span><span>/</span><span>frp</span><span>/</span><span>frps</span><span>.</span><span>ini</span></span></code><code><code><span class="code-snippet_outer"><span>[</span><span>Install</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>WantedBy</span><span>=</span><span>multi</span><span>-</span><span>user</span><span>.</span><span>target</span></span></code></code>
<span class="code-snippet_outer"><span>[</span><span>Service</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>Service</span><span>]</span></span>[Service]
<span class="code-snippet_outer"><span>Type</span><span>=</span><span>simple</span></span><span class="code-snippet_outer"><span>Type</span><span>=</span><span>simple</span></span>Type=simple
<span class="code-snippet_outer"><span>User</span><span>=</span><span>nobody</span></span><span class="code-snippet_outer"><span>User</span><span>=</span><span>nobody</span></span>User=nobody
<span class="code-snippet_outer"><span>Restart</span><span>=</span><span>on</span><span>-</span><span>failure</span></span><span class="code-snippet_outer"><span>Restart</span><span>=</span><span>on</span><span>-</span><span>failure</span></span>Restart=on-failure
<span class="code-snippet_outer"><span>RestartSec</span><span>=</span><span>5s</span></span><span class="code-snippet_outer"><span>RestartSec</span><span>=</span><span>5s</span></span>RestartSec=5s
<span class="code-snippet_outer"><span>ExecStart</span><span>=</span><span>/usr/</span><span>local</span><span>/</span><span>frp</span><span>/</span><span>frps </span><span>-</span><span>c </span><span>/</span><span>usr</span><span>/</span><span>local</span><span>/</span><span>frp</span><span>/</span><span>frps</span><span>.</span><span>ini</span></span><span class="code-snippet_outer"><span>ExecStart</span><span>=</span><span>/usr/</span><span>local</span><span>/</span><span>frp</span><span>/</span><span>frps </span><span>-</span><span>c </span><span>/</span><span>usr</span><span>/</span><span>local</span><span>/</span><span>frp</span><span>/</span><span>frps</span><span>.</span><span>ini</span></span>ExecStart=/usr/local/frp/frps -c /usr/local/frp/frps.ini
<code><span class="code-snippet_outer"><span>[</span><span>Install</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>WantedBy</span><span>=</span><span>multi</span><span>-</span><span>user</span><span>.</span><span>target</span></span></code><code><span class="code-snippet_outer"><span>[</span><span>Install</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>WantedBy</span><span>=</span><span>multi</span><span>-</span><span>user</span><span>.</span><span>target</span></span></code>
<span class="code-snippet_outer"><span>[</span><span>Install</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>Install</span><span>]</span></span>[Install]
<span class="code-snippet_outer"><span>WantedBy</span><span>=</span><span>multi</span><span>-</span><span>user</span><span>.</span><span>target</span></span><span class="code-snippet_outer"><span>WantedBy</span><span>=</span><span>multi</span><span>-</span><span>user</span><span>.</span><span>target</span></span>WantedBy=multi-user.target
特别提示,如果使用此方法启动 frps 服务,vhost_http_port 又想用 80 端口,需要将配置文件中的 User=nobody 注释掉或删掉,当然也可以使用 Nginx 端口转发,这里就不细说了。
设置 frps 服务开机启动:
<span class="code-snippet_outer"><span>sudo systemctl enable frps</span></span><span class="code-snippet_outer"><span>sudo systemctl enable frps</span></span>sudo systemctl enable frps
启动 frps 服务:
<span class="code-snippet_outer"><span>sudo systemctl start frps</span></span><span class="code-snippet_outer"><span>sudo systemctl start frps</span></span>sudo systemctl start frps
这样 frps 服务就可以在后台运行了,即使服务器关机重启也会自动启动。
其他命令如下:
•手动重启 frps 服务:
<span class="code-snippet_outer"><span>sudo systemctl restart frps</span></span><span class="code-snippet_outer"><span>sudo systemctl restart frps</span></span>sudo systemctl restart frps
•停止 frps 服务:
<span class="code-snippet_outer"><span>sudo systemctl stop frps</span></span><span class="code-snippet_outer"><span>sudo systemctl stop frps</span></span>sudo systemctl stop frps
自定义二级域名
如果同时需要多个代理,那就需要多个域名,是不是要把每个域名都解析到服务器呢?
当然不是, frp 提供了「自定义二级域名」的功能。
首先,解析 *.963564449.xyz 到 42.194.190.195。
然后,修改 frps.ini 如下:
<span class="code-snippet_outer"><span>[</span><span>common</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>common</span><span>]</span></span>[common]
<span class="code-snippet_outer"><span>bind_port </span><span>=</span><span> </span><span>7000</span></span><span class="code-snippet_outer"><span>bind_port </span><span>=</span><span> </span><span>7000</span></span>bind_port = 7000
<span class="code-snippet_outer"><span>vhost_http_port </span><span>=</span><span> </span><span>80</span></span><span class="code-snippet_outer"><span>vhost_http_port </span><span>=</span><span> </span><span>80</span></span>vhost_http_port = 80
<span class="code-snippet_outer"><span>token </span><span>=</span><span> juemruen</span></span><span class="code-snippet_outer"><span>token </span><span>=</span><span> juemruen</span></span>token = juemruen
<span class="code-snippet_outer"><span>subdomain_host </span><span>=</span><span> </span><span>963564449.xyz</span></span><span class="code-snippet_outer"><span>subdomain_host </span><span>=</span><span> </span><span>963564449.xyz</span></span>subdomain_host = 963564449.xyz
再修改 frpc.ini 如下:
<span class="code-snippet_outer"><span>[</span><span>common</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>common</span><span>]</span></span>[common]
<span class="code-snippet_outer"><span>server_addr </span><span>=</span><span> </span><span>42.194</span><span>.</span><span>190.195</span></span><span class="code-snippet_outer"><span>server_addr </span><span>=</span><span> </span><span>42.194</span><span>.</span><span>190.195</span></span>server_addr = 42.194.190.195
<span class="code-snippet_outer"><span>server_port </span><span>=</span><span> </span><span>7000</span></span><span class="code-snippet_outer"><span>server_port </span><span>=</span><span> </span><span>7000</span></span>server_port = 7000
<span class="code-snippet_outer"><span>token </span><span>=</span><span> juemruen</span></span><span class="code-snippet_outer"><span>token </span><span>=</span><span> juemruen</span></span>token = juemruen
<code><span class="code-snippet_outer"><span>[</span><span>web</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span></code><code><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>80</span></span></code><code><span class="code-snippet_outer"><span>subdomain </span><span>=</span><span> j</span></span></code><code><code><span class="code-snippet_outer"><span>[</span><span>web1</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span></code><code><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>8080</span></span></code><code><span class="code-snippet_outer"><span>subdomain </span><span>=</span><span> w</span></span></code></code><code><span class="code-snippet_outer"><span>[</span><span>web</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span></code><code><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>80</span></span></code><code><span class="code-snippet_outer"><span>subdomain </span><span>=</span><span> j</span></span></code><code><code><span class="code-snippet_outer"><span>[</span><span>web1</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span></code><code><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>8080</span></span></code><code><span class="code-snippet_outer"><span>subdomain </span><span>=</span><span> w</span></span></code></code>
<span class="code-snippet_outer"><span>[</span><span>web</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>web</span><span>]</span></span>[web]
<span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span>type = http
<span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>80</span></span><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>80</span></span>local_port = 80
<span class="code-snippet_outer"><span>subdomain </span><span>=</span><span> j</span></span><span class="code-snippet_outer"><span>subdomain </span><span>=</span><span> j</span></span>subdomain = j
<code><span class="code-snippet_outer"><span>[</span><span>web1</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span></code><code><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>8080</span></span></code><code><span class="code-snippet_outer"><span>subdomain </span><span>=</span><span> w</span></span></code><code><span class="code-snippet_outer"><span>[</span><span>web1</span><span>]</span></span></code><code><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span></code><code><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>8080</span></span></code><code><span class="code-snippet_outer"><span>subdomain </span><span>=</span><span> w</span></span></code>
<span class="code-snippet_outer"><span>[</span><span>web1</span><span>]</span></span><span class="code-snippet_outer"><span>[</span><span>web1</span><span>]</span></span>[web1]
<span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span><span class="code-snippet_outer"><span>type </span><span>=</span><span> http</span></span>type = http
<span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>8080</span></span><span class="code-snippet_outer"><span>local_port </span><span>=</span><span> </span><span>8080</span></span>local_port = 8080
<span class="code-snippet_outer"><span>subdomain </span><span>=</span><span> w</span></span><span class="code-snippet_outer"><span>subdomain </span><span>=</span><span> w</span></span>subdomain = w
这里的 web 和 web1 的名称可以自定义,但是不能重复。
最后,重启服务端和客户端,分别访问 http://j.963564449.xyz 和 http://w.963564449.xyz,也就是本地 80 端口和 8080 端口对应的服务。
这样,即使有很多的代理,也无需一一解析域名,只需要写配置文件就可以了。
服务端 Dashboard
服务端 Dashboard 使用户可以通过浏览器查看 frp 的状态以及代理统计信息。
想要知道有多少客户端连接了服务端?有多少个代理?通过服务端 Dashboard 就可以查看。
在 frps.ini 的 [common] 段落添加下面的代码:
<span class="code-snippet_outer"><span>dashboard_port </span><span>=</span><span> </span><span>7500</span></span><span class="code-snippet_outer"><span>dashboard_port </span><span>=</span><span> </span><span>7500</span></span>dashboard_port = 7500
<span class="code-snippet_outer"><span># dashboard 用户名密码,默认都为 admin,如果不需要,需要主动设置为空</span></span><span class="code-snippet_outer"><span># dashboard 用户名密码,默认都为 admin,如果不需要,需要主动设置为空</span></span># dashboard 用户名密码,默认都为 admin,如果不需要,需要主动设置为空
<span class="code-snippet_outer"><span>dashboard_user </span><span>=</span><span> admin</span></span><span class="code-snippet_outer"><span>dashboard_user </span><span>=</span><span> admin</span></span>dashboard_user = admin
<span class="code-snippet_outer"><span>dashboard_pwd </span><span>=</span><span> admin</span></span><span class="code-snippet_outer"><span>dashboard_pwd </span><span>=</span><span> admin</span></span>dashboard_pwd = admin
云服务器安全组放通 7500 端口,然后访问「服务器IP:7500」,即 http://42.194.190.195:7500,就可以查看 Dashboard 了。

通过 Proxies–>HTTP 可以查看详细信息:

当然,文中提到的只是 frp 的部分用法,更多关于 frp 的用法和说明可以参考官方文档:https://gofrp.org/docs。
由于微信不支持外链,请点击下方【阅读原文】,访问我的个人博客。
原文链接:https://toutiao.io/posts/nxkil2p/preview