弃用花生壳,改用frp实现内网穿透,好自由!

5,316 阅读8分钟

1、痛点

内网穿透对我来说,挺重要的,最开始我是使用的 灵曜这款产品做的穿透,但是挺局限 体验也不好,后来换成技术很成熟的花生壳,开始也还不错,但是很多东西他都是收费,而且是按功能点收费(这真的很蛋疼。。。。),其中端口开放的特别少只有2个: image.png ,我想暴露其他端口的话,只能是通过ssh做端口映射,对此我还写了个端口映射的脚本,每次使用起来挺不方便,而且都在ssh隧道内做的操作,速度上也一般。这里备份下端口映射的脚本:

路径:.ssh/config

Host xzll_suzhuji
    HostName 97xcxxxxx.mmcp.fun
    User root
    Port 44170
    ControlMaster auto
    ControlPath ~/.ssh/control-%r@%h:%p
    ControlPersist yes
    ServerAliveInterval 60
    ServerAliveCountMax 3
    

路径:/Users/hzz/我的linux服务器/tunnel

#!/bin/bash

# 检测是否存在已有的 ssh 进程
echo "正在检查是否存在 SSH 进程..."
SSH_PID=$(pgrep -f "ssh -fN")

if [ -n "$SSH_PID" ]; then
    echo "检测到 SSH 进程 (PID: $SSH_PID),正在终止..."
    kill -9 $SSH_PID
    echo "SSH 进程已终止。"
else
    echo "没有检测到现有的 SSH 进程。"
fi

# 创建主连接
echo "正在创建主连接..."
ssh -fN xzll_suzhuji
if [ $? -eq 0 ]; then
    echo "主连接已创建成功。"
else
    echo "主连接创建失败!"
    exit 1
fi


# 定义目标主机 IP 地址常量
TARGET_HOST_134="192.168.122.139" # 对应vm04

TARGET_HOST_136=192.168.122.136 # 对应vm06
TARGET_HOST_137=192.168.122.137 # 对应vm07
TARGET_HOST_138=192.168.122.138 # 对应vm08

# 定义隧道信息(名称和端口)
tunnels=(

    # 哨兵端口映射
    "Redis 哨兵隧道 (26379):26379:${TARGET_HOST_136}:26379"
    "Redis 哨兵隧道 (36379):36379:${TARGET_HOST_137}:36379"
    "Redis 哨兵隧道 (46379):46379:${TARGET_HOST_138}:46379"

    "Redis 隧道 (6379):6379:${TARGET_HOST_136}:6379"
    "Redis 隧道 (6380):6380:${TARGET_HOST_137}:6380"
    "Redis 隧道 (6381):6381:${TARGET_HOST_138}:6381"

    # 物理机隧道
    "宝塔 隧道 (14270):18888:localhost:14270"

     # 136 的隧道(前缀 1)
    #"Redis 隧道 (16379):16379:${TARGET_HOST_136}:6379"

    "Jenkins 隧道 (18079):18079:${TARGET_HOST_136}:8079"
    "IM 长连接 隧道 (10001):10001:${TARGET_HOST_136}:10001"
    

    "MySQL 隧道 (13306):13306:${TARGET_HOST_136}:3306"
    "CK http 隧道 (18123):18123:${TARGET_HOST_136}:8123"
    "CK tcp 端口 隧道 (19000):19000:${TARGET_HOST_136}:9000"
    "nacos 隧道 (18848):18848:${TARGET_HOST_136}:8848"
    "zk server 隧道 (12181):12181:${TARGET_HOST_136}:2181"

    "rocketmq 控制台 隧道 (18080):18080:${TARGET_HOST_136}:8080"
    "rocketmq server 隧道 (19876):19876:${TARGET_HOST_136}:9876"
    "rocketmq broker 隧道 (10909):10909:${TARGET_HOST_136}:10909"
    "rocketmq broker 隧道 (10911):10911:${TARGET_HOST_136}:10911"

    # 137 的隧道(前缀 2)
    
    # "rocketmq broker 隧道 (20909):20909:${TARGET_HOST_137}:10909"
    # "rocketmq broker 隧道 (20911):20911:${TARGET_HOST_137}:10911"
    # "rocketmq server 隧道 (29876):29876:${TARGET_HOST_137}:9876"

    #"Redis 隧道 (26379):26379:${TARGET_HOST_137}:6379"
    "MySQL 隧道 (23306):23306:${TARGET_HOST_137}:3306"
    "CK http 隧道 (28123):28123:${TARGET_HOST_137}:8123"
    "CK tcp 端口 隧道 (29000):29000:${TARGET_HOST_137}:9000"
    "elasticsearch 隧道 (29200):29200:${TARGET_HOST_137}:9200"
    "zk server 隧道 (22181):22181:${TARGET_HOST_137}:2181"
   

    # 138 的隧道(前缀 3)
    
    # "rocketmq server 隧道 (39876):39876:${TARGET_HOST_138}:9876"
    # "MySQL 隧道 (33306):33306:${TARGET_HOST_138}:3306"
    # "CK http 隧道 (38123):38123:${TARGET_HOST_138}:8123"
    # "CK tcp 端口 隧道 (39000):39000:${TARGET_HOST_138}:9000"
    # "rocketmq broker 隧道 (30909):30909:${TARGET_HOST_138}:10909"
    # "rocketmq broker 隧道 (30911):30911:${TARGET_HOST_138}:10911"

    # "Redis 隧道 (36379):36379:${TARGET_HOST_138}:6379"
    "zk server 隧道 (32181):32181:${TARGET_HOST_138}:2181"
    "elasticsearch 隧道 (39200):39200:${TARGET_HOST_138}:9200"
    "kabana 隧道 (35601):35601:${TARGET_HOST_138}:5601"

    # "rocketmq 控制台 隧道 (38080):38080:${TARGET_HOST_138}:8080"
    # "rocketmq server 隧道 (39876):9876:${TARGET_HOST_138}:9876"
    # "rocketmq broker 隧道 (30909):10909:${TARGET_HOST_138}:10909"
    # "rocketmq broker 隧道 (30911):10911:${TARGET_HOST_138}:10911"
)

