跳转至

基础设施-SSH连接-Windows无sshpass远程操作服务器

问题现象

Windows 11 环境下需要对 CentOS Stream 9 服务器(120.77.218.217)执行远程命令(git pullsystemctl restart 等),但: - Git Bash 默认没有 sshpass,无法像 Linux 那样 sshpass -p 'password' ssh root@host 'cmd' - 服务器仅支持密码登录,未配置 SSH Key - taskkill / netstat 等 Windows 命令在 Git Bash 下表现不一致

核心问题

Windows Git Bash 与 Linux 的运维工具链存在差异,主要表现在: 1. sshpass 缺失:Git Bash 未预装 sshpass,通过 pacman -S sshpass 安装不稳定 2. SSH 客户端行为差异:Git Bash 的 OpenSSH 不支持 ControlMaster(Unix socket 在 Windows 上不兼容) 3. 端口管理 CLI 差异:Git Bash 中 taskkill //F //IM node.exe 无法正确终止 Windows 进程,需用 PowerShell 的 Stop-Process

解决方案

整个演进分为两个阶段,第二阶段是最终推荐方案。

第一阶段:paramiko 密码认证(过渡方案)

Python 的 paramiko 是 Windows Git Bash 下唯一稳定可用的程序化 SSH 方式,不依赖外部二进制文件。

适用场景:临时排查、紧急操作、尚未配置密钥时。

操作方式:在本地执行 Python 单行脚本

venv/Scripts/python.exe -c "
import paramiko

c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect('120.77.218.217', username='root', password='你的密码', timeout=15)

def run(cmd):
    stdin, stdout, stderr = c.exec_command(cmd)
    out = stdout.read().decode()
    err = stderr.read().decode()
    if err:
        print('ERR:', err.strip())
    return out.strip()

# --- 在此处执行远程命令 ---
print(run('cd /www/news && git log --oneline -1'))
print(run('systemctl status news-backend --no-pager -l | head -10'))

c.close()
"

缺陷: - 密码明文出现在命令中(进程列表、历史记录可见) - 需要额外依赖 paramiko 库 - 每次都要写完整连接代码,不简洁 - 不适合频繁、多步操作

第二阶段:SSH 密钥 + Config 别名(最终方案)

配置 SSH Key 免密登录 + ~/.ssh/config 别名后,ssh news 一条命令即可远程执行任意操作。

2.1 生成密钥对

在 Windows PowerShell 或 Git Bash 中执行:

ssh-keygen -t ed25519 -C "news-server" -f ~/.ssh/id_ed25519_news

一路回车,不设 passphrase(设了每次都要输,影响自动化)。

  • 私钥:~/.ssh/id_ed25519_news
  • 公钥:~/.ssh/id_ed25519_news.pub

2.2 上传公钥到服务器

先用 paramiko 把公钥写入服务器 ~/.ssh/authorized_keys

venv/Scripts/python.exe -c "
import paramiko
pubkey = '你的pub公钥ssh-xxx news-server'
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect('120.77.218.217', username='root', password='你的密码', timeout=15)
def do(cmd):
    stdin, stdout, stderr = c.exec_command(cmd)
    return stdout.read().decode().strip()
do('mkdir -p ~/.ssh && chmod 700 ~/.ssh')
do('printf \"%s\\n\" \"{}\" >> ~/.ssh/authorized_keys'.format(pubkey))
do('chmod 600 ~/.ssh/authorized_keys')
do('sort -u ~/.ssh/authorized_keys -o ~/.ssh/authorized_keys')
print('Done - 公钥已写入,条目数:', do('wc -l < ~/.ssh/authorized_keys'))
c.close()
"

注意:printfecho 更安全,不会因特殊字符导致转义问题;sort -u 可避免重复追加公钥。

2.3 创建 SSH Config 文件

C:\Users\Administrator\.ssh\config(无后缀名)写入:

Host news
    HostName 120.77.218.217
    User root
    IdentityFile ~/.ssh/id_ed25519_news
    IdentitiesOnly yes
    ServerAliveInterval 30
    ServerAliveCountMax 3

避坑:不要添加 ControlMaster / ControlPath。Windows Git Bash 的 OpenSSH 不完全支持 Unix socket,会导致 mux_client_request_session: read from master failed 错误。

2.4 测试连接

ssh news "echo '连接成功' && hostname && uptime"

预期输出无需密码直接返回服务器信息。

2.5 日常使用

从此服务器操作简化为一行命令:

# 查看状态
ssh news "systemctl status news-backend --no-pager | head -5"

# 部署代码
ssh news "cd /www/news && git pull origin main"

# 重启服务
ssh news "systemctl restart news-backend"

# 多条命令组合
ssh news "cd /www/news && git pull origin main && systemctl restart news-backend"

下次防错措施

  1. 新机器配置清单:换电脑或重装系统后,按 2.1 → 2.2 → 2.3 流程重新配置,全程不超过 3 分钟。
  2. 密钥备份:私钥 ~/.ssh/id_ed25519_news 妥善备份,不要提交到 Git 仓库。
  3. Config 文件模板~/.ssh/config 内容已记录在上述文档,可直接复制使用。
  4. Windows 特有问题速查
  5. ControlMaster 报错 → 从 config 中删除该配置
  6. 端口进程管理 → 优先用 PowerShell Get-NetTCPConnection | Stop-Process,而非 Git Bash 的 taskkill
  7. SSH 连接卡住 → rm -f ~/.ssh/ssh_mux_* 清理残留 socket(如曾尝试过 multiplexing)
  8. CODEBUDDY.md 索引:项目 docs/config/server-deploy.md 中维护了最新的 SSH 连接方式和部署流程,作为权威参考。