使用 frp 工具实现内网穿透

1. frp 工具简介

下面这一段是来自 frp 官网frp 的介绍

frp 是一款高性能的反向代理应用,专注于内网穿透。它支持多种协议,包括 TCP/UDP、HTTP/HTTPS 等,提供了加密、压缩,身份认证,代理限速,负载均衡等众多能力。此外,还可以通过 xtcp 实现 P2P 通信。使用 frp,可以安全、便捷地将内网服务暴露到公网,通过拥有公网 IP 的节点进行中转。

frp 采用经典的 C/S 模式,将服务端部署在具有公网 IP 的机器上,客户端部署在内网或防火墙内的机器上,通过访问暴露在服务器上的端口,反向代理到处于内网的服务

frp 架构.excalidraw

2. 配置拥有公网 IP 的服务器

2.1 下载 frp 安装包

首先,查看自己服务器 CPU 的信息,方便后面选择安装包

$ lscpu

CPU Information

根据操作系统(OS)和 CPU 的架构,选择相应的 frp 安装包,

FRP Assets

这里选择 frp_0.53.2_linux_amd64.tar.gz,具体安装包的下载方式根据自己服务器的网络情况而定,

  • 比如,直接在服务器上使用 wget 工具 进行下载

    $ wget https://github.com/fatedier/frp/releases/download/v0.53.2/frp_0.53.2_linux_amd64.tar.gz
    
  • 或者先下载到自己的本机,再通过 scp 工具上传到服务器

    $ scp D:\Users\borne\Downloads\Temp\frp_0.53.2_linux_amd64.tar.gz TC_born:/home/borne
    

frp_0.53.2_linux_amd64.tar.gz 压缩包解压到 /usr/local/ 目录下,得到下列文件

  • frpc/frps:frp 的客户端(client)/ 服务器端(server)程序,需要放到内网服务 / 拥有公网 IP 的机器上;
  • frpc/frps.toml:frp 的客户端程序(frpc)/ 服务器端程序(frps)的配置文件;

frp 文件目录

2.2 配置 frps.toml 文件

通过简单配置 TCP 类型的代理,使用户能够访问内网服务器。

部署 frps 并编辑 frps.toml 文件。以下是简化的配置,其中设置了 frp 服务器用于接收客户端连接的端口:

bindPort = 7000

注:bindPort 可自行设置成其他端口!

如果你使用的云服务商的主机绑定了安全组,需要手动登录服务器的云控制台,在网络安全组中将 7000 端口设置为进站出站的放行策略,才能在后续进行访问,具体过程,详见之前写过的一篇文章《如何开启服务器的自定义端口?》。

2.3 使用 systemd 管理 frp 服务

可以直接通过下面的命令去直接启动 frp 服务器或者客户端

  • 启动 frp 服务器

    $ ./frps -c ./frps.toml
    
  • 启动 frp 客户端

    $ ./frpc -c ./frpc.toml
    

注意:上面这种运行方式,一旦关闭终端相应的 frp 服务就会终止。

所欲对于类似 frp 这种需要在后台长期运行的服务,最好去结合其他工具,比如:systemdsupervisor 进行管理。

