Reading

用一份 ~/.ssh/config 管好所有服务器:别名、密钥与跳板机

服务器多了以后,IP、端口、密钥、跳板机全靠记忆和备忘录是撑不住的。用一份 ~/.ssh/config 把它们固化成别名,登录任何机器都只要一个短命令。

返回归档
用一份 ~/.ssh/config 管好所有服务器:别名、密钥与跳板机 封面图

适用场景:手里的服务器越来越多,每次登录都要翻笔记找 IP、端口和密钥,或者要先登跳板机再往里跳。这篇教程用一份 ~/.ssh/config 把这些信息固化下来,登录任何一台机器都只需要一个别名。

背景和思路

我一开始管理服务器的方式是把 ssh root@101.xx.xx.xx -p 2222 -i ~/.ssh/aliyun.pem 这样的完整命令存在备忘录里,用的时候复制粘贴。机器到第四台的时候就乱了:密钥对不上、端口记混、还有一台必须从跳板机进。

正确的做法是让 SSH 客户端自己记住这些事。~/.ssh/config 支持按主机写配置块,之后不管是 sshscprsync 还是 VS Code Remote,全部自动生效。

准备工作

  1. 一台 macOS 或 Linux 的本地机器,OpenSSH 7.3 以上(ssh -V 查看,7.3 才支持 ProxyJumpInclude)。
  2. 确认配置文件权限正确,否则 SSH 会直接拒绝读取:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/config
chmod 600 ~/.ssh/config

基本结构:一台机器一个块

Host blog
    HostName 101.37.21.147
    User root
    Port 22
    IdentityFile ~/.ssh/id_ed25519_blog
    IdentitiesOnly yes

Host nas
    HostName 192.168.31.8
    User qsw
    Port 2222
    IdentityFile ~/.ssh/id_ed25519_home
    IdentitiesOnly yes

之后登录只需要:

ssh blog
scp dist.tar.gz blog:/opt/app/

两个容易忽略的点:

  • Host 后面是你自己起的别名,可以随便取;HostName 才是真实地址。
  • IdentitiesOnly yes 很重要。不写的话,SSH 会把 agent 里所有密钥挨个试一遍,密钥多的人会莫名收到服务器的 Too many authentication failures

跳板机:ProxyJump 一行解决

内网机器需要先登跳板机的场景,老写法是 ProxyCommand 配一长串 netcat,现在只需要:

Host bastion
    HostName 47.100.20.5
    User ops
    IdentityFile ~/.ssh/id_ed25519_work

Host db-internal
    HostName 10.0.3.15
    User ops
    ProxyJump bastion
    IdentityFile ~/.ssh/id_ed25519_work

ssh db-internal 会自动先连 bastion 再跳进去,scp 和端口转发同样直接可用。多级跳板用逗号连:ProxyJump bastion1,bastion2

通用默认值放最后

~/.ssh/config 是从上往下匹配、先到先得的,所以通配块 Host * 要放在文件末尾,只兜底那些没被具体块覆盖的选项:

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    AddKeysToAgent yes
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 10m
  • ServerAliveInterval:每 60 秒发一个保活包,防止挂机被防火墙掐断。
  • ControlMaster 三件套:第一条连接建立后复用同一条通道,之后再开新终端连同一台机器几乎是瞬时的,rsync 多次传输也不用重复握手。记得先 mkdir -p ~/.ssh/sockets

配置多了以后:Include 拆文件

机器一多,单文件难维护,可以按用途拆分:

Include conf.d/*.conf

把这一行放在 ~/.ssh/config 的最上面,然后建 ~/.ssh/conf.d/work.conf~/.ssh/conf.d/home.conf 分开管理。注意 Include 的相对路径是相对 ~/.ssh/ 解析的。

验证

不确定某个别名最终会用什么参数时,不要靠猜,让 SSH 自己说:

ssh -G blog | grep -E "^(hostname|user|port|identityfile|proxyjump)"

ssh -G 会输出解析完所有配置后的最终值,排查「为什么连的不是我想的那台机器」时非常好用。

收尾检查

  • ~/.ssh 是 700,config 和所有私钥是 600。
  • 每个块都写了 IdentitiesOnly yes
  • Host * 通配块在文件末尾(或 Include 在最前、通配在最后)。
  • ssh -G 别名 验证过关键机器的最终配置。

这份文件值得纳入 dotfiles 做版本管理,但注意:只提交 config,永远不要把私钥提交进仓库