SSH 使用技巧¶
SSH 是一种开放协议,它的主流实现 OpenSSH 具有最丰富的功能,因此本教程只介绍 OpenSSH 的使用。
客户端配置¶
SSH 客户端会按顺序处理以下配置,先出现的配置优先级更高:
- 命令行参数
~/.ssh/config/etc/ssh/ssh_config
OpenSSH 的所有配置项都可以在 [ssh_config(5)][ssh_config.5] 中找到,这里介绍一些常用的配置。
对于经常登录的主机,可以在 ~/.ssh/config 中配置主机别名、用户名、端口等信息,以简化登录命令。
| Bash | |
|---|---|
1 2 3 4 | |
注意 SSH config 没有提供密码配置,因为这是不安全的,请使用密钥登录。
Note
事实上,现在如果你不在config里说明密钥的话,连接是不让你过的🤡
公钥认证¶
默认情况下,SSH 会寻找 ~/.ssh/id_* 作为私钥,其中 * 部分可以是 rsa、dsa、ecdsa、ed25519 等,也可以通过 -i 参数指定私钥文件。私钥的文件名加上 .pub 后缀就是公钥文件,暂时没有方法指定公钥文件的路径。如果要在配置文件中指定一个或多个私钥,可以使用 IdentityFile 选项,例如:
| Bash | |
|---|---|
1 2 3 | |
一般来说,除非为了兼容一些非常古老(如 10 年前的)或非常简单的(如嵌入式)系统而不得不使用较短的 RSA 密钥对的时候,我们推荐使用 Ed25519 密钥对,或者 ECDSA 密钥对。这两种基于椭圆曲线的密码学算法比 RSA 更安全,而且性能也更好。如果不得不使用 RSA 的话,请尽可能使用 3072 位或更长的密钥长度。密钥长度可以在使用 ssh-keygen 生成密钥对时指定(-b),其中不同算法支持与推荐的长度也是不同的:
| 算法 | 支持长度 | 推荐长度 | 说明 |
|---|---|---|---|
| RSA | 1024-4096 | 3072 或以上 | 曾经的推荐长度是 2048 位,但 2020 年以后认为这个长度已不够安全 |
| DSA (不推荐) |
1024 | 1024 | 由于安全性问题,OpenSSH 7.0 以后不再默认支持 DSA 密钥 |
| ECDSA | 256 / 384 / 521 | 256 / 384 / 521 | 由于椭圆曲线参数选择的特殊性,只有这三种长度可选。注意最后一个选项是 521,不是 512 |
| Ed25519 | - | - | Ed25519 是基于 Edwards 曲线的算法,没有“长度”这种参数 |
端口转发¶
SSH 配置 TCP 端口转发的格式为 [bind_address:]port:host:hostport,SSH 支持三种端口转发:

本地端口转发(Local port forwarding)¶
在本地上监听一个端口,将收到的数据转发到远程主机的指定端口。即将远程主机上某个服务的端口转发到本地,使本地的其他程序可以通过 SSH 访问到远程的服务。例如将远程主机的 80 端口转发到本地的 8080:
| Bash | |
|---|---|
1 | |
也可以将远程主机所在网络的机器通过这种方法转发,假设需要访问的远程主机网络内部的机器名叫 internalserver:
| Bash | |
|---|---|
1 | |
本地端口转发默认监听在 localhost。如果要监听其他地址,可以指定需要监听的地址,例如:
| Bash | |
|---|---|
1 | |
虽然 SSH 客户端也有一个 GatewayPorts 选项,但它只影响没有指定监听地址的语法模式(即三段式 localport:remotehost:remoteport)。指定四段式语法后,GatewayPorts 选项不再起作用。
远程端口转发(Remote port forwarding)¶
在远程主机上监听一个端口,将收到的数据转发到本地的指定端口。即将本地某个服务的端口转发到远程主机上,使远程的其他程序可以通过 SSH 访问到本地的服务。例如将本地主机的 80 端口转发到远程主机的 8080 端口:
| Bash | |
|---|---|
1 | |
上面命令表示在远程主机 example 上监听 8080 端口,将收到的数据转发到本地的 80 端口。
同样的,也可以将本地网络中的机器做转发,假设对应机器名为 myinternalserver:
| Bash | |
|---|---|
1 | |
注意远程端口转发默认只能监听 localhost。如果要监听其他地址,需要在远程主机的 sshd_config 中设置 GatewayPorts yes。与另外两种端口转发不同,客户端无法覆盖服务端的 GatewayPorts 设定。
在 OpenSSH 7.6 版本之后的客户端,-R 也可以用来让远程主机利用本地作为 SOCKS5 代理(相当于下面的 -D 参数反过来),对应手册中的 -R [bind_address:]port 部分:
| Bash | |
|---|---|
1 2 3 | |
动态端口转发(Dynamic port forwarding)¶
: 在本地监听一个端口用作 SOCKS5 代理,将收到的数据转发到远程主机,相当于利用了远程主机作为代理。例如:
| Text Only | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
以上三种端口转发都可以在配置文件中指定,例如:
| Bash | |
|---|---|
1 2 3 4 5 6 7 | |
-L、-R、-D 和配置文件中对应的选项都可以多次出现,指定多条转发规则,它们互相独立、不会覆盖,因此如果重复指定了同一个端口,就会出现冲突。
跳板¶
SSH 支持通过跳板机连接目标主机,即先 SSH 登录 jump-host,再从 jump-host 登录目标主机。一些受限的网络环境常常采用这种方案,例如一个集群内只有跳板机暴露在公网上,而其他主机都在被隔离的内网中,只能通过跳板机访问。
ssh 命令的 -J 选项可以指定跳板机,例如:
| Bash | |
|---|---|
1 | |
对应的配置文件语句是 ProxyJump [email protected]。
如果要给跳板机设置更多参数,如端口等,则必须使用配置文件:
| Bash | |
|---|---|
1 2 3 4 5 6 7 8 9 | |