使用 systemd 工具来管理 frps 服务,包括启动、停止、配置后台运行和设置开机自启动,大致步骤如下

  1. /etc/systemd/system 目录下创建一个 frps.service 文件,用于配置 frps 服务

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

    写入内容,

    [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.toml
       
    [Install]
    WantedBy = multi-user.target
    
  2. 使用 systemd 命令管理 frps 服务

    # 启动frp
    sudo systemctl start frps
    # 停止frp
    sudo systemctl stop frps
    # 重启frp
    sudo systemctl restart frps
    # 查看frp状态
    sudo systemctl status frps
    
  3. 设置 frps 开机自启动

    $ sudo systemctl enable frps
    

通过上述步骤,可以轻松地使用 systemd 来管理 frps 服务,实现启动停止自动运行开机自启动

systemd 管理 frps 服务

同理,也可以使用 systemd 来管理 frpc 服务,

[Unit]
# 服务名称,可自定义
Description = frp client
After = network.target syslog.target
Wants = network.target

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

[Install]
WantedBy = multi-user.target

3. 配置内网服务所在的机器

为了能够实现内网穿透,仿照前面 frps 的配置(拥有公网 IP 的服务器),同样的需要在内网服务所在的机器上部署 frpc 并编辑 frpc.toml 文件。

3.1 通过 SSH 访问内网机器

假设 frps 所在服务器的公网 IP 地址x.x.x.x。以下是简单的示例配置

serverAddr = "x.x.x.x"
serverPort = 7000

[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000
  • localIPlocalPort配置为需要从公网访问的内网服务的地址和端口,比如:上面 ssh 服务的默认端口是 22
  • remotePort 表示在 frp 服务端监听的端口,访问此端口的流量将被转发到本地服务的相应端口。

注意:服务器端除了 serverPort 需要开放之外,remotePort 也需要服务器的云控制台中进行开放

配置完成后,启动服务端 frps 和 客户端 frpc

  • 启动服务器

    frp server start

  • 启动客户端

    frp client start

  • 启动客户端后,服务器与客户端之间建立了连接

    Establish a connection between frp server and client

使用以下命令通过 SSH 访问内网机器,假设用户名为 test

$ ssh -o Port=6000 test@x.x.x.x

SSH access

3.2 通过 RDP 远程桌面访问内网机器

关于 RDP,百科中有这样一段介绍,

远程桌面协议(英语:Remote Desktop Protocol,缩写:RDP)是一个多通道(multi-channel)的协议,让用户(客户端或称“本地电脑”)连上提供微软终端服务的电脑(服务端或称“远程电脑”)。大部分的 Windows 都有客户端软件。其他操作系统例如 Linux、FreeBSD、Mac OS X,也有对应的客户端软件

由于 RDP 远程桌面访问的通用性,所以下面重点说一下如何基于 frp 实现通过 RDP 远程桌面访问内网机器。

3.2.1 Linux 客户端

对于 Linux,首先在内网机器上通过 netstat 查询,xrdp 服务的 IP 地址和端口号,

xrdp service

然后,同样通过 frp 客户端(frpc)配置文件(frpc.toml),配置 xrdp 服务,

[[proxies]]
name = "xrdp"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3389
remotePort = 6001

注意,对于不同的服务通常需要配置不同的 remotePort,否则会出现错误,

start error: port already used

3.2.2 Windows 客户端

下载针对 Windows 的 frp 客户端(frp_0.53.2_windows_amd64.zip),解压后得到下列文件,

Windows frp directory

同样也是配置 frpc.toml 文件,

[[proxies]]
name = "RDP"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3389
remotePort = 6002

然后,在 Windows Powershell 窗口中运行 frpc 客户端,即可

$ \path\to\frpc.exe -c \path\to\frpc.toml

Start frpc on Windows

和在 Linux 中使用 systemdsupervisor 管理 frp 服务一样,为了方便 frp 后续的使用,在 Windows 中同样也进行类似的处理,将可执行文件打包成系统服务,然后让服务在后台自动运行

在 Windows 中使用 WinSW 来打包服务,大致流程如下,

  1. 获取 WinSW.exeWinSW.zip,然后将其放置到 frp 服务所在目录下,可将其重命名为 WinSW_frpc.exe

    Download WinSW

  2. 在当前目录下,创建 WinSW_frpc.exe配置文件 WinSW_frpc.xml

    <service>
      <id>frpc</id>
      <name>frpc</name>
      <description>frp client</description>
      <executable>frpc.exe</executable>
      <arguments>-c frpc.toml</arguments>
      <onfailure action="restart" delay="60 sec"/>
      <onfailure action="restart" delay="120 sec"/>
      <logmode>reset</logmode>
    </service>
    
  3. 在 Windows Powershell 窗口中运行 WinSW_frpc.exe install [options] 来安装服务

    Install frpc with WinSW

  4. 在 Windows Powershell 窗口中运行 WinSW_frpc.exe start 来启动服务

    Start frpc with WinSW

此时,从 Windows 的服务管理中,可以发现已经能够查找到 frpc 服务,

frpc on Windows service

为了方便文件传输,也可以在 Windows frpc 客户端中配置 ssh 服务,基本原理和前面提到的在 Linux frpc 中配置 ssh 服务类似,但是由于 Windows 的特殊性也有些不同的地方,大致流程如下,具体详见这篇文章

  1. 需要在 Windows 可选功能中添加 OpenSSH 服务器和客户端

    OpenSSH Server and Client

  2. 在 Windows 服务 中设置 OpenSSH Authentication AgentOpenSSH SSH Server 启动类型为自动,并立即启用

    Config OpenSSH on Windows Service

  3. 在 Windows 防火墙对 OpenSSH 进行放行,勾选专用公用

    Config OpenSSH on Windows firewall

    注意:SSH 登录的用户名可以在 C:\Users\ 下去找,密码的话就和通过 RDP 进行访问时用的密码相同。

4. 可能遇到的问题

4.1 查看服务器端口是否成功开放

可以使用 nmap 工具检测服务器端口号,

$ nmap -Pn IP地址 -p 端口号

test server potrt with nmap

也可以使用 telnet 工具

$ telnet IP地址 端口号

假设服务器的 IP 地址是 x.x.x.x ,使用 telnet 测试出现以下内容说明服务器的该端口开放,

Trying x.x.x.x...
Connected to x.x.x.x.
Escape character is '^]'.
Connection closed by foreign host.

注意:不管是 nmap 工具也好,telnet 工具也罢,都只能检测服务器自身(比如:防火墙)对端口的控制,检测不到云服务商的主机绑定的安全组是否开放了端口。对于一台没有配置防火墙的服务器,无论安全组配置如何,用这两个工具检测的任意端口的结果都显示的是开放状态,所以一定别忘了要在安全组也开放相应端口。

4.2 查询内网服务的地址和端口号

比如通过 netstat 查询 ssh 服务的 IP 地址和端口号,

$ netstat -nltp | head -n 2 && netstat -nltp | grep -i ssh

结果如下:

query the address and port number of a service

5. 写在最后

这不快放寒假了吗,想着在家里的时候也能用上学校的机器,于是便有了上面这一系列的折腾,嗯,希望能用上。

分类:

更新时间:

留下评论