SSH 操作手册

17 分钟
本页目录

连接不上时,先判断停在网络、主机身份还是用户认证;需要转发时,先确定谁监听、谁连接目标。这两件事弄清楚,再选命令通常就很直接。

本文面向 OpenSSH 客户端和 Linux 服务器。ops 是示例远程用户,server.example.com 是示例主机;后文的 server、jump、internal 是你在 ~/.ssh/config 中定义的别名。命令标注“本机”或“服务器”的地方,请在对应机器执行。

按当前任务找入口

你现在要做什么从这里开始
登录服务器,或固定端口、用户名和密钥连接与配置
经跳板机登录内网机器跳板连接
配公钥登录,或确认到底用了哪把密钥分清三种密钥文件
访问远程内网服务,或让远程访问本机服务端口转发
上传、下载,或同步目录文件传输
超时、拒绝连接、公钥认证失败、主机密钥变化按失败阶段排查

连接与配置

# 本机:使用默认 SSH 端口登录
ssh ops@server.example.com

首次连接先核验主机指纹;ops 是目标账户,不是本机用户名。需要非默认参数时改选下面的完整形式。

# 本机:明确端口和本次使用的身份
ssh -p 2222 -i ~/.ssh/id_ed25519_ops -o IdentitiesOnly=yes ops@server.example.com

-p 是服务器端口,-i 是本机私钥路径,IdentitiesOnly 限制尝试的身份;与上一条是备选连接方式。

下一份配置定义 server 别名;保存配置后,登录可简化为 ssh server。只执行命令时使用下一段,执行位置仍是本机。

# 本机:在服务器执行一条命令后退出
ssh server 'uname -a'

引号内命令由远端 shell 解释;核对输出来自预期主机。脚本使用时检查 SSH 返回码,255 通常是连接/SSH 错误,其他值可能是远端命令退出码。

经常连接的机器写入 ~/.ssh/config,后续 ssh、scp 和 rsync 都可复用别名:

Host server
    HostName server.example.com
    User ops
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_ops
    IdentitiesOnly yes

Host jump
    HostName bastion.example.com
    User ops
    IdentityFile ~/.ssh/id_ed25519_ops
    IdentitiesOnly yes

Host internal
    HostName 10.0.0.20
    User ops
    ProxyJump jump
    IdentityFile ~/.ssh/id_ed25519_ops
    IdentitiesOnly yes

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

具体主机放前面,通用默认值放后面:多数配置项采用先取得的值⁠,不是后面的块覆盖前面;IdentityFile 等可累加的项有自己的规则。IdentitiesOnly yes 限制所尝试的配置身份,避免把 agent 中所有密钥逐个试过去。OpenSSH 配置规则

ServerAliveInterval 在没有收到服务器数据时发起 SSH 层探测,连续无应答达到限制后断开。它有助于发现失联,也可能维持中间设备的连接状态,但不会自动重连或恢复远程进程。

配置写了却没有生效,先看最终值:

# 本机:求值配置而不建立会话
ssh -G server | grep -E '^(hostname|user|port|identityfile|identitiesonly|proxyjump) '

-G 展示匹配 Host/Match 后的客户端值;逐项核对输出,特别是 ProxyJump 与 IdentityFile。

如果输出仍指向旧 IP、旧端口或错误用户,先查别名拼写、匹配到的 Host 块和命令行参数;此时改服务器的 authorized_keys 没有帮助。

跳板连接

# 本机:使用配置中的跳板与最终目标
ssh internal

先保证 internal、jump 两个别名都定义正确;用 ssh -G internal 核对。

# 本机:一次性指定跳板的替代方式
ssh -J ops@bastion.example.com ops@10.0.0.20

-J 指定跳板,最后一个参数才是最终目标;不要先执行上一条后在远端继续这条。

路径是“本机 → 跳板机 → 内网机器”。本机客户端分别处理跳板与最终目标的认证,跳板承担到目标的 TCP 转发;不需要先把私钥复制到跳板,也不需要为了 -J 开启 agent forwarding。两台机器的端口和密钥应分别写在各自的 Host 块中。OpenSSH 跳板连接

分清三种密钥文件

公钥登录同时涉及两个方向的身份确认。下面两条线分开读,能避免把“服务器身份变化”和“用户没有登录权限”混为一谈。

