原创

使用FRP实现内网穿透:通过公网访问树莓派上的服务

温馨提示:
本文最后更新于 2024年07月13日,已超过 280 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

 

一台外网可以访问的固定IP的云服务器,Ubuntu系统

一台外网不能访问的树莓派,Ubuntu系统

现在将云服务器搭建成一台内网穿透服务器,可以通过云服务器访问到树莓派上部署的软件。

1.简介

FRP(Fast Reverse Proxy)是一个开源的内网穿透工具,主要用于在网络受限的环境中,使外部网络可以访问内部网络中的服务。FRP 支持多种协议,包括 HTTP、HTTPS、TCP 和 UDP,并且可以实现动态域名解析和负载均衡等功能。

FRP 主要包含两部分:

  • frps(server): 这是运行在公共网络上的服务器端程序,负责监听来自客户端的连接请求,并将这些请求转发到正确的内部服务器。
  • frpc(client): 这是运行在内网中的客户端程序,它会与 frps 建立连接并将本地的服务暴露给公网。

FRP 的工作流程大致如下:

  1. 内网中的 frpc 客户端与公网上的 frps 服务器建立连接。
  2. frpc 向 frps 注册服务,并告知其内网服务的地址和端口。
  3. frps 将此信息保存并为该服务生成一个可从公网访问的地址。
  4. 当外部客户端尝试访问这个公网地址时,frps 会将请求转发到相应的内网服务上。
  5. 内网服务响应后,frps 再将响应数据传回给外部客户端。

FRP 提供了多种配置选项,可以根据不同的需求进行定制,比如 SSL 加密、多用户支持、动态域名解析等。

2.安装

FRP的下载地址:https://github.com/fatedier/frp/releases

2.1服务端安装

云服务器放行端口

  • FRP服务端口:7000(可自定义)
  • FRP控制面板端口:7500(可自定义)

云服务器操作系统也要放行端口,这里直接将防火墙关闭

systemctl stop ufw
systemctl disable ufw

在云服务器执行以下命令

# 解压
tar -zxvf frp_0.59.0_linux_amd64.tar.gz
# 进入目录
cd frp_0.59.0_linux_amd64

frps.toml配置

# frp服务的特定端口,防火墙也需放开该端口
bindPort = 7000
 
# 服务面板可查看frp服务状态信息
# 后台管理地址,默认是127.0.0.1,如果是公网访问则改成0.0.0.0
webServer.addr = "0.0.0.0"
# 后台管理端口
webServer.port = 7500
# (可选)后台登录用户名
webServer.user = "admin"
# (可选)后台登录密码
webServer.password = "admin"

# 服务端将只接受 TLS链接
transport.tls.force = true
# 客户端访问验证方式
auth.method = 'token'
# 客户端访问验证密码,frpc要与frps一致
auth.token = "12345"

做成service服务,方便管理,frps.service内容

[Unit]
Description=frp server service
After=network.target

[Service]
Type=simple
ExecStart=/opt/frp_0.59.0_linux_amd64/frps -c /opt/frp_0.59.0_linux_amd64/frps.toml
Restart=always
RestartSec=30


[Install]
WantedBy=multi-user.target

执行以下命令,创建frps.service服务,并开机自启

cp frps.service /etc/systemd/system/
sudo systemctl start frps
sudo systemctl enable frps

浏览器输入http://云服务器IP:端口,如http://47.108.106.40:7500/。输入用户名和密码,如admin/admin,可以查看连接状态。

2.2客户端安装

树莓派关闭防火墙

systemctl stop ufw

在树莓派执行以下命令安装

# 解压
tar -zxvf frp_0.59.0_linux_arm64.tar.gz
# 进入目录
cd frp_0.59.0_linux_arm64

frpc.toml配置

transport.tls.enable = true
# 服务端ip
serverAddr = "47.108.106.40"
# 服务端端口
serverPort = 7000
# 客户端访问验证方式
auth.method = 'token'
# 客户端访问验证密码
auth.token = '12345'
 
[[proxies]]
name = "web-http"
type = "tcp"
# 需要暴露的服务的IP
localIP = "127.0.0.1"
# 将本地8443端口的服务暴露在公网的8888端口
localPort = 8443
remotePort = 8888
 
[[proxies]]
name = "admin-http"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8085
remotePort = 8889

[[proxies]]
name = "file-http"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8088
remotePort = 8890

[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 2222

做成service服务,方便管理,frpc.service内容

[Unit]
Description=frp client service
After=network.target

[Service]
Type=simple
ExecStart=/opt/frp_0.59.0_linux_arm64/frpc -c /opt/frp_0.59.0_linux_arm64/frpc.toml
Restart=always
RestartSec=30


[Install]
WantedBy=multi-user.target

执行以下命令,创建frpc.service服务,并开机自启

cp frpc.service /etc/systemd/system/
sudo systemctl start frpc
sudo systemctl enable frpc

3.其他

3.1用户真实IP

在使用FRP进行内网穿透时,由于请求经过FRP服务器转发,后端服务获取到的用户IP通常是127.0.0.1(即FRP服务器的本地地址),而不是用户的真实IP。为了解决这个问题,可以通过Nginx自定义HTTP头来存储和传递用户的真实IP,从而让后端服务能够正确获取到用户的真实IP地址。

实现步骤:

  1. 在Nginx中配置自定义HTTP头
    在Nginx的配置文件中,通过
    proxy_set_header指令将用户的真实IP($remote_addr)存储到一个自定义的HTTP头中(例如CT-Real-IP),然后将该头信息传递给后端服务。
location / {
    # 其他配置项
    ...

    # 将用户真实IP存储到自定义HTTP头CT-Real-IP中
    proxy_set_header CT-Real-IP $remote_addr;
}
  1. 后端服务获取真实IP
    后端服务需要从HTTP请求头中读取
    CT-Real-IP字段,以获取用户的真实IP。
String realIp = request.getHeader("CT-Real-IP");
正文到此结束
本文目录