高级功能:连接复用¶
SSH 协议允许 在一条连接内运行多个 channel,其中每个 channel 可以是一个 shell session、端口转发、scp 命令等。
OpenSSH 支持连接复用,即 一个 SSH 进程在后台保持连接,其他客户端在连接同一个主机时可以复用这个连接,而不需要重新握手认证等,可以显著减少连接时间。这在频繁连接同一个主机时非常有用,尤其是当主机的延迟较大、常用操作所需的 RTT 较多时(例如从 GitHub 拉取仓库,或者前文所述的跳板机使用方式)。
启用连接复用需要在配置文件中同时指定 ControlMaster、ControlPath 和 ControlPersist 三个选项(它们的默认值都是禁用或者很不友好的值):
| Bash | |
|---|---|
1 2 3 4 | |
其中 %C 是 %l%h%p%r 的 hash,因此连接不同主机的 control socket 不会冲突。但是如果你尝试用相同的用户名和不同的公钥连接同一个目标(例如 [email protected]),由于没有新建连接的过程,你指定的公钥并不会生效,解决方法是再单独指定另一个 ControlPath,或者设置 ControlPath=none 暂时禁用连接复用功能。
文件传输¶
SFTP(Secure File Transfer Protocol)和 SCP(Secure Copy Protocol)都是基于 SSH 的另一种文件传输工具,它用于在本地和远程系统之间安全地复制文件。
- SCP 功能相对简单,主要提供文件的复制功能。
- SFTP 是一个独立的协议,建立在 SSH 之上,提供了一个交互式文件传输会话和更丰富的文件操作功能,包括对文件的浏览、编辑和管理。
Rsync
SCP 和 SFTP 能够提供的文件传输功能较为基础。如果你需要更多的功能,例如增量传输、断点续传、文件校验等,可以考虑使用 Rsync。Rsync 可以使用 SSH 作为传输层,因此可以替代 scp 命令。
SCP¶
SCP 是基于 SSH (Secure Shell) 协议的文件传输工具,它允许用户在本地和远程主机之间安全地复制文件。SCP 使用 SSH 进行数据传输,提供同 SSH 相同级别的安全性,包括数据加密和用户认证。
SCP 命令的基本语法如下:
| Bash | |
|---|---|
1 | |
其中,源文件或目标文件的格式可以是本地路径,或者远程路径,如 用户名@主机名:文件路径。
文件复制¶
从本地复制到远程服务器
| Bash | |
|---|---|
1 | |
或从远程服务器复制到本地
| Bash | |
|---|---|
1 | |
这个命令会提示您输入远程主机上用户的密码,除非您已经设置了 SSH 密钥认证。
Tip
你可以一次性传输多个文件或目录,将它们作为源路径的参数。例如:
| Bash | |
|---|---|
1 | |
常用参数¶
复制目录
如果需要 复制整个目录,需要使用 -r 选项,这表示递归复制:
| Text Only | |
|---|---|
1 2 3 | |
使用非标准端口
如果远程主机的 SSH 服务不是运行在标准端口(22),则可以使用 -P 选项指定端口:
| Bash | |
|---|---|
1 | |
Tip
你也可以在 SSH 客户端配置文件中为 Host remotehost 指定 Port 2222,这样就不需要每次在命令行中指定端口了。
限制带宽
使用 -l 选项可以限制 SCP 使用的带宽,单位是 Kbit/s:
| Bash | |
|---|---|
1 | |
保留文件属性
-p 选项可以保留原文件的修改时间和访问权限:
| Bash | |
|---|---|
1 | |
开启压缩
使用 -C 选项开启压缩,可以减少传输数据量并提升传输速度,特别对于文本文件效果显著。
| Bash | |
|---|---|
1 | |
Tip
你也可以在 SSH 客户端配置文件中为 Host remotehost 指定 Compression yes,这样就不需要每次在命令行中启用压缩了。
SFTP¶
SFTP 是一种安全的文件传输协议,它在 SSH 的基础上提供了一个扩展的功能集合,用于文件访问、文件传输和文件管理。与 SCP 相比,SFTP 提供了更丰富的操作文件和目录的功能,例如列出目录内容、删除文件、创建和删除目录等。由于 SFTP 在传输过程中使用 SSH 提供的加密通道,因此它能够保证数据的安全性和隐私性。
启动 SFTP 会话¶
要连接到远程服务器,可以使用以下命令:
| Bash | |
|---|---|
1 | |
如果远程服务器的 SSH 服务使用的不是默认端口(22),可以使用 -P 选项指定端口:
| Bash | |
|---|---|
1 | |
文件和目录操作¶
ls:列出远程目录的内容。get remote-file [local-file]:下载文件。put local-file [remote-file]:上传文件。mkdir directory-name:创建远程目录。rmdir directory-name:删除远程目录。rm file-name:删除远程文件。chmod mode file-name:改变远程文件的权限。pwd:显示当前远程目录。lpwd:显示当前本地目录。cd directory-name:改变远程工作目录。lcd directory-name:改变本地工作目录。
退出 SFTP 会话¶
输入 exit 或 bye 来终止 SFTP 会话。
使用脚本进行自动化操作
通过创建一个包含 SFTP 命令的批处理文件,你可以 让SFTP 会话自动执行这些命令。例如,你可以创建一个文件 upload.txt,其中包含以下内容:
| Bash | |
|---|---|
1 2 3 4 | |
sftp -b upload.txt username@remotehost 来自动上传文件。
服务端配置¶
服务端的配置与客户端有一些不同点:
- sshd 服务端程序只有很少量的命令行参数,各种配置都在配置文件中完成。特别注意,如果配置文件不存在或者包含错误,sshd 会拒绝启动。
- sshd 仅有一个配置文件
/etc/ssh/sshd_config,它的配置项可以在 [sshd_config(5)][sshd_config.5] 中找到。
sshd 接受 SIGHUP 信号作为重新载入配置文件的方式。sshd -t 命令可以检查配置文件的语法是否正确,这也是大多数发行版提供的 ssh.service 中指定的 ExecStartPre= 命令和第一条 ExecReload= 命令,即在尝试启动和重新加载服务前先检查配置文件的语法。
authorized_keys 文件¶
~/.ssh/authorized_keys 文件是 SSH 服务端用于验证客户端公钥的文件,每行一个公钥,空行或者以 # 开头的行会被当作注释忽略。
authorized_keys 文件还允许为每个公钥指定一些选项,例如:
from="192.0.2.0/24,2001:db8::/32"
: 限制此公钥只能从指定的 IP 地址连接。
expiry-time="197001010800Z"
: 限制此公钥的有效时间,格式为 YYYYMMDDhhmm(服务器的本地时间),或者在其后添加一个大写字母 Z 表示 UTC 时间。适合用于添加临时用途的公钥,确保不会在事后忘记删除。
command="/path/to/command"
: 限制此公钥只能用于执行指定的命令,且不能登录 shell。如果使用此公钥登录时提供了额外的命令(例如 ssh user@host some/other/command),提供的命令将会在 SSH_ORIGINAL_COMMAND 环境变量中传递给指定的命令。
| Text Only | |
|---|---|
1 2 3 | |
no-port-forwarding, no-X11-forwarding, no-agent-forwarding, no-pty, no-user-rc
: 禁止对应的功能。这些选项可以用于限制公钥的功能,例如禁止各种转发和使用终端等。
restrict
: 禁止所有可选功能,相当于同时使用上一条列出的(和没列出的,详情见 man page)所有选项。
| Text Only | |
|---|---|
1 2 3 | |
完整的选项列表可以在 [sshd(8)][sshd.8] 的 AUTHORIZED_KEYS FILE FORMAT 部分找到。
案例:用于备份 LUG FTP 的公钥配置
| Bash | |
|---|---|
1 | |
拆分配置文件¶
从 OpenSSH 7.3p1 开始,ssh_config 和 sshd_config 都支持 Include 选项,可以在主配置文件中 include 其他文件。与 C 的 #include 或 Nginx 的 include 不同,SSH config 里的 Include 不等价于文本插入替换,并且 Include 可以出现在 Host 和 Match 块中,出现在这两个块中的 Include 会被视作条件包含。因此一个(不太常见的)坑是:
错误写法
| Bash | |
|---|---|
1 2 3 4 5 | |
因为 SSH 读取配置文件时是不会看缩进的,因此上面示例中的 Include 仅对 Host example 生效。正确的写法是将其放在一个 Match all 块(或者 Host *)中:
正确写法
| Bash | |
|---|---|
1 2 3 4 5 6 | |
更加推荐的写法是将 Include 放在配置文件开头:
推荐写法
| Bash | |
|---|---|
1 2 3 4 5 | |
一些坑点¶
在 OpenSSH 内部,同一个“代号”可能指代多种(有关联但)不同的细节。例如 ssh-rsa 至少有以下三种不同的含义:
- RSA 密钥对或 RSA 公钥算法(
id_rsa和id_rsa.pub文件) - 基于 RSA / SHA-1 的 SSH 证书的签名算法(
CASignatureAlgorithms)
这种算法已经在 OpenSSH 8.2 中被淘汰,而 OpenSSH 7.2 起就已经支持替代算法 rsa-sha2-256 和 rsa-sha2-512(采用 SHA-256 和 SHA-512 哈希算法),虽然直到 OpenSSH 8.2,使用 RSA CA 私钥签出来的证书才默认采用 rsa-sha2-512 算法。
如果你正在使用一个 RSA CA,那么你需要将已有的证书使用 OpenSSH 8.2 以上的版本重新签名。
如果需要临时兼容 ≤ 7.1 版本的 OpenSSH,可以在 ~/.ssh/config 或 sshd_config 中指定 CASignatureAlgorithms +ssh-rsa,这样就可以使用旧版本的证书签名算法了。
- 基于 RSA / SHA-1 的公钥签名算法套件(
ssh-rsa)。与前面的证书不同,这种签名算法是用于用户登录时的公钥验证,不会保存在文件里,而是在 SSH 协议内部使用。
与前一个采用 SHA-1 作为哈希算法的算法套件类似,OpenSSH 8.8 起也不再默认启用,且替代算法也分别叫做 rsa-sha2-256 和 rsa-sha2-512。好消息是,你不需要重新签发任何证书,只要确保客户端和服务端的 OpenSSH 版本都不低于 7.2 就可以了。
如果需要临时兼容 ≤ 7.1 版本的 OpenSSH,可以通过配置选项 HostkeyAlgorithms 和 PubkeyAcceptedAlgorithms 启用。这两个选项分别控制服务端和客户端的公钥签名算法套件,并且在两端都可以指定。