主机身份与用户身份分别核验 服务器证明身份 主机公钥 server 本机信任记录 known_hosts 用户证明身份 私钥签名证明 client 服务器授权记录 authorized_keys 用户私钥留在本机
文件放在哪里解决什么问题
id_ed25519_ops本机,或由本机 agent 使用用户私钥,参与证明“我是这个用户”
authorized_keys服务器上要登录的那个用户的 .ssh/ 下允许哪些用户公钥登录该账户
known_hosts本机记录信任的服务器主机密钥

新增一把登录密钥

# 本机:为此用途创建一对新密钥
ssh-keygen -t ed25519 -C "ops-laptop" -f ~/.ssh/id_ed25519_ops

-f 指定新文件名,已有文件时取消而不覆盖;-C 是识别说明。完成后会有私钥与同名 .pub 公钥,私钥保留在本机。

# 本机:通过已有登录权限安装指定公钥
ssh-copy-id -i ~/.ssh/id_ed25519_ops.pub -p 2222 ops@server.example.com

需要先有密码等可用认证方式,目标是远程 ops 的 authorized_keys。只传 .pub;新密钥创建成功不代表已经安装。

# 本机:另开连接验证新身份
ssh -o PreferredAuthentications=publickey server 'id -un'

核对远端输出 ops,原有会话在新身份验证通过前保持可用。

成功时应输出远程用户名 ops。ssh-copy-id 需要你已有一种可用的登录方式;它不能绕过访问权限。私钥的 passphrase 在本机解锁密钥,与服务器账户密码不同。受合规或兼容性限制的环境应使用其支持的密钥类型。

使用 agent,减少反复输入 passphrase

# 本机:只查看 agent 中身份的指纹
ssh-add -l

需要完整公钥时另用 ssh-add -L;两者只读,不载入文件。

# 本机:将这把密钥载入当前 agent 一小时
ssh-add -t 1h ~/.ssh/id_ed25519_ops

输入的是私钥 passphrase。用 ssh-add -l 对照新增指纹;仅影响当前 SSH_AUTH_SOCK 指向的 agent。

# 本机:不再需要时移除此身份
ssh-add -d ~/.ssh/id_ed25519_ops

这是稍后撤销;-D 会清空该 agent 的全部身份,不能当成单密钥删除。

若提示无法连接 authentication agent,先检查当前会话是否有有效的 SSH_AUTH_SOCK。桌面会话通常已提供 agent;只在确实没有时,在当前 shell 执行 eval "$(ssh-agent -s)",避免每个终端都重复启动一个。

端口转发:先找监听端,再找目标端

-L 与 -R 按监听端口所在位置命名。它们都通过同一条 SSH 连接传输双向数据;图中箭头表示新的应用连接从哪边进入,不表示响应只能单向流动。

正在呈现知识画面
端口开在哪边,谁连接目标?

-L 在本机监听,由服务器连接目标;-R 在服务器监听,由本机连接目标;-D 在本机提供 SOCKS 入口,由服务器连接应用指定的目标。箭头表示应用连接的进入方向,隧道中的数据双向流动。

本地转发:从本机访问远程一侧的服务

# 本机终端一:保持本地转发运行
ssh -N -T -o ExitOnForwardFailure=yes \
  -L 127.0.0.1:8080:127.0.0.1:8000 server

该命令占用终端,出现监听失败先检查本机端口;不要等待它退出后才测试。

# 本机终端二:通过入口测试 HTTP 目标
curl -v http://127.0.0.1:8080/

读取状态与正文确认服务;结束测试后在终端一 Ctrl-C 关闭隧道。

两个 127.0.0.1 指向不同机器:第一个是本机的监听地址⁠;第二个由SSH 服务器用于连接目标,所以这里指服务器自己的回环地址。若目标是服务器能访问的内网机器,可把后半段改成 db.internal:5432,再用数据库客户端连接本机 8080;名称解析也发生在服务器一侧。

远程转发:让服务器访问本机服务

# 本机:为本机的 8000 服务建立远程入口
ssh -N -T -o ExitOnForwardFailure=yes \
  -R 127.0.0.1:9000:127.0.0.1:8000 server

先确认本机服务可访问,保持此终端运行。

# 服务器:从远端回环入口验证
curl -v http://127.0.0.1:9000/

