ssh -R 把「远程机器的某个端口」转发回「本地机器的某个端口」,常用于让没有公网代理的远程机借用本机代理上网。

核心原理

-R 的流量方向是 远程 → 本地,连接建立在已有的 SSH 会话上:

远程机 127.0.0.1:7890 ──SSH 隧道──> 本机 127.0.0.1:7070 ──> 互联网
  • 在本机执行 ssh -R,SSH 客户端向 sshd 请求:在远程侧监听一个端口
  • 远程侧每收到一条连接,ssh 就把字节流通过已建立的 SSH 连接送回本机,由本机去连目标地址
  • 因此目标端口上的服务只需要监听本机 127.0.0.1,不必开 Allow LAN

对比 -L(本地转发):

监听位置流量方向典型用途
-L本机本地 → 远程访问远程内网服务(数据库、内网 Web)
-R远程远程 → 本地把本机服务/代理借给远程机用

语法

ssh -R [bind_address:]remote_port:host:hostport user@remote-host
参数说明
remote_port在远程机监听的端口
host:hostport从本机视角要连接的目标地址,通常 127.0.0.1:7070
-N不执行远程命令,只建隧道
-f认证成功后转后台
-T不分配伪终端
-o ExitOnForwardFailure=yes端口转发失败即退出,避免”隧道没建起来但会话还在”
-o ServerAliveInterval=30每 30s 发心跳,防中间设备掐断空闲连接

默认只绑定远程的 127.0.0.1。要让同网段其他机器也能用,需远程 sshd 开 GatewayPorts yes,并显式写绑定地址(如 -R 0.0.0.0:7890:...)——这等于把代理暴露出去,一般不这么做。

实战:借本机代理给远程机加速 git push

前提:本机有可用代理(如 ClashX 监听 127.0.0.1:7070),远程机无法直连 GitHub。

1. 本机发起带隧道的 SSH 连接

ssh -R 7890:127.0.0.1:7070 \
    -o ExitOnForwardFailure=yes \
    -o ServerAliveInterval=30 \
    user@remote-host

2. 远程机验证隧道通了

curl -I https://github.com        # 返回 HTTP/2 200/301 即通

3. 远程机让 git 走代理

# 仅当前 shell 生效
export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890
git push

或只给 GitHub 配代理,不动其他流量:

git config --global http.https://github.com.proxy http://127.0.0.1:7890

注意:这里的 127.0.0.1:7890 是远程机的地址,不是本机的。SSH 隧道把该端口映射回了本机的 7070。

4. SSH remote 的仓库

远程机 ~/.ssh/config 里让 ssh 客户端也走这条代理:

Host github.com
  HostName ssh.github.com
  Port 443
  User git
  ProxyCommand nc -X connect -x 127.0.0.1:7890 %h %p

走 ssh.github.com:443 同时绕开 22 端口封锁。

保活与自动化

固定配置写进本机 ~/.ssh/config,之后普通 ssh remote-host 就自动建隧道:

Host remote-host
  HostName 1.2.3.4
  User ops
  RemoteForward 7890 127.0.0.1:7070
  ExitOnForwardFailure yes
  ServerAliveInterval 30
  ControlMaster auto
  ControlPersist 10m

专用后台隧道用 autossh(断线自动重连):

autossh -M 0 -f -N \
  -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
  -o ExitOnForwardFailure=yes \
  -R 7890:127.0.0.1:7070 user@remote-host

-M 0 关闭 autossh 自带的监控端口,改用 SSH 自身的 keepalive,避免额外端口占用。

验证与排障

在远程机确认端口确实在监听:

ss -lntp | grep 7890        # Linux
lsof -nP -iTCP:7890         # macOS

常见问题:

现象原因处理
Warning: remote port forwarding failed for listen port 7890远程 7890 已被占用换端口,或去掉 -f 先看报错
隧道建了但 curl 超时本机代理没监听 / 端口写错本机 lsof -nP -iTCP:7070 确认
空闲几分钟后失效NAT/防火墙清空长连接加 ServerAliveInterval,或上 autossh
只绑了 127.0.0.1 但想跨机访问默认不对外开放远程 sshd 配 GatewayPorts 并显式绑地址
远程已有同名端口服务冲突用高段端口(如 17890)减少碰撞

局限性

  • 依赖会话存活:本机断网、休眠、SSH 断开,隧道立即失效;长期使用需 autossh + 保活
  • 带宽受本机上行限制:流量要绕经本机一次,大仓库 push 速度取决于本机上行带宽
  • 本机需在线:本机离线则远程代理不可用,比远程自建代理多一层依赖
  • DNS 解析发生在执行 curl/git 的机器:远程机解析 github.com 仍可能失败,可改用 ProxyCommand 走本地解析或用 socks5h
  • 不是所有 sshd 都允许转发:AllowTcpForwarding no 会直接拒绝

相关链接