Skip to main content

第 9 课:内网穿透 FRP

(一)使用第三方 Saas

Linux 环境下 的配置教程

SakuraFrp 启动器安装 / 使用指南 | SakuraFrp 帮助文档

命令:

sudo bash -c ". <(curl -sSL https://doc.natfrp.com/launcher.sh)"

或者命令:

sudo bash -c ". <(wget -O- https://doc.natfrp.com/launcher.sh)"

这会 安装Docker,并在创建名为 natfrp-service 的容器

同时创建 /etc/natfrp 文件夹用于存储启动器配置文件

如果需要绕过 Docker 检测强制安装到系统中

命令:

sudo bash -c ". <(curl -sSL https://doc.natfrp.com/launcher.sh) direct"

需要输入 SakuraFrp 的 访问密钥 和 远程管理密码


Docker 模式安装成功, 您可使用下面的命令管理服务:

  • 查看日志 docker logs natfrp-service

  • 停止服务 docker stop natfrp-service

  • 启动服务 docker start natfrp-service

如果没有使用docker安装的话,可以使用 systemctl 进行管理

接下来要在服务器上启动这个隧道,我们需要在服务器的浏览器或者局域网内的浏览器访问: https://192.168.124.129:7102

输入上面给出的密码:YeB79U***

进入本地启动器管理界面

============= 启动器连接信息 =============

\> 远程管理模式已开启, 请到管理面板使用远程管理连接

WebUI 端口: 7102

WebUI 密码: YeB79U***
注意:

新版本改用系统服务,您可使用下面的命令管理服务:

  • 查看状态 systemctl status natfrp.service
  • 停止服务 systemctl stop natfrp.service
  • 启动服务 systemctl start natfrp.service
  • 查看日志 journalctl -u natfrp.service
  • 重启服务 systemctl restart natfrp.service

请登录远程管理界面启动隧道: https://www.natfrp.com/remote/v2

6月 29 22:42:19 HeiheServer natfrp-service[10617]: 2025-06-29 22:42:19 Info Service 开始登录, 访问密钥: oowj****xh

使用 https://192.168.124.129:7102 进行连接

如果您使用非内网访问或使用和上面 IP 不通的网络, 请使用 https://%3C访问本机用的IP%3E:7102 进行连接

image-20250629222336413

双击节点来启动

请登录远程管理界面启动隧道: https://www.natfrp.com/remote/v2


由于我们设置了访问秘钥:

image-20250629222517542

因此需要再访问端的浏览器先进行身份验证,以记录访问端 IP地址

image-20250629222422285

现在就可以去连接了:

image-20250629222431566

卸载方式

停用并删除 Unit 文件

systemctl disable --now natfrp.service

rm /etc/systemd/system/natfrp.service

删除用户和 HOME 目录

userdel -r natfrp


(二)自己搭建FRP 服务器端

大部分国内的 FRP 都不支持在美国使用,而且相比于使用第三方 FRP 服务,自己搭建 FRP 服务器的成本要低很多。

本教程将采用亚马逊上购买的 Ubuntu24 LightSail云服务作为参考,我购买了 7刀一个月 的套餐,一个月有 1T 的流量,和3-4Gbps 的带宽。公网IP 为:3.147.53.191。我们将要将其配置为一台 FRP 服务器给其他本地提供内网穿透服务。

image-20250904110722402


第一步:安装 frp

mkdir /home/ubuntu/frp
cd /home/ubuntu/frp

# 获取最新版本
wget https://github.com/fatedier/frp/releases/download/v0.64.0/frp_0.64.0_linux_amd64.tar.gz

# 解压
tar -xzf frp_0.64.0_linux_amd64.tar.gz
mv frp_0.64.0_linux_amd64 frp
cd frp

第二步:编辑配置文件

创建配置文件:

vim frps.ini

填入以下内容(你可以修改端口或 token):

[common]
bind_port = 7000
token = HandsomeHeihe
vhost_http_port = 80
vhost_https_port = 8443
subdomain_host = 3.147.53.191.nip.io

# 仪表盘
dashboard_port = 7500
dashboard_user = Heihe
dashboard_pwd = Cjy65100405
log_file = ./frps.log
log_level = info
log_max_days = 7

之后可以访问 http://3.147.53.191:7500 来查看连接状态。