在服务器的另一连接执行,不是在运行隧道的本机执行。

此时第一个地址请求在服务器上监听⁠,第二个地址由本机客户端连接。因此默认用途是“服务器本身访问本机服务”,不等于已经把服务发布到公网。

服务器的 GatewayPorts 决定远程监听的地址策略:no 限于回环,clientspecified 允许客户端选择,yes 强制通配地址。需要其他机器访问时,应由管理员明确配置监听地址、转发权限和入口访问控制,并检查实际监听结果;不要直接把 yes 当作通用修复。远程监听地址策略

动态转发:由应用通过 SOCKS 指定目标

# 本机终端一:启动 SOCKS 入口
ssh -N -T -o ExitOnForwardFailure=yes -D 127.0.0.1:1080 server

保持前台运行;这是 -L/-R 的另一种使用方式,不要求同时建立三条隧道。

# 本机终端二:由 SOCKS 一侧解析目标名
curl --proxy socks5h://127.0.0.1:1080 https://example.com/

socks5h 的 h 指代理侧解析;核对实际响应,结束后在终端一 Ctrl-C。

应用必须配置 SOCKS 代理;仅建立 -D 不会自动代理整台机器的流量。命令里没有固定目标地址,每条代理请求各自指定目标。OpenSSH 转发选项

隧道建好了,不代表目标可用

-N 不执行远程命令,-T 不分配伪终端。ExitOnForwardFailure=yes 让监听建立失败时退出,⁠不会因为后续目标连接失败而自动退出⁠。转发失败的边界

按这三个位置检查,不要只看 SSH 进程是否存在:

检查位置观察什么能确认什么
监听所在机器Linux 上 ss -ltn,找 8080、9000 或 1080入口是否存在、绑定哪个地址;必要时用有权限的 ss -ltnp 确认进程
发起目标连接的机器用该协议的客户端直接访问目标;本例可 curl -v http://127.0.0.1:8000/目标服务是否能从正确的一侧访问
应用入口通过转发端口或 SOCKS 发起请求一次实际请求是否走通

-L / -D 的目标侧是服务器,-R 的目标侧是本机。若看到 administratively prohibited,查服务器的转发策略及该密钥的限制;若是 connect failed: Connection refused,查目标地址和目标服务监听。

文件传输:先确认方向,再确认目录层次

任务在本机执行
上传一个文件scp report.txt server:/tmp/
下载一个文件scp server:/tmp/report.txt ./
上传整个目录scp -r assets server:/tmp/
不用别名,指定 SCP 的 SSH 端口scp -P 2222 report.txt ops@server.example.com:/tmp/

scp 的端口参数是大写 -P,ssh 的是小写 -p。使用主机别名可以避免反复写错。

同步目录:把预期结果写出来

假设本机已有 site/index.html,远程目录 /srv/www/ 已存在且当前用户可写:

源参数命令目标中的文件
site/:目录内容rsync -av site/ server:/srv/www//srv/www/index.html
site:目录本身rsync -av site server:/srv/www//srv/www/site/index.html

尾斜杠改变的是源目录是否多包一层。rsync 路径语义

# 本机:预览源目录内容将如何更新目标
rsync -av --dry-run --itemize-changes site/ server:/srv/www/

审阅 itemize 输出和目标层次,确认不存在路径多包一层;dry-run 不写文件。

# 本机:确认预览后执行同一范围同步
rsync -av --partial --progress site/ server:/srv/www/

检查退出状态,再以同一 dry-run 复查是否仍有非预期差异,并请求实际站点。若远端文件被覆盖,恢复依赖事先保留的副本。

-a 包含递归和常用元数据保留,实际能否保留所有者等属性取决于权限;它不自动包含 ACL、扩展属性或硬链接保留。--partial 帮助后续重试利用已有部分数据,不意味着任何情况下都简单从断点追加。需要压缩时再加 -z。这些命令不会删除远程多余文件;只有确实要做镜像时才另行考虑 --delete,并先预览删除列表。

按失败阶段排查

先在本机执行 ssh -vvv server,找最后成功的阶段。下表的日志是典型片段,不同版本的文字可能略有差别;查看目标登录失败时,也要分清跳板和最终目标各自的日志。

