一、为什么使用frp

路由器搬到了一个只有内网ip,甚至公网ipv6的都没的,以往的DDNS方案就失效了,所以,目前可以选择的方案,就是内网穿透方案了,刚好腾讯云有一台闲置的轻量云服务,这里就利用起来

二、FRP简介

frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议,且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。

选用FRP的原因

通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括:

  • 客户端服务端通信支持 TCP、QUIC、KCP 以及 Websocket 等多种协议。
  • 采用 TCP 连接流式复用,在单个连接间承载更多请求,节省连接建立时间,降低请求延迟。
  • 代理组间的负载均衡。
  • 端口复用,多个服务通过同一个服务端端口暴露。
  • 支持 P2P 通信,流量不经过服务器中转,充分利用带宽资源。
  • 多个原生支持的客户端插件(静态文件查看,HTTPS/HTTP 协议转换,HTTP、SOCK5 代理等),便于独立使用 frp 客户端完成某些工作。
  • 高度扩展性的服务端插件系统,易于结合自身需求进行功能扩展。
  • 服务端和客户端 UI 页面。

三、服务端

FRP分为客户端和服务端

我们在FRP的github链接下载对应的版本。

https://github.com/fatedier/frp/releases

image-20230715143431004

服务端的安装可以用官网的教程

使用 systemd

这个示例将会演示在 Linux 系统下使用 systemd 控制 frps 及配置开机自启。

在 Linux 系统下,使用systemd 可以方便地控制 frp 服务端 frps 的启动和停止、配置后台运行和开启自启。

要使用 systemd 来控制 frps,需要先安装 systemd,然后在 /etc/systemd/system 目录下创建一个 frps.service 文件。

  1. 如Linux服务端上没有安装 systemd,可以使用 yumapt 等命令安装 systemd

    1
    2
    3
    4
    # yum
    yum install systemd
    # apt
    apt install systemd
  2. 使用文本编辑器,如 vim 创建并编辑 frps.service 文件。

    1
    $ vim /etc/systemd/system/frps.service

    写入内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [Unit]
    # 服务名称,可自定义
    Description = frp server
    After = network.target syslog.target
    Wants = network.target

    [Service]
    Type = simple
    # 启动frps的命令,需修改为您的frps的安装路径
    ExecStart = /path/to/frps -c /path/to/frps.ini

    [Install]
    WantedBy = multi-user.target
  3. 使用 systemd 命令,管理 frps。

    1
    2
    3
    4
    5
    6
    7
    8
    # 启动frp
    systemctl start frps
    # 停止frp
    systemctl stop frps
    # 重启frp
    systemctl restart frps
    # 查看frp状态
    systemctl status frps
  4. 配置 frps 开机自启。

    1
    systemctl enable frps

四、客户端的安装

同样的,只要下载好安装包,运行

1
2
# frpc 是客户端 frps是服务端
/path/to/frpc -c /path/to/frpc.ini

重点就是配置项了

这里讲两种配置

如何用ssh 进行内网穿透

  1. 在具有公网 IP 的机器上部署 frps,修改 frps.ini 文件,这里使用了最简化的配置,设置了 frp 服务器用户接收客户端连接的端口:

    1
    2
    [common]
    bind_port = 7000
  2. 在需要被访问的内网机器上(SSH 服务通常监听在 22 端口)部署 frpc,修改 frpc.ini 文件,假设 frps 所在服务器的公网 IP 为 x.x.x.x:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [common]
    server_addr = x.x.x.x
    server_port = 7000

    [ssh]
    type = tcp
    local_ip = 127.0.0.1
    local_port = 22
    remote_port = 6000

    local_iplocal_port 配置为本地需要暴露到公网的服务地址和端口。remote_port 表示在 frp 服务端监听的端口,访问此端口的流量将会被转发到本地服务对应的端口。

  3. 分别启动 frps 和 frpc。

  4. 通过 SSH 访问内网机器,假设用户名为 test:

    ssh -oPort=6000 test@x.x.x.x

    frp 会将请求 x.x.x.x:6000 的流量转发到内网机器的 22 端口。

如何用http访问内网请求

通过自定义域名访问内网的 Web 服务

这个示例通过简单配置 HTTP 类型的代理让用户访问到内网的 Web 服务。

HTTP 类型的代理相比于 TCP 类型,不仅在服务端只需要监听一个额外的端口 vhost_http_port 用于接收 HTTP 请求,还额外提供了基于 HTTP 协议的诸多功能。

HTTPS 与此类似,但是需要注意,frp 的 https 代理需要本地服务是 HTTPS 服务,frps 端不会做 TLS 终止。也可以结合 https2http 插件来实现将本地的 HTTP 服务以 HTTPS 协议暴露出去。

  1. 修改 frps.ini 文件,设置监听 HTTP 请求端口为 8080:

    1
    2
    3
    [common]
    bind_port = 7000
    vhost_http_port = 8080

    https 代理的话需要配置 vhost_https_port

  2. 修改 frpc.ini 文件,假设 frps 所在的服务器的 IP 为 x.x.x.x,local_port 为本地机器上 Web 服务监听的端口, 绑定自定义域名为 custom_domains

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [common]
    server_addr = x.x.x.x
    server_port = 7000

    [web]
    type = http
    local_port = 80
    custom_domains = www.yourdomain.com

    [web2]
    type = http
    local_port = 8080
    custom_domains = www.yourdomain2.com
  3. 分别启动 frps 和 frpc。

  4. www.yourdomain.comwww.yourdomain2.com 的域名 A 记录解析到 IP x.x.x.x,如果服务器已经有对应的域名,也可以将 CNAME 记录解析到服务器原先的域名。或者可以通过修改 HTTP 请求的 Host 字段来实现同样的效果。

  5. 通过浏览器访问 http://www.yourdomain.com:8080 即可访问到处于内网机器上 80 端口的服务,访问 http://www.yourdomain2.com:8080 则访问到内网机器上 8080 端口的服务。

这里我写下一个场景,比如我们需要转发多个http的端口请求,比如a.com:8080 a.com:8090 分别到客户端的8080 和8090端口应该怎么办呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 这里常规配置
[common]
server_addr = xxx
server_port = 7000

[web]
type = tcp
local_ip = xxx
local_port = 8080
remote_port = 8080
[web2]
type = tcp
local_ip = xxx
local_port = 9090
remote_port = 9090

对,这里转发的请求改成tcp协议就可以了,也不用写域名什么的了