其中 nip.io 是一个免费、公共的动态 DNS 服务,由 PowerDNS 创始人提供支持。其功能是自动把域名 3.147.53.191.nip.io 解析为 A记录 3.147.53.191,从而省去了手动配置域名解析的麻烦。具体实现功能在后面会看到。


第三步:配置防火墙

确保你的服务器防火墙和 AWS 控制台中开放以下端口:

  • 7000(frpc 连接)
  • 7500(仪表盘访问,可选)
  • 你希望外部映射的其他端口(例如 SSH 的 6000、Web 的 8080 等)

第四步:启动 frps

./frps -c ./frps.ini

第五步:配置为 systemd

我们来写一个开机自启服务:

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

填入以下内容:

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

[Service]
ExecStart=/home/ubuntu/frp/frps -c /home/ubuntu/frp/frps.ini
Restart=on-failure

[Install]
WantedBy=multi-user.target

启动并设置开机自启

sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable frps
sudo systemctl start frps
sudo systemctl status frps

你应该看到状态为 active (running)


第六步:配置nginx

我们在后面需要穿透一个 HTTPS 服务(Docusaurus),但是 FRP 本身是不具备 HTTPS 加密功能的(仪表盘里的 HTTPS 选项 是指对已经部署好的 HTTPS 服务进行穿透)。我们不想在客户端部署 nginx ,因此需要在服务端部署nginx 并进行 SSL 加密。

目标:使用 frp 将本地服务通过 https://notes.heihet09.com 方式安全访问。


1. 域名解析

首先在阿里云上为 notes.heihet09.com 添加了解析指向 3.147.53.191 (A记录)


2. 下载证书

我们的URL 是 notes.heihet09.com,需要先从阿里云下载 证书notes.heihet09.com.keynotes.heihet09.com.pem

将证书文件上传到:

/home/ubuntu/certification/notes.heihet09.com.pem  
/home/ubuntu/certification/notes.heihet09.com.key

3. 安装 Nginx

sudo apt update
sudo apt install nginx -y

查看 Nginx 状态:

sudo systemctl status nginx

4. 站点配置文件

我们来创建 Nginx 的站点配置文件,告诉 Nginx 如何处理 https://notes.heihet09.com 的请求。

sudo vim /etc/nginx/sites-available/notes.heihet09.com

粘贴以下内容:

server {
listen 443 ssl;
server_name notes.heihet09.com;

ssl_certificate /home/ubuntu/certification/notes.heihet09.com.pem;
ssl_certificate_key /home/ubuntu/certification/notes.heihet09.com.key;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
proxy_pass http://127.0.0.1:80; # 此处端口需与你的 frp 对应
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

# 可选:HTTP 重定向到 HTTPS
# server {
# listen 80;
# server_name notes.heihet09.com;
#
# return 301 https://$host$request_uri;
#}

思考:为什么要注释 “HTTP 重定向到 HTTPS” 这一部分?

现在 Nginx 只监听 443 端口发来的 HTTPS 请求,如果访问网址是 notes.heihet09.com,就解码成 HTTP 请求并转发到 本地FRP 服务的 80端口,FRP 服务在把这个HTTP 请求转发到 client 的 4090端口。

但是现在 FRP 也监听 80 端口,比如上面的 http://notes.3.147.53.191.happy.io 实际上是监听 http://notes.3.147.53.191.happy.io:80? 因此如果 Nginx 也监听80端口的话会产生冲突。

sudo nginx -T | grep 'listen 80'

5. 启用站点配置

sudo ln -s /etc/nginx/sites-available/notes.heihet09.com /etc/nginx/sites-enabled/

检查语法是否正确:

sudo nginx -t

如果无错误提示,重启 Nginx:

sudo systemctl reload nginx

后面如果修改了配置文件,需要输入:

systemctl daemon-reload

确认防火墙已放行端口

如果你开启了防火墙(如 UFW),确保放行 443 和 80:

sudo ufw allow 80
sudo ufw allow 443
danger

Nginx 修改配置文件的步骤:

禁用默认站点

sudo rm /etc/nginx/sites-enabled/default

⚠️ 不要删除 /etc/nginx/sites-available/default,我们只移除它的“启用链接”

重启 Nginx

sudo nginx -t
sudo systemctl reload nginx

验证是否还监听 80

sudo lsof -i :80

如果 没有输出,说明端口 80 已空出,frps 就可以成功监听它。


查看所有启用站点配置

ls -l /etc/nginx/sites-enabled/

只保留你写的:

notes.heihet09.com -> ../sites-available/notes.heihet09.com

确保没有其他监听 80 的文件链接。



(三)Win 制作 FRP 客户端

第一步:下载软件

GitHub Releases 下载对应平台版本。解压到桌面

你要在 Windows 上运行一个服务(例如本地网站、远程桌面、SSH、数据库等),通过 frpc 把它映射成:

http://3.147.53.191:<指定端口>

第二步:配置文件

我们有三个服务要穿透:SSH(TCP 22) ,docusaurse(HTTP 4090),docusaurs(HTTPS 4090)

在目录中创建或编辑 frpc.toml 文件:

serverAddr = "3.147.53.191"
serverPort = 7000
auth.token = "HandsomeHeihe"

# 默认 HTTP 应用:映射 http://3.147.53.191/
# [[proxies]]
# name = "http-root"
# type = "http"
# localIP = "127.0.0.1"
# localPort = 4090
# customDomains = ["3.147.53.191"]

# 添加 HTTP 应用方法一:子域名
# 访问URL: http://notes.3.147.53.191.nip.io/
[[proxies]]
name = "Notes"
type = "http"
localIP = "127.0.0.1"
localPort = 4090
subdomain = "Notes"

# 添加 HTTP 应用方法二:自定义域名
# 访问 URL: http://notes.heihet09.com
[[proxies]]
name = "secure-notes"
type = "http"
localIP = "127.0.0.1"
localPort = 4090  
customDomains = ["notes.heihet09.com"]

# 添加 TCP 应用
# SSH 代理:ssh <username>@3.147.53.191 -p 6000
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000

其中的两种添加 HTTP 方法:

  • 添加 HTTP 应用方法一 适合快速搭建网站或者临时访问,因为不需要手动配置域名解析,也不用配置 Nginx 代理。

    如果嫌这个域名太丑,可以配置云解析 CNAME 记录,把另一个域名手动解析成这个。

  • 添加 HTTP 应用方法二 提供了更多自定义的功能。

现在只要配置域名解析 notes.heihet09.com 为 A记录 3.147.53.191,就可以通过 http://notes.heihet09.com 来访问这个服务。具体链路如下:

Client Browser
^
| `http://notes.heihet09.com`
v
域名云解析
^
| 3.147.53.191:80
v
FRPS
^ (接受端口: 80)
| 查找匹配 customDomains["notes.heihet09.com"]
v (输出端口:7000)
FRPC
^ (接受端口:7000)
| 本地 TCP 隧道传输,接收请求
v
Local Docusaurus on 127.0.0.1:4090

也可以加上通过 Nginx 代理成 HTTPS 应用,实现链路如下:

Client Browser
^
| `https://notes.heihet09.com`
v
域名云解析
^
| 3.147.53.191:443
v
Nginx 服务
^ (接受端口: 443)
| 查找匹配 servername["notes.heihet09.com"]
v (输出端口:80)
FRPS
^ (接受端口: 80)
| 查找匹配 customDomains["notes.heihet09.com"]
v (输出端口:7000)
FRPC
^ (接受端口:7000)
| 本地 TCP 隧道传输,接收请求
v
Local Docusaurus on 127.0.0.1:4090

所以厉害就厉害在只要配置一次DNS解析,就可以同时用 HTTP 和 HTTPS 来访问。

而其中的 SSH (TCP)代理的链路就相对简单了:

Client SSH Tool 
|
| TCP 请求 → 3.147.53.191:6000
v
FRPS (Ubuntu, frps.ini)
|
| 查找 remotePort = 6000 的 TCP 代理通道
v
FRPC (Windows)
|
| 隧道传输请求 → 127.0.0.1:22
v
本地 OpenSSH 服务 (Windows)
tip

现在访问 http://notes.heihet09.com 是可以访问的,但不会跳转到 https://notes.heihet09.com

如果发现自动跳转了,是客户端(浏览器)的行为,原因是 HSTS(HTTP Strict Transport Security)缓存生效了

HSTS 是现代浏览器保护用户安全的重要机制,它防止 中间人攻击强行降级到 HTTP,并更容易被搜索引擎捕获到。

当你第一次访问了:

https://notes.heihet09.com

并且服务器返回了如下响应头:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

浏览器就会把这个域名加入 HSTS 列表,在未来 1 年内(31536000 秒)强制将 HTTP 请求升级为 HTTPS,即使你手动输入 http://... 也不行,打开无痕窗口也不行。

在 edge 打开浏览器地址栏输入:(改成 chrome浏览器 就把开始的词改成 chrome)

edge://net-internals/#hsts

Query HSTS/PKP domain 中输入:notes.heihet09.com。点「Query」看看是否存在记录


第三步:启动 frpc 客户端

.\frpc.exe -c frpc.toml

你将看到日志输出:

2025/08/31 03:24:00 [I] [service.go:xxx] login to server success
2025/08/31 03:24:00 [I] [proxy.go:xxx] start proxy [web] success

为了更方便启动,我们制作一个 start.bat,以供一键启动

@echo off
title FRPC Client - Connecting to 3.147.53.191

echo Starting frpc client...
echo ===========================

:: 启动 frpc 并加载配置
.\frpc.exe -c frpc.toml

:: 保持窗口打开,查看输出
echo.
echo ===========================
echo frpc.exe has exited. Press any key to close.
pause >nul

danger

注意 Mac 的浏览器重启不会自动清除历史缓存,这可能导致很多奇奇怪怪的访问不了问题!需要手动清除历史记录 或者 打开无痕窗口!


(四)Ubuntu 制作 FRP 客户端

现在我们将完全复刻相同配置,在 Ubuntu 上部署 FRP 客户端(frpc)

建议目录结构

~/frpc/
├── frpc                  # 可执行文件
├── frpc.toml            # 客户端配置文件
├── run.sh               # 启动脚本

第一步:下载并解压

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

选择适合你系统的版本,例如:

cd ~
wget https://github.com/fatedier/frp/releases/download/v0.64.0/frp_0.64.0_linux_amd64.tar.gz
tar -zxvf frp_0.64.0_linux_amd64.tar.gz
mv ./frp_0.64.0_linux_amd64 ./frpc
cd ~/frpc

第二步:配置文件

编辑配置文件:

vim ~/frpc/frpc.toml

粘贴以下内容(和之前 Windows 的完全一致):

serverAddr = "3.147.53.191"
serverPort = 7000
auth.token = "HandsomeHeihe"

# SSH 代理:3.147.53.191:6001 -> 本地 22
[[proxies]]
name = "ssh-WSL"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6001

注意要修改 Ubuntu 的这个 SSH 代理的名字或端口,不能再通之前的 “ssh",而要用 ”ssh-WSL“,否则会报错:

2025-10-04 19:10:11.778 [W] [client/control.go:170] [b77bb0c65558d9eb] [ssh] start error: proxy [ssh] already exists

第三步:启动脚本

vim ~/frpc/run.sh

填入以下内容:

#!/bin/bash
cd "$(dirname "$0")"
./frpc -c frpc.toml

添加执行权限:

chmod +x run.sh

第四步:启动 FRP 客户端

cd ~/frpc
./run.sh

如果一切顺利,你应该看到日志输出:

2025/09/05 ... [I] [proxy.go:...] start proxy [Notes] success
2025/09/05 ... [I] [proxy.go:...] start proxy [secure-notes] success
2025/09/05 ... [I] [proxy.go:...] start proxy [ssh] success

第五步:配置为系统服务

sudo vim /etc/systemd/system/frpc.service

填入以下内容(请根据你的实际路径修改):

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

[Service]
Type=simple
User=your-username
WorkingDirectory=/home/your-username/frpc
ExecStart=/home/your-username/frpc/frpc -c /home/your-username/frpc/frpc.toml
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target

重新加载 systemd 配置

sudo systemctl daemon-reexec
sudo systemctl daemon-reload

启动 frpc 服务

sudo systemctl start frpc
sudo systemctl enable frpc
sudo systemctl status frpc

(五)Mac 制作 FRP 客户端

步骤和 Linux 的完全一样,就是用的版本是

frp_0.54.0_darwin_arm64.tar.gz

(六)FRP 的原理

从功能上来讲, FRP 本身就是一种端口映射。把 外网服务器的某个端口 映射到 内网服务器上的某个端口,从而实现公网访问局域网内容的功能。

那么FRP具体是怎么实现的呢?举个例子,在 POST 请求或者 GET请求中,我们都必须要知道目标的IP地址,才能知道往哪里发送数据。现在FRP客户端在内网,他当然可以把数据发送给有公网IP的 FRP 服务器,但是 FRP服务器怎么把数据发送给没有公网 IP 的客户端呢?

FRP 本质上是“长连接 + 虚拟隧道 + 多路复用

它并不是依赖一次一次的 HTTP 请求目标 IP,而是 靠“客户端主动连接服务器,保持长连接”来实现穿透的

角色所在网络功能
frps(FRP Server)公网服务器,有公网 IP等待客户端连接;接收来自浏览器的访问请求
frpc(FRP Client)内网机器,无公网 IP主动连接 frps,保持通道;将请求数据转发到本地应用
tip

在上面服务器端的配置文件是:

[common]
bind_port = 7000
token = HandsomeHeihe
vhost_http_port = 80
vhost_https_port = 8443
subdomain_host = 3.147.53.191.nip.io

# 仪表盘
dashboard_port = 7500
dashboard_user = Heihe
dashboard_pwd = Cjy65100405
log_file = ./frps.log
log_level = info
log_max_days = 7

思考:bind_portvhost_http_port 有什么区别?为什么用 bind_port 来和 client 通信,用 vhost_http_port 来监听网络请求?

配置项用途方向谁连接谁
bind_portfrpc 客户端连接 frps 服务器的端口(控制连接)客户端 → 服务器frpc 主动连接 frps:7000
vhost_http_portfrps 对外暴露的 HTTP 请求端口(用户访问入口)用户浏览器 → 服务器用户访问 frps:80
vhost_https_portfrps 对外暴露的 HTTPS 请求端口(用户访问入口)用户浏览器 → 服务器用户访问 frps:8443

因为 “通信的主动方向” 不同,因此功能不能互换

行为谁主动发起?谁被动等待?
客户端上线连接服务器(控制连接)frpcfrps
浏览器访问网页浏览器frps

(七)实战:在无 sudo 权限下安装

有一台Ubuntu服务器,但是处于校园局域网中,必须使用 RVPN 连接,而且我们没有 sudo 权限,该如何安装 FRPC 呢?

步骤一:检查防火墙连接

我们首先要测试防火墙是否开启。

在非 sudo 情况下,我们没有办法使用命令 ufw status 来检查防火墙状况,因此需要手动端口探测。

9780 端口为例,首先在服务器 启动一个监听服务(你有权限的前提下)

python3 -m http.server 9780

然后在本地先连接上 RVPN,测试内网连接

curl http://130.126.208.85:9780/

输出

<!DOCTYPE HTML> <html lang="en"> <head> <meta charset="utf-8"> <title>Directory listing for /</title> </head> <body> <h1>Directory listing for /</h1> <hr> <ul> <li><a href=".bash_history">.bash_history</a></li> <li><a href=".bash_logout">.bash_logout</a></li> <li><a href=".bashrc">.bashrc</a></li> <li><a href=".cache/">.cache/</a></li> <li><a href=".codeium/">.codeium/</a></li> <li><a href=".conda/">.conda/</a></li> <li><a href=".local/">.local/</a></li> <li><a href=".nv/">.nv/</a></li> <li><a href=".profile">.profile</a></li> <li><a href=".python_history">.python_history</a></li> <li><a href=".ssh/">.ssh/</a></li> <li><a href=".windsurf-server/">.windsurf-server/</a></li> <li><a href="complex_policy/">complex_policy/</a></li> <li><a href="miniconda3/">miniconda3/</a></li> <li><a href="snap/">snap/</a></li> </ul> <hr> </body> </html>

说明端口连接成功,也说明防火墙处于开放状态


步骤二: 安装FRPC

和之前 Linux 相同的安装方法,不需要 sudo 权限。

连接名称为 4090-SSH,使用公网服务器端口 6002


步骤三:Nohup 后台进程

现在没有 sudo ,无法安装 screen 工具,因此要让 /home/chenjiayang/frpc/run.sh 成为断开 SSH 后仍运行的常驻后台进程,需要使用 原生工具 nohup

nohup /home/chenjiayang/frpc/run.sh > ~/frpc.log 2>&1 &
  • nohup 让进程在 断开 SSH 后仍运行

  • & 让它在后台运行

  • 输出会写入 ~/frpc.log,你可以随时查看状态:

    tail -f ~/frpc.log
    

注意:

  • 启动前确认 run.sh 文件第一行是 #!/bin/bash,并 chmod +x
  • 如果脚本中使用了 read 等等待交互的语句,会卡住。需要改为非交互式脚本