现象或日志已经知道什么下一步查哪里
Could not resolve hostname还没有连接到目标ssh -G 的 HostName、DNS、别名拼写
Connection timed out / No route to hostTCP 尚未成功,不能归因于公钥地址、路由、安全组、防火墙及主机可达性
Connection refused连接被主动拒绝正确机器和端口是否监听;也可能有主动拒绝规则
Connection establishedTCP 已建立,登录尚未完成继续找密钥交换、主机身份及认证阶段
REMOTE HOST IDENTIFICATION HAS CHANGED当前主机密钥与记录不符先独立核验服务器身份,见下节
Offering public key 后仍被拒绝客户端尝试了这把公钥,尚未获准登录远程用户名、该账户的公钥文件、权限和认证策略
Too many authentication failures认证尝试次数用尽检查配置身份;用 IdentitiesOnly 限定需要的密钥
Authenticated to ...用户认证已成功若随后断开,查远程 shell、强制命令、会话限制和服务器日志

不要看到认证失败就批量改权限,也不要看到卡住就先设 UseDNS no。先用日志确定卡在哪一层,再改变对应配置。

公钥被拒绝:沿着具体身份查

# 本机:读取准备认证的用户公钥指纹
ssh-keygen -lf ~/.ssh/id_ed25519_ops.pub

-l 显示指纹,-f 指定公钥文件;接着在目标账户侧核对同一指纹。

# 服务器目标用户:读取允许登录的指纹
ssh-keygen -lf ~/.ssh/authorized_keys

与本机公钥对照,确认核对的是远程目标用户的家目录。

# 服务器目标用户:检查路径所有者与权限
ls -ld ~ ~/.ssh ~/.ssh/authorized_keys

查看 owner/group 与其他用户写权限;仅修复实际不符合要求的路径,不批量递归 chmod 整个家目录。

默认文件布局下,常用权限是 .ssh 为 700、authorized_keys 为 600,所有者应正确,家目录不能被其他用户随意写入。若服务端配置了不同的 AuthorizedKeysFile、集中式密钥获取或证书认证,应检查实际来源,不能只盯默认文件。

需要管理员排查时,在服务器查实际使用的服务单元(常见为 ssh.service 或 sshd.service):

# 服务器管理员:查本次认证尝试的拒绝原因
sudo journalctl -u ssh.service -u sshd.service --since "10 min ago" --no-pager

按源地址、用户名与时间关联;两种 unit 名适配不同发行版,不表示都必须运行。

# 服务器管理员:验证磁盘上的服务端配置
sudo sshd -t

通过通常无输出;失败先修配置,不 reload。确需应用新配置时重载实际 ssh/sshd unit,保留原会话并另开登录验证。

第一条找具体拒绝理由;非 systemd 系统查对应认证日志。第二条验证服务端配置及主机密钥的基本有效性,不证明某个用户一定能登录。修改配置后保留现有会话,另开连接验证,再退出旧会话。

主机密钥变化:先核验,再更新记录

通过已有可信控制台或管理员提供的独立渠道核对新主机指纹。例如,在服务器控制台读取 Ed25519 主机公钥指纹:

# 服务器可信控制台:读取主机身份指纹
sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

核对的是服务器主机公钥,而不是用户 authorized_keys;算法需与客户端警告一致。

它必须与本机提示中的算法、指纹对应;若协商的是其他类型,应核对对应主机公钥。确认确实是预期服务器且变更合理后,才在本机删除报错中对应主机和端口的旧项:

# 本机:独立确认身份后移除对应旧记录
ssh-keygen -R '[server.example.com]:2222'

按报错的主机与端口精确匹配,不删除整个 known_hosts。

# 本机:重新连接并核对新指纹
ssh server

只有与可信渠道核对一致后才接受;仅执行 -R 不会证明新端点可信。

默认 22 端口通常用 ssh-keygen -R server.example.com。使用 HostKeyAlias 或自定义 known-hosts 文件时,按实际配置处理。重新连接时核对新指纹;ssh-keyscan 只能收集当前网络端点给出的密钥,不能独立证明它可信。主机密钥记录操作

进一步查阅

完整选项以当前安装版本的 man ssh、man ssh_config、man sshd_config 为准。想理解 SSH 的协议层次与通道机制,可继续读 SSH 协议。本篇保留常见任务入口,协议原理放在对应知识文章中展开。