适用场景:Windows 本地电脑通过 SSH 登录裸金属服务器;通过跳板机访问内网机器;让远端服务器使用 Windows 本地代理;用 VS Code Remote-SSH 连接远端服务器。
0. 当前网络与目标
机器关系
| 名称 | IP / Host | 说明 |
|---|---|---|
| Windows 本地电脑 | C:\Users\24385 |
本地开发机,本地代理端口为 127.0.0.1:7897 |
| 跳板机 | 10.42.206.102 |
Windows 可直接 SSH 登录 |
| 目标机 | 10.20.2.5 / bms-25 |
只能经跳板机访问 |
| 其他服务器 | 192.168.206.112 |
用户 pcljgy |
| 其他服务器 | 192.168.206.140 / 192.168.206.140_jgy |
用户 pcljgy |
目标 1:Windows 直接登录目标机:
powershell
ssh bms-25
实际路径:
text
Windows 本地电脑 → 10.42.206.102 → 10.20.2.5
目标 2:让远端服务器使用 Windows 本地代理:
text
远端服务器 127.0.0.1:10240
↓ SSH 隧道
Windows 本地 127.0.0.1:7897
1. SSH 免密登录基础
1.1 公钥应该放在哪里
SSH 免密登录的规则是:你用哪个用户登录,服务器就去哪个用户的家目录找 authorized_keys。
| 登录命令 | 服务器读取的公钥文件 |
|---|---|
ssh root@10.42.206.102 |
/root/.ssh/authorized_keys |
ssh root@10.20.2.5 |
/root/.ssh/authorized_keys |
ssh pcljgy@192.168.206.112 |
/home/pcljgy/.ssh/authorized_keys |
所以不是"必须上传到 root 文件夹",而是因为你登录的是 root 用户。
1.2 / 和 /root 的区别
text
/ 是 Linux 系统根目录
/root 是 root 用户的家目录
1.3 公钥和私钥
你的 Windows 公钥是:
text
C:\Users\24385\.ssh\id_rsa.pub
私钥是:
text
C:\Users\24385\.ssh\id_rsa
只能上传公钥 id_rsa.pub,不要上传私钥 id_rsa。
2. 通过跳板机访问内网目标机
2.1 为什么 ssh -J 失败
曾尝试:
powershell
ssh -J root@10.42.206.102 root@10.20.2.5
报错:
text
channel 0: open failed: administratively prohibited: open failed
stdio forwarding failed
Connection closed by UNKNOWN port 65535
含义:Windows 成功连上了跳板机,但跳板机的 SSH 服务不允许 TCP forwarding,所以 ProxyJump 被禁止。常见原因是跳板机 /etc/ssh/sshd_config 中有:
text
AllowTcpForwarding no
或存在 PermitOpen / Match 限制。
2.2 如何查询 -J 的含义
ssh --help 不一定可用,因为 OpenSSH 通常不支持 --help。
可以用:
bash
ssh -h 2>&1 | grep -- "-J"
或:
bash
man ssh
进入手册后输入:
text
/-J
-J 是 ProxyJump,格式:
bash
ssh -J 跳板机用户@跳板机IP 目标用户@目标IP
2.3 使用 ProxyCommand + nc 代替 ProxyJump
先在跳板机确认存在 nc:
bash
which nc
结果:
text
/usr/bin/nc
测试跳板机到目标机的 22 端口:
bash
nc -vz 10.20.2.5 22
结果:
text
Ncat: Connected to 10.20.2.5:22.
说明:
text
10.42.206.102 → 10.20.2.5:22 是通的
Windows 本地可以这样直接测试:
powershell
ssh -o "ProxyCommand=ssh root@10.42.206.102 /usr/bin/nc %h %p" root@10.20.2.5
这里不要写 nc -vz,因为 -vz 只是测试端口。真正代理 SSH 流量时应该使用:
bash
/usr/bin/nc %h %p
其中:
text
%h = 目标 HostName,例如 10.20.2.5
%p = 目标端口,默认 22
3. 将 Windows 公钥写入内网目标机
3.1 成功的一条 PowerShell 命令
在 Windows PowerShell 中执行:
powershell
$pub = (Get-Content $env:USERPROFILE\.ssh\id_rsa.pub -Raw).Trim(); ssh -o "ProxyCommand=ssh root@10.42.206.102 /usr/bin/nc %h %p" root@10.20.2.5 "mkdir -p /root/.ssh && touch /root/.ssh/authorized_keys && grep -qxF '$pub' /root/.ssh/authorized_keys || echo '$pub' >> /root/.ssh/authorized_keys; chmod 700 /root/.ssh; chmod 600 /root/.ssh/authorized_keys"
作用:
- 读取 Windows 本地
id_rsa.pub; - 通过
ProxyCommand + nc连接10.20.2.5; - 在目标机创建
/root/.ssh; - 将公钥写入
/root/.ssh/authorized_keys; - 如果公钥已存在,则不重复添加;
- 设置正确权限。
权限要求:
bash
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys
3.2 为什么"管道传公钥 + 内层 ssh"容易失败
之前类似命令:
powershell
Get-Content $env:USERPROFILE\.ssh\id_rsa.pub | ssh root@10.42.206.102 "ssh root@10.20.2.5 'mkdir -p /root/.ssh && cat >> /root/.ssh/authorized_keys'"
失败原因:外层 SSH 正在接收管道输入,内层 ssh root@10.20.2.5 又需要交互式输入密码,管道和交互式密码输入容易冲突。改用 ProxyCommand + nc 后,Windows 本地直接建立到目标机的 SSH 会话,所以可以正常输入密码并写入公钥。
4. Windows SSH config 推荐配置
打开配置文件:
powershell
notepad $env:USERPROFILE\.ssh\config
推荐写法:
sshconfig
Host bms-gateway
HostName 10.42.206.102
User root
IdentityFile C:/Users/24385/.ssh/id_rsa
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
Host bms-25
HostName 10.20.2.5
User root
IdentityFile C:/Users/24385/.ssh/id_rsa
IdentitiesOnly yes
ProxyCommand ssh -q bms-gateway /usr/bin/nc %h %p
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
之后可以直接:
powershell
ssh bms-25
ProxyCommand 中加 -q 的作用是减少跳板机登录 banner 等输出,避免干扰 VS Code Remote-SSH。
5. VS Code Remote-SSH 连接问题
5.1 先判断是否真的 SSH 失败
如果日志里有:
text
Found existing installation at /root/.vscode-server...
Starting VS Code CLI...
Remote server is listening on socket /tmp/code-...
或:
text
Found running server...
listeningOn==34713==
说明 SSH 已经连上,VS Code Server 也已启动。失败通常发生在后续 tunnel / socket 通信。
5.2 socket 模式问题
如果看到:
text
remote.SSH.remoteServerListenOnSocket = true
Remote server is listening on socket /tmp/code-...
Exec server failed: Error: read ECONNRESET
可以先关闭 socket 模式。
打开 VS Code 用户设置:
powershell
notepad $env:APPDATA\Code\User\settings.json
加入或合并:
json
{
"remote.SSH.remoteServerListenOnSocket": false,
"remote.SSH.useExecServer": false,
"remote.SSH.useLocalServer": false,
"remote.SSH.showLoginTerminal": true,
"remote.SSH.remotePlatform": {
"bms-25": "linux"
}
}
然后在 VS Code 中执行:
text
Ctrl + Shift + P
Remote-SSH: Kill VS Code Server on Host...
选择 bms-25
再重新连接。
5.3 目标机禁止 TCP forwarding
如果日志里出现:
text
channel 3: open failed: administratively prohibited: open failed
检查目标机:
bash
sshd -T | grep -Ei "allowtcpforwarding|permitopen|allowstreamlocalforwarding"
曾出现:
text
allowtcpforwarding no
allowstreamlocalforwarding yes
permitopen any
这说明目标机禁止 TCP forwarding。VS Code Remote-SSH 需要 SSH tunnel,因此会失败。
5.4 开启目标机 TCP forwarding
在目标机 10.20.2.5 上执行:
bash
cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d_%H%M%S)
修改或追加:
bash
grep -qEi '^[[:space:]]*AllowTcpForwarding[[:space:]]+' /etc/ssh/sshd_config \
&& sed -i -E 's/^[[:space:]]*AllowTcpForwarding[[:space:]]+.*/AllowTcpForwarding yes/I' /etc/ssh/sshd_config \
|| echo 'AllowTcpForwarding yes' >> /etc/ssh/sshd_config
检查配置:
bash
sshd -t
无输出表示语法正确。
重载服务:
bash
systemctl reload sshd
如果 reload 不可用:
bash
systemctl restart sshd
确认:
bash
sshd -T | grep -Ei "allowtcpforwarding|permitopen|allowstreamlocalforwarding"
期望:
text
allowtcpforwarding yes
allowstreamlocalforwarding yes
permitopen any
5.5 注意 Match 块覆盖
如果改完仍然是 allowtcpforwarding no,检查:
bash
grep -nEi "AllowTcpForwarding|PermitOpen|AllowStreamLocalForwarding|Match" /etc/ssh/sshd_config
如果看到:
text
Match User root
AllowTcpForwarding no
则需要修改 Match 块内部配置。
6. 远程端口转发:让远端使用 Windows 本地代理
6.1 这是远程端口转发 -R
命令:
powershell
ssh -N -T -R 127.0.0.1:10240:127.0.0.1:7897 bms-25
含义:
text
bms-25 上的 127.0.0.1:10240
↓ SSH 隧道
Windows 本地的 127.0.0.1:7897
所以,在远端访问:
bash
127.0.0.1:10240
实际会访问 Windows 本地:
text
127.0.0.1:7897
6.2 临时启动代理隧道
在 Windows PowerShell 执行:
powershell
ssh -N -T -R 127.0.0.1:10240:127.0.0.1:7897 `
-o ServerAliveInterval=30 `
-o ServerAliveCountMax=6 `
-o TCPKeepAlive=yes `
-o ExitOnForwardFailure=yes `
-o ConnectTimeout=15 `
bms-25
保持这个窗口不关闭。
6.3 测试远端代理
在远端执行:
bash
curl -x http://127.0.0.1:10240 https://github.com -I
如果返回 HTTP 响应头,说明转发成功。
6.4 设置远端代理环境变量
bash
export http_proxy=http://127.0.0.1:10240
export https_proxy=http://127.0.0.1:10240
export HTTP_PROXY=http://127.0.0.1:10240
export HTTPS_PROXY=http://127.0.0.1:10240
测试:
bash
curl https://github.com -I
6.5 Git 代理
设置:
bash
git config --global http.proxy http://127.0.0.1:10240
git config --global https.proxy http://127.0.0.1:10240
取消:
bash
git config --global --unset http.proxy
git config --global --unset https.proxy
7. 将远程代理转发写进 SSH config
7.1 不建议直接写进普通 Host
可以直接写:
sshconfig
Host 192.168.206.112
HostName 192.168.206.112
User pcljgy
RemoteForward 127.0.0.1:10240 127.0.0.1:7897
但不推荐用于 VS Code,因为 VS Code Remote-SSH 会开多条 SSH 连接。每条连接都会尝试占用远端 127.0.0.1:10240,容易冲突、卡住或出现:
text
remote port forwarding failed for listen port 10240
更稳的方式是分成两个 Host:
text
普通 Host:给 VS Code / 普通 SSH 使用
-proxy Host:专门维持代理隧道
7.2 bms-25 推荐配置
sshconfig
Host bms-gateway
HostName 10.42.206.102
User root
IdentityFile C:/Users/24385/.ssh/id_rsa
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
Host bms-25
HostName 10.20.2.5
User root
IdentityFile C:/Users/24385/.ssh/id_rsa
IdentitiesOnly yes
ProxyCommand ssh -q bms-gateway /usr/bin/nc %h %p
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
Host bms-25-proxy
HostName 10.20.2.5
User root
IdentityFile C:/Users/24385/.ssh/id_rsa
IdentitiesOnly yes
ProxyCommand ssh -q bms-gateway /usr/bin/nc %h %p
RemoteForward 127.0.0.1:10240 127.0.0.1:7897
ExitOnForwardFailure yes
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
RequestTTY no
SessionType none
使用:
powershell
ssh bms-25 # 普通登录 / VS Code
ssh bms-25-proxy # 代理隧道
7.3 192.168.206.112 推荐配置
sshconfig
Host 192.168.206.112
HostName 192.168.206.112
User pcljgy
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
Host 192.168.206.112-proxy
HostName 192.168.206.112
User pcljgy
RemoteForward 127.0.0.1:10240 127.0.0.1:7897
ExitOnForwardFailure yes
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
RequestTTY no
SessionType none
使用:
powershell
ssh 192.168.206.112 # 普通登录 / VS Code
ssh 192.168.206.112-proxy # 代理隧道
7.4 192.168.206.140_jgy 推荐配置
sshconfig
Host 192.168.206.140_jgy
HostName 192.168.206.140
User pcljgy
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
Host 192.168.206.140_jgy-proxy
HostName 192.168.206.140
User pcljgy
RemoteForward 127.0.0.1:10240 127.0.0.1:7897
ExitOnForwardFailure yes
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
RequestTTY no
SessionType none
使用:
powershell
ssh 192.168.206.140_jgy # 普通登录 / VS Code
ssh 192.168.206.140_jgy-proxy # 代理隧道
7.5 为什么 VS Code 不能连接 -proxy Host
-proxy Host 里有:
sshconfig
RequestTTY no
SessionType none
含义是:该连接只做隧道,不启动远程 shell。
VS Code 需要远程执行脚本、安装和启动 VS Code Server,因此不适合连接 -proxy Host。
正确用法:
| 用途 | Host |
|---|---|
| VS Code 远程开发 | bms-25 |
| bms-25 代理隧道 | bms-25-proxy |
| VS Code 远程开发 | 192.168.206.112 |
| 192.168.206.112 代理隧道 | 192.168.206.112-proxy |
7.6 如果坚持直接写进普通 Host
可以这样写,但要降低冲突影响:
sshconfig
Host 192.168.206.112
HostName 192.168.206.112
User pcljgy
RemoteForward 127.0.0.1:10240 127.0.0.1:7897
ExitOnForwardFailure no
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
这里建议用:
sshconfig
ExitOnForwardFailure no
不要用:
sshconfig
ExitOnForwardFailure yes
否则 VS Code 多连接时,如果第二条连接发现远端 10240 已被占用,可能直接失败。
8. 后台启动代理隧道
8.1 前台启动
powershell
ssh bms-25-proxy
或:
powershell
ssh 192.168.206.112-proxy
窗口无输出、不进入 shell、一直挂着,是正常现象。
8.2 后台隐藏启动
powershell
Start-Process -WindowStyle Hidden -FilePath "ssh.exe" -ArgumentList "bms-25-proxy"
powershell
Start-Process -WindowStyle Hidden -FilePath "ssh.exe" -ArgumentList "192.168.206.112-proxy"
powershell
Start-Process -WindowStyle Hidden -FilePath "ssh.exe" -ArgumentList "192.168.206.140_jgy-proxy"
如果 ssh.exe 不在 PATH 中:
powershell
Start-Process -WindowStyle Hidden -FilePath "C:\Program Files (x86)\OpenSSH-Win64\ssh.exe" -ArgumentList "bms-25-proxy"
8.3 查看 SSH 进程
powershell
Get-Process ssh
8.4 关闭所有 SSH 进程
powershell
Stop-Process -Name ssh
注意:这会关闭所有名为 ssh 的进程,包括普通 SSH 和隧道。
9. 保活参数解释
sshconfig
ServerAliveInterval 30
ServerAliveCountMax 6
TCPKeepAlive yes
整体含义:每 30 秒检查一次 SSH 连接;连续 6 次无响应则断开,大约 3 分钟。
9.1 ServerAliveInterval 30
如果 30 秒内没有收到服务器任何数据,SSH 客户端向服务器发送 SSH 协议层保活包。
9.2 ServerAliveCountMax 6
连续 6 次保活探测无响应后,SSH 客户端断开连接。
text
30 秒 × 6 = 180 秒
9.3 TCPKeepAlive yes
启用操作系统 TCP 层面的 keepalive。它更底层,但检测通常更慢。
9.4 区别
| 参数 | 层级 | 作用 |
|---|---|---|
ServerAliveInterval |
SSH 协议层 | 定期发送 SSH 保活包 |
ServerAliveCountMax |
SSH 协议层 | 连续多少次无响应后断开 |
TCPKeepAlive |
TCP 系统层 | 操作系统检测 TCP 连接 |
这些参数只能检测坏连接并退出,不能自动重连。若要自动重连,可考虑 autossh、Windows 任务计划程序或 PowerShell 循环脚本。
10. 常见报错速查
10.1 unknown option -- -
命令:
bash
ssh --help
原因:OpenSSH 通常不支持 --help。
替代:
bash
ssh -h
man ssh
10.2 channel 0: open failed: administratively prohibited
常见于:
powershell
ssh -J root@10.42.206.102 root@10.20.2.5
原因:跳板机禁止 TCP forwarding。
解决:改用 ProxyCommand + nc,或在跳板机开启 AllowTcpForwarding yes。
10.3 channel 3: open failed: administratively prohibited
常见于 VS Code Remote-SSH。
原因:目标机禁止 TCP forwarding,导致 VS Code tunnel 建立失败。
解决:在目标机开启:
text
AllowTcpForwarding yes
10.4 VS Code 连接 -proxy Host 卡住
现象:
text
设置 SSH 主机 192.168.206.112-proxy: 正在初始化 VS Code 服务器
原因:-proxy Host 是隧道,不适合 VS Code 远程开发。
解决:VS Code 连接普通 Host,代理隧道用 PowerShell 单独启动。
10.5 remote port forwarding failed for listen port 10240
原因:远端 127.0.0.1:10240 已被其他 SSH 隧道占用。
排查:
bash
ss -lntp | grep 10240
解决:关闭已有隧道,或换端口,例如 10241。
11. 速查命令
测试普通 SSH:
powershell
ssh bms-25
ssh 192.168.206.112
ssh 192.168.206.140_jgy
测试 ProxyCommand:
powershell
ssh -o "ProxyCommand=ssh -q root@10.42.206.102 /usr/bin/nc %h %p" root@10.20.2.5
启动 bms-25 代理:
powershell
ssh bms-25-proxy
后台启动 bms-25 代理:
powershell
Start-Process -WindowStyle Hidden -FilePath "ssh.exe" -ArgumentList "bms-25-proxy"
远端设置代理:
bash
export http_proxy=http://127.0.0.1:10240
export https_proxy=http://127.0.0.1:10240
远端测试代理:
bash
curl -x http://127.0.0.1:10240 https://github.com -I
检查 sshd 转发能力:
bash
sshd -T | grep -Ei "allowtcpforwarding|permitopen|allowstreamlocalforwarding|gatewayports"
12. 安全注意事项
只上传公钥:
text
id_rsa.pub
不要上传私钥:
text
id_rsa
推荐远程转发只绑定远端本机:
sshconfig
RemoteForward 127.0.0.1:10240 127.0.0.1:7897
不建议随意开放到内网:
sshconfig
RemoteForward 0.0.0.0:10240 127.0.0.1:7897
因为这会把代理暴露给远端内网其他机器,并且需要远端 sshd 允许:
text
GatewayPorts yes
或:
text
GatewayPorts clientspecified
13. 最终推荐工作流
VS Code 远程开发连接普通 Host:
text
bms-25
192.168.206.112
192.168.206.140_jgy
不要用 VS Code 连接:
text
bms-25-proxy
192.168.206.112-proxy
192.168.206.140_jgy-proxy
代理隧道用 PowerShell 单独启动:
powershell
ssh bms-25-proxy
或后台启动:
powershell
Start-Process -WindowStyle Hidden -FilePath "ssh.exe" -ArgumentList "bms-25-proxy"
远端使用代理:
bash
export http_proxy=http://127.0.0.1:10240
export https_proxy=http://127.0.0.1:10240
curl https://github.com -I
14. 核心结论
text
1. 公钥放在哪里,取决于你登录哪个远端用户。
2. Windows 本地只保留私钥 id_rsa,服务器只放公钥 id_rsa.pub。
3. ProxyJump 失败时,可以用 ProxyCommand + nc 代替。
4. VS Code Remote-SSH 需要目标机允许 AllowTcpForwarding yes。
5. 远程代理转发使用 -R / RemoteForward。
6. 不建议把 RemoteForward 直接写进 VS Code 使用的普通 Host。
7. 最稳方案是:普通 Host 用于 VS Code;-proxy Host 用于代理隧道。
8. ServerAliveInterval / ServerAliveCountMax / TCPKeepAlive 用于检测坏连接,但不会自动重连。