# 循环创建隧道
for tunnel_info in "${tunnels[@]}"; do
    tunnel_name="${tunnel_info%%:*}" # 获取隧道名称
    tunnel="${tunnel_info#*:}"       # 获取隧道端口信息

    echo "正在打开 ${tunnel_name}..."
    ssh -fN -L $tunnel xzll_suzhuji
    if [ $? -eq 0 ]; then
        echo "${tunnel_name} 已成功打开。"
        lsof -iTCP:$(echo $tunnel | cut -d':' -f1) -sTCP:LISTEN
    else
        echo "${tunnel_name} 打开失败!"
    fi
    echo ""
done

echo "所有隧道已成功打开。"

2、使用frp做内网穿透,自由清新!

为了减少带来的麻烦,我调研了一款工具即:frp ,用下来以后,我发现这工具挺爽的,很自由,速度也还行(当然取决于公网服务器的带宽,反正暂时对我来说够用了)

2.1、什么是frp?

FRP(Fast Reverse Proxy)是一个高性能的反向代理应用,旨在解决内网穿透的问题。它通常用于将内网的服务暴露到外网,尤其适用于无法直接访问的内网环境。FRP 可以在一台公网服务器上运行,通过该服务器的代理功能,访问被防火墙、NAT 等限制的内网服务。

FRP 的工作原理:

