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-host2. 远程机验证隧道通了
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会直接拒绝
相关链接
- access-token — HTTPS 方式 git clone/push 与凭据配置
- masterdnsvpn — 网络代理/加速类工具
- git-worktree — 仓库操作并行工作流