脱敏说明
本文中的 IP、端口、账号、密码、Token 均为占位示例,实际使用时请替换为你自己的值。
一、业务场景
手上有一台带公网 IP 的云服务器,以及若干台没有公网 IP、只能在内网访问的机器,需要把内网里的服务暴露到公网。
装备情况:
- 一台云服务器(示例为 Windows Server 2012),带公网 IP;
- 三台内网服务器,其中两台 Windows Server,一台 CentOS;
- 一个一级域名,已解析到该公网 IP。
需求:
- 通过域名或 IP 访问三台内网机器上部署的
http服务; - 通过域名或 IP 连接这三台机器的远程桌面(RDP)或
SSH。
二、为什么选择 frp
- 开源,维护频繁;
- 支持 TCP、UDP、HTTP、HTTPS、STCP 等协议;
- Go 语言编写,占用内存小,代理稳定;
- 配置简单,支持自定义插件,也方便按业务需求二次开发;
- 提供安全暴露内网服务、加密与压缩、底层通信可选 kcp、端口复用、负载均衡、健康检查、URL 路由、范围端口映射、请求 header 处理等能力。
frp 还提供了一个浏览器端的状态与统计面板,即代理服务器上的可视化仪表盘。
仪表盘总览(查看各代理状态、代理统计信息):
在线改配置(查看各穿透状态、动态在线配置、热更新配置):
三、服务端 frps 配置
1. 开放云服务器的端口
登录云服务平台,进入实例安全组,开放穿透代理需要的端口。示例规划如下:
| 协议 | 端口 | 用途 |
|---|---|---|
| TCP | 7000 | frp 服务端默认通信端口 |
| TCP | 7001 - 7010 | 代理内网 TCP 应用,端口不够用时可继续往后延伸 |
| TCP | 7080 / 7443 | HTTP 与 HTTPS 代理。云服务器的 80、443 已被其他应用占用,取带 80、443 后缀的名字方便记忆 |
| UDP | 7001 | 如需点对点内网穿透可开启 |
| TCP | 7500 | frp 仪表盘(可选) |
以上规划并非硬性要求,可按需自定义。
2. 下载 frp
进入 frp Releases,下载对应云服务器操作系统与架构的压缩包。
3. 配置 frps
解压后,服务端只需要 frps.toml;frpc 开头的文件是给内网机器用的,服务端用不到。
frps.toml 示例:
[common]
# 监听地址及通信端口
bind_addr = 0.0.0.0
bind_port = 7000
# 默认的 UDP 端口
bind_udp_port = 7001
# HTTP / HTTPS 代理端口,两者可以设成同一个端口
vhost_http_port = 7080
vhost_https_port = 7443
# 仪表盘监听地址与端口。dashboard_addr 不设置时默认与 bind_addr 相同;
# dashboard_port 不设置则不开启仪表盘服务。
dashboard_addr = 0.0.0.0
dashboard_port = 7500
# 仪表盘登录账号与密码,不设置时默认都是 admin,务必修改
dashboard_user = <your_dashboard_user>
dashboard_pwd = <your_dashboard_password>
# 云服务器使用的域名,方便用子域名方式访问各个被代理出去的服务
subdomain_host = example.com
# 鉴权 Token,建议用足够长的随机字符串,frpc 侧需保持一致
token = <your_frp_token>
# 日志
log_file = ./logs/frps.log
# 日志级别:trace / debug / info / warn / error
log_level = info
# 日志保留天数
log_max_days = 7
4. 启动 frps
./frps -c ./frps.toml
5. 配成系统服务
Linux 系统的 frp 压缩包内自带 systemd 目录,里面是现成的 service 文件,可直接参考。
四、客户端 frpc 配置
1. 下载 frp
同样从 frp Releases 下载对应内网机器系统的版本。
2. 配置 frpc
解压后只用到 frpc.toml;frps 开头的文件内网机器用不到。
frpc.toml 示例:
# 服务端地址(填公网 IP 或域名)
serverAddr = "<your_server_ip_or_domain>"
# 服务端通信端口
serverPort = 7000
# 传输协议
transport.protocol = "tcp"
# 鉴权方式
auth.method = "token"
# 与服务端配置保持一致
auth.token = "<your_frp_token>"
# ===== SSH:公网 <ssh_remote_port> -> 本机 22 =====
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = <ssh_remote_port>
# ===== 游戏服务器(以 Java 版 Minecraft 为例):公网 25565 -> 本机 25565 =====
[[proxies]]
name = "game-tcp"
type = "tcp"
localIP = "127.0.0.1"
localPort = 25565
remotePort = 25565
[[proxies]]
name = "game-udp"
type = "udp"
localIP = "127.0.0.1"
localPort = 25565
remotePort = 25565
# ===== 远程桌面 xrdp:公网 <rdp_remote_port> -> 本机 3389 =====
[[proxies]]
name = "rdp"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3389
remotePort = <rdp_remote_port>
# ===== 远程桌面 GNOME:公网 <rdp_gnome_remote_port> -> 本机 3390 =====
[[proxies]]
name = "rdp-gnome"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3390
remotePort = <rdp_gnome_remote_port>
3. 启动 frpc
./frpc -c ./frpc.toml
启动成功后就可以从公网测试穿透出去的 SSH、RDP 和 Web 服务。
4. 配成系统服务
与配置 frps 为系统服务同理,不再赘述。
五、HTTPS 配置
把穿透出去的 HTTP 服务变成 HTTPS,主要有两种思路:
- 用 frpc 的
https2http插件在本地直接启用 HTTPS。配置简单、可控,但如果要代理的 HTTPS 服务很多,就得为每个服务单独生成并配置证书,比较繁琐。 - 在公网服务器上申请泛域名证书,配 Nginx 反向代理转发到穿透出来的 Web 服务。
本文采用第二种方案。
六、连接方式
先约定几个占位符,后文命令都复用它们:
| 占位符 | 含义 |
|---|---|
<public_ip> |
云服务器的公网 IP,如 203.0.113.10(RFC 5737 文档保留地址) |
<intranet_ip> |
校内/内网直连地址,如 192.168.1.100 |
<ssh_port> |
frp 映射出来的 SSH 端口 |
<rdp_port> |
frp 映射出来的 RDP 端口 |
<user> |
登录用的服务器账号 |
<password> |
登录密码(仅在提示时手动输入,不要落盘) |
方式 1:终端命令行连接
适合快速查看系统状态、跑点简单命令。
打开本地终端
- Windows:按
Win + R,输入powershell或cmd回车; - macOS / Linux:打开自带的 Terminal。
- Windows:按
执行连接命令
# 走公网入口 ssh -p <ssh_port> <user>@<public_ip> # 备用:校内网络下可直连内网地址 ssh -p <ssh_port> <user>@<intranet_ip>输入密码
- 提示
password:时输入你的服务器密码。 - Linux 终端下输入密码不会显示任何字符或星号(光标不动),这是正常的,直接盲敲完回车即可。
- 提示
方式 2:VS Code 远程连接(推荐)
在服务器上跑代码、调试项目时,用 VS Code 最顺手:本地编辑远程代码,用远程的环境运行调试,体验和本地开发一致。
本地安装 Visual Studio Code,在扩展市场安装 Remote - SSH 插件。
配置 SSH 配置文件
在 VS Code 中按
F1(或Ctrl + Shift + P),输入并选择Remote-SSH: Open SSH Configuration File...;选择第一项(通常是
C:\Users\你的用户名\.ssh\config);在文件末尾追加并保存:
Host myserver HostName <public_ip> Port <ssh_port> User <user> ServerAliveInterval 60 # 每 60 秒发一次心跳,防止空闲掉线 ServerAliveCountMax 3
发起连接
- 点击 VS Code 左下角的远程连接图标(
><),或按F1选择Remote-SSH: Connect to Host...; - 在列表中点击
myserver; - 按提示选择服务器平台(Linux);
- 输入密码并回车;
- 连接成功后,从「资源管理器 -> 打开文件夹」选择项目目录即可开始开发。
- 点击 VS Code 左下角的远程连接图标(
方式 3:Windows 图形化远程桌面(RDP)
需要图形界面时,用 Windows 自带的「远程桌面连接」。
⚠️ 同一时间同一账户只能有一人控制。 多人共用同一账号时,同时进图形化桌面会互相抢鼠标。建议日常跑代码优先用 VS Code SSH,互不影响。
- 按
Win + R输入mstsc.exe回车。 - 在「远程桌面连接」窗口中:
- 计算机:填
<public_ip>(若 RDP 映射了非默认端口,填<public_ip>:<rdp_port>); - 用户名:填
<user>。
- 计算机:填
- 点「连接」,在密码框中输入密码即可进入图形化桌面。
七、常见问题
Q1:突然连接超时 / 提示连接失败?
- 先核对公网 IP 和映射端口是否发生了变更;
- 如果 IP 或端口改过了,记得同步修改本地 VS Code SSH 配置里的
HostName和Port。
Q2:长时间运行的任务怕断网中断?
SSH 或 VS Code 里跑耗时较长的脚本(如模型训练),关电脑、断网都会导致任务终止。建议用 tmux 把任务挂到后台:
# 1. 创建并进入一个名为 train_task 的后台会话
tmux new -s train_task
# 2. 在会话中启动脚本
python train.py
# 3. 暂时离开:先按 Ctrl + B,松开后再按 D(任务仍在后台跑)
# 4. 下次连上服务器后,重新接回该会话
tmux a -t train_task
Q3:提示 Host key verification failed?
内网穿透经常更换公网服务器或重装系统,本地记录的旧指纹与新节点对不上就会报这个错。在本地终端清理旧指纹后重连:
ssh-keygen -R [<public_ip>]:<ssh_port>
Q4:如何使用 SSH 密钥免密直接登录服务器?
把本地生成的公钥上传并授权到服务器后,SSH 每次连接会自动用非对称加密完成校验,无需再手动输入密码。公钥可以公开,私钥始终留在本地,不要外传。
首次绑定(把本地公钥同步到服务器,只做一次)
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p <ssh_port> <user>@<public_ip>按提示输入一次服务器登录密码,出现
Number of key(s) added: 1即表示绑定成功。日常免密登录
ssh -p <ssh_port> <user>@<public_ip> # 若已按「方式 2」配置了别名,可以直接用别名登录 ssh myserver
各平台的首次绑定命令:
| 平台 | 命令 |
|---|---|
| Linux | ssh-copy-id -i ~/.ssh/id_ed25519.pub -p <ssh_port> <user>@<public_ip> |
| macOS | 同上(系统自带 ssh-copy-id) |
| Windows(PowerShell) | 见下方「Windows 平台的等价写法」 |
Windows 平台的等价写法
Git for Windows 自带的 OpenSSH 没有 ssh-copy-id 这个脚本,用一行管道命令替代:
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh -p <ssh_port> <user>@<public_ip> "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
如果用 WSL,或自己装了 MSYS2 的 openssh 包,直接使用上面的 ssh-copy-id 命令即可。
也可以纯手工完成:用记事本打开公钥文件并复制内容,粘贴到服务器的 ~/.ssh/authorized_keys 中(一个公钥一行):
notepad $env:USERPROFILE\.ssh\id_ed25519.pub
参数提示:公钥文件名按实际情况替换(如
id_rsa.pub);若本地还没有密钥对,先执行ssh-keygen -t ed25519 -C "你的邮箱"生成。