FRP 通过客户端(frpc)和服务器端(frps)的配合工作,将内网中的服务通过公网暴露出来。基本原理是:

  1. FRP 服务器端(frps :部署在公网的服务器上,负责监听来自客户端的请求并转发到对应的内网服务。
  2. FRP 客户端(frpc :部署在内网的机器上,负责将内网服务的流量转发到 FRP 服务器。它会主动连接到 FRP 服务器,并维持一个长连接。

核心功能:

  1. 内网穿透:FRP 能够通过公网服务器使内网的服务可以在外网访问。比如,内网中有一个 Web 服务,FRP 可以将它暴露到公网。
  2. 反向代理:FRP 允许外部访问内网服务,客户端和服务器端之间建立反向代理通道。
  3. 支持多种协议:FRP 支持 HTTP、HTTPS、TCP、UDP 等多种协议,可以将多种类型的内网服务暴露到外网。
  4. 负载均衡:支持多个 FRP 客户端同时连接到 FRP 服务器,从而实现负载均衡。
  5. 访问控制:FRP 可以配置访问控制规则,限制只有特定的客户端可以访问暴露的服务。

常见用法:

  1. 将内网 Web 服务暴露到外网:如果你有一个内网的 Web 服务,可以使用 FRP 将它暴露给外网用户访问。
  2. 访问内网数据库:通过 FRP,你可以将内网的数据库服务暴露到外网,这样就可以远程访问内网数据库了。
  3. 远程桌面:FRP 可以将内网的桌面应用或者 RDP 服务暴露到外网,方便远程操作。
  4. 物联网设备访问:将内网中的物联网设备的服务暴露到公网,方便远程控制或监控。

FRP 组件:

  • frps:FRP 服务器端,部署在公网服务器上,负责监听来自客户端的请求,并将请求转发到对应的内网服务。
  • frpc:FRP 客户端,部署在内网主机上,负责连接到 frps 服务器,并将本地服务暴露到公网。

2.2、使用frp

首先我有以下2个硬件资源

  • 有4个内网机器(1物理机3虚拟机),
  • 有1个华为云公网服务器

想要通过frp做内网穿透的话,基本思路就是:通过在华为云服务器部署 frps即服务端,在内网机器上部署frpc即客户端,然后再公网管理端开启对应的端口即可 。下边做个记录:

下载frp的tar.gz 包

frp_0.61.1_linux_amd64.tar.gz 之后上传到华为云公网和你要穿透的内网服务器上并解压。

配置frps.ini(服务端即公网)文件

image.png

配置frpc.ini(客户端即内网)文件

这个是物理机的,只开放22端口即可,因为他不部署中间件和应用程序: image.png

下边是虚拟机vm06的实例配置:


# vm06的frpc.ini配置:
[common]
#华为云公网ip
server_addr = x.x.x.x
server_port = 7000            

# 映射内网的 10001 端口到公网服务器的 10001 端口
[vm06_rocketmq_console]
type = tcp                     
local_ip = 127.0.0.1           
local_port = 8080             
remote_port = 8080   

#华为云公网ip
custom_domains = ["x.x.x.x"]

[vm06_im长连接]
type = tcp                     
local_ip = 127.0.0.1           
local_port = 10001             
remote_port = 10001   

# 映射内网的 8843 端口到公网服务器的 8843 端口
[vm06_nacos]
type = tcp                     
local_ip = 127.0.0.1           
local_port = 8848             
remote_port = 8848      

[vm06_redis]
type = tcp                     
local_ip = 127.0.0.1           
local_port = 6379              
remote_port = 6379

[vm06_zookeeper]
type = tcp                     
local_ip = 127.0.0.1           
local_port = 2181              
remote_port = 2181

[vm06_redis-sentinel]
type = tcp                     
local_ip = 127.0.0.1           
local_port = 26379              
remote_port = 26379

[vm06_mysql]
type = tcp                     
local_ip = 127.0.0.1           
local_port = 3306              
remote_port = 13306

[vm06_ssh]
type = tcp                     
local_ip = 127.0.0.1           
local_port = 22              
remote_port = 2226   

[vm06_jenkins]
type = tcp                     
local_ip = 127.0.0.1           
local_port = 8079             
remote_port = 8079  

[vm06_flink_ui]
type = tcp                     
local_ip = 127.0.0.1           
local_port = 8078             
remote_port = 8078  

其余的机器也是类似,就不贴了。总之你需要暴露哪些,就往frpc.ini文件加就好了。

现在frps.ini和 frpc.ini都配好了,接下来就是启动,首先我们启动华为云上的服务端,我可以直接在frp安装目录执行:

./frps -c frps.ini 

命令启动frps服务端,启动成功后,可以在内网机器上 通过

./frpc -c frpc.ini 

启动客户端,但是这样的话不算很好管理,一般我喜欢将其使用system管理,以达到方便启动和开机自启的效果,如下:

在华为云上执行:

sudo vim /etc/systemd/system/frps.service 
# 然后加入以下内容

[Unit]
Description=FRP server Service
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/home/frp/frp_0.61.0_linux_amd64
ExecStart=/home/frp/frp_0.61.0_linux_amd64/frps -c /home/frp/frp_0.61.0_linux_amd64/frps.ini
Restart=on-failure
RestartSec=5s
StandardOutput=append:/home/frp/frps.log
StandardError=append:/home/frp/frps_error.log

[Install]
WantedBy=multi-user.target

然后再在内网服务器执行: sudo vim /etc/systemd/system/frpc.service

加入以下内容:

[Unit]
Description=FRP Client Service
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/home/hzz/frp/frp_0.61.0_linux_amd64
ExecStart=/home/hzz/frp/frp_0.61.0_linux_amd64/frpc -c /home/hzz/frp/frp_0.61.0_linux_amd64/frpc.ini
Restart=on-failure
RestartSec=5s
StandardOutput=append:/home/hzz/frp/frpc.log
StandardError=append:/home/hzz/frp/frpc_error.log

[Install]
WantedBy=multi-user.target
#执行以下命令,重新加载 `systemd` 配置:
sudo systemctl daemon-reload

#设置开机自启动
sudo systemctl enable frpc
sudo systemctl enable frps

#启动
sudo systemctl start frpc
sudo systemctl start frps

#查看启动情况
sudo systemctl status frpc
sudo systemctl status frps

3、查看控制台可观察情况:

在frps和frpc都启动后,访问frps的管理端,可以看到对应端口的转发情况,如下: image.png

随便访问一个,验证下: image.png

frp用了一段时间了,反正我感觉是挺爽的,很自由,需要暴露哪些就加哪些端口就ok了。