两台内网主机需要从外部访问时,可以通过 frp 共用一台公网服务器:SSH 按端口区分,Web 服务按域名区分。远程开发时,还可以用 SSH 的 RemoteForward,让远端访问本机上的服务。
下面沿着这两种连接方式展开配置和排查。示例中的主机 A、B 都运行 SSH 和 Web 服务,分别映射到公网服务器的不同入口。
两台内网主机怎样共享服务器
frpc 通过 20020 端口连接 frps。主机 A 的 SSH 映射到 20023,主机 B 映射到 20022;两台主机上的 Web 服务都监听 5666,由 frps 的 8080 入口按域名转发。
配置时需要同时处理服务端、客户端、防火墙和域名解析。FRPS_HOST 填写公网服务器地址,两端的 REPLACE_WITH_SHARED_SECRET 替换为同一个认证 token。
补齐 frps 和 frpc 两端
以下配置使用 TOML。先确认两端版本和二进制来源,配置格式、校验命令见 frp 官方配置文档。
服务器上的 frps.toml:
bindPort = 20020
vhostHTTPPort = 8080
auth.method = "token"
auth.token = "REPLACE_WITH_SHARED_SECRET"主机 A 上的 frpc.toml:
serverAddr = "FRPS_HOST"
serverPort = 20020
loginFailExit = false
auth.method = "token"
auth.token = "REPLACE_WITH_SHARED_SECRET"
[[proxies]]
name = "ssh_host_a"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 20023
[[proxies]]
name = "host-a.example.com"
type = "http"
localIP = "127.0.0.1"
localPort = 5666
customDomains = ["host-a.example.com"]主机 B 使用同一个服务端和 token,代理部分是:
[[proxies]]
name = "ssh_host_b"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 20022
[[proxies]]
name = "host-b.example.com"
type = "http"
localIP = "127.0.0.1"
localPort = 5666
customDomains = ["host-b.example.com"]原配置里有一个容易漏掉的问题:两台机器的 customDomains 填了同一个域名,只改代理的 name 并不会改变 HTTP 匹配域名。因此,两个 Web 服务需要分别设置域名,并将它们解析到 frps 所在的公网服务器。
服务器的控制端口与业务端口各有用途,防火墙按需要分别开放。frp SSH 映射示例说明了 remotePort 到客户端本地服务的路径;auth.token 则需要两端一致,见官方认证说明。
认证 token 用于 frpc 连接 frps,不能替代 SSH 公钥认证,也不会自动给 Web 服务加登录保护。示例 HTTP 入口使用 8080,不提供浏览器到服务器这一段的 HTTPS;需要公网 Web 访问时还要配置 TLS 和应用认证。HTTP 域名映射与 HTTPS 的不同处理方式见 frp 的虚拟主机文档。
先校验,再分段检查
分别在安装对应程序的机器上运行:
frps verify -c frps.toml
frpc verify -c frpc.toml校验通过后,分别以前台方式启动观察错误:
frps -c frps.toml
frpc -c frpc.toml启动成功后,从客户端验证 SSH:
ssh -p 20023 TARGET_USER@FRPS_HOST
ssh -p 20022 TARGET_USER@FRPS_HOSTWeb 服务可以先在内网机器上用 curl -I http://127.0.0.1:5666 确认本地服务工作,再从外部验证 Host 路由:
curl -I -H 'Host: host-a.example.com' http://FRPS_HOST:8080
curl -I -H 'Host: host-b.example.com' http://FRPS_HOST:8080这一步绕过的是域名解析,不是应用认证。验证正常后再把域名解析到服务器地址。域名不匹配、控制连接失败、本地 5666 不监听,分别是不同问题;按 frps、frpc、本地服务这三段查日志,比直接更换所有端口更容易定位。
SSH 的 RemoteForward 指向哪里
在客户端的 ~/.ssh/config 中,可以为不同连接保存别名。下面的 host-b-via-frp 通过 20022 连接主机 B;remote-work 则连接远程工作机,并用 RemoteForward 将客户端本机的 7897 端口转发到远端。
Host remote-work
HostName workstation.example.com
Port 22078
User TARGET_USER
RemoteForward 127.0.0.1:7897 127.0.0.1:7897
ExitOnForwardFailure yes
Host host-b-via-frp
HostName FRPS_HOST
Port 20022
User TARGET_USER只建立隧道而不打开远端 Shell,可以执行:
ssh -N remote-workRemoteForward 的客户端手册解释了监听端与目标端的关系。远端是否允许转发还受 AllowTcpForwarding、PermitListen 和 GatewayPorts 等服务端策略控制,参见 sshd_config 手册。不需要给其他主机访问时,保持回环监听即可。
ExitOnForwardFailure 可以让监听建立失败时退出,却不能证明之后每次访问目标服务都成功。先确认客户端 7897 确实有服务,再到远端核对监听和实际请求。多个 SSH 会话同时申请同一远端端口也会冲突;原笔记没有保留这些连接的运行日志,因此这里保留配置关系和检查方法,不补写当年的成功率或长期稳定性。