只要碰 Linux,SSH 就是你每天用最多的工具。但很多人对它的掌握停留在「ssh user@host + 输密码」,把大量时间浪费在重复输入长命令、记一堆 IP、来回跳机器上。这一篇把 SSH 从入门讲到进阶:密钥登录免密码、config 配置文件简化连接、ProxyJump 优雅跳板、端口转发打隧道,让你从「会用」升级到「用得飞起」。
一、SSH 基础:连接与验证
SSH(Secure Shell)通过加密通道远程登录和执行命令。基本用法:
ssh user@host
ssh user@host -p 2222 # 指定端口
ssh user@host "ls -l /data" # 执行单条命令后退出
第一次连接会提示确认主机指纹:
The authenticity of host 'example.com (1.2.3.4)' can't be established.
ED25519 key fingerprint is SHA256:xxxxx.
Are you sure you want to continue connecting (yes/no)?
输入 yes 后,指纹被记入 ~/.ssh/known_hosts。
二、密钥登录:告别密码
密码登录有三个问题:服务器被暴力破解、每次输密码、自动化脚本没法用。密钥登录一次性解决。
生成密钥对
ssh-keygen -t ed25519 -C "your_email@example.com"
-t ed25519:现代推荐算法,比 RSA 更安全更快-C:注释,方便识别- 一路回车用默认路径(
~/.ssh/id_ed25519),可设 passphrase 增强安全
生成的密钥对:
| 文件 | 用途 | 权限 |
|---|---|---|
~/.ssh/id_ed25519 |
私钥,绝不外泄 | 600 |
~/.ssh/id_ed25519.pub |
公钥,发给服务器 | 644 |
分发公钥到服务器
ssh-copy-id user@host
它会自动把公钥追加到服务器的 ~/.ssh/authorized_keys。手动方式:
cat ~/.ssh/id_ed25519.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
服务端权限要求(关键)
SSH 对权限极其敏感,不对就拒绝密钥登录:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519 # 私钥
chmod 644 ~/.ssh/id_ed25519.pub # 公钥
家目录权限也不能太开放(不能是 777):
chmod 755 ~ # 或 700
用指定私钥登录
ssh -i ~/.ssh/mykey user@host
三、ssh_config:不再记长命令
每次敲一长串 ssh -i key -p 2222 user@ip 太累。写在 ~/.ssh/config 里,用别名一键连。
配置文件位置
| 文件 | 作用 |
|---|---|
~/.ssh/config |
用户级(优先) |
/etc/ssh/ssh_config |
全局 |
基本配置
vim ~/.ssh/config
Host web
HostName 192.168.1.100
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519
Host db
HostName 192.168.1.200
User admin
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
配置后,直接:
ssh web # 等价于 ssh -p 2222 -i ... deploy@192.168.1.100
ssh db
Host * 是通配,对所有主机生效,适合放通用参数(如心跳保活)。
常用配置项
| 配置项 | 作用 |
|---|---|
Host |
别名(匹配模式) |
HostName |
真实 IP/域名 |
User |
用户名 |
Port |
端口 |
IdentityFile |
私钥路径 |
ProxyJump |
跳板机 |
ServerAliveInterval |
保活间隔(秒),防断连 |
ForwardAgent |
是否转发 agent |
⚠️ config 文件权限
~/.ssh/config 权限也要正确:
chmod 600 ~/.ssh/config
权限太开放,SSH 会忽略它。
四、sshd_config:服务端安全加固
服务端配置在 /etc/ssh/sshd_config(注意 d 是 daemon)。改完要 systemctl restart sshd。
关键安全项
# 禁用 root 直接登录
PermitRootLogin no
# 禁用密码登录,只允许密钥
PasswordAuthentication no
PubkeyAuthentication yes
# 改默认端口(减少扫描)
Port 2222
# 限制可登录用户
AllowUsers deploy admin
# 禁止空密码
PermitEmptyPasswords no
# 登录超时
LoginGraceTime 30
# 限制认证尝试次数
MaxAuthTries 3
⚠️ 改 sshd 的保命姿势
动 sshd_config 前一定保留一个已连接的会话,并先测配置:
# 1. 语法检查(不改动服务)
sudo sshd -t
# 2. 用新配置起一个测试实例(在另一端口)
sudo /usr/sbin/sshd -t -f /etc/ssh/sshd_config
# 3. 确认无误再重启
sudo systemctl restart sshd
最怕的是:禁用密码登录 + 密钥没配好,直接把自己锁在门外。 改之前先确认密钥能登录。
五、跳板机与 ProxyJump
生产环境常不允许从公网直连内网机器,必须先登录一台跳板机(bastion/jump host) ,再从它连内网。传统方式是手动两跳,麻烦。ProxyJump 一步搞定:
命令行方式
ssh -J jumpuser@jump.example.com:22 user@internal.host
config 配置方式(推荐)
Host jump
HostName jump.example.com
User jumpuser
Port 22
IdentityFile ~/.ssh/id_ed25519
Host internal
HostName 10.0.0.50
User deploy
ProxyJump jump
之后直接:
ssh internal # 自动经 jump 跳转,命令、文件都透传
ProxyJump 的优势:
- 一条命令完成两跳,不用手动中转
scp、rsync、端口转发都自动支持(因为它本质是 SSH 隧道)- 支持多级跳板 :
-J jump1,jump2
多级跳板
ssh -J user1@jump1,user2@jump2 user@target
六、端口转发:SSH 隧道
SSH 能把远程端口「搬」到本地,或把本地端口「推」到远程,用于访问内网服务、绕过网络限制。
本地转发(-L):本地端口 → 远程服务
ssh -L 8080:localhost:80 user@server
含义:访问本机 8080 → 通过 SSH 隧道 → 在 server 上访问 localhost:80。
用途:server 上的服务只监听 127.0.0.1(如数据库),从本地安全访问。
# 本地 13306 → server 上的 3306
ssh -L 13306:localhost:3306 user@server
# 本地连 mysql -h 127.0.0.1 -P 13306
远程转发(-R):远程端口 → 本地服务
ssh -R 9000:localhost:3000 user@server
含义:访问 server 的 9000 → 转发到 本机 3000。常用于把本地开发服务临时暴露出去。
动态转发(-D):SOCKS 代理
ssh -D 1080 user@server
在本机开一个 SOCKS5 代理(1080),用它可以把流量走 server 出去(爬墙/访问内网网段)。
常用附加参数
ssh -L 8080:hostA:80 -N -f user@jumper
-N:不执行远程命令(纯转发)-f:后台运行-T:不分配终端
配合 config:
Host tunnel
HostName jumper.example.com
User deploy
LocalForward 13306 db.internal:3306
LocalForward 16379 redis.internal:6379
七、免密与自动化
ssh-agent:缓存私钥
私钥有 passphrase 时每次都要输,ssh-agent 可以帮你记着:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
之后同一会话内再用私钥就不用输 passphrase。
转发 agent(跳板场景)
Host jump
ForwardAgent yes
连接跳板时把本地 agent 转发过去,跳板上再连其他机器就能用你本地的密钥,而私钥不落地到跳板机(更安全)。
用 SSH 跑命令/传文件
# 执行远程命令
ssh web "df -h && free -h"
# 批量在多台机器执行
for h in web1 web2 web3; do ssh $h "uptime"; done
# 用 rsync 走 SSH
rsync -avz -e ssh /local/ user@host:/remote/
八、⚠️ 常见错误
- 权限太开放导致密钥登录被拒 。
~/.ssh必须 700、authorized_keys必须 600、家目录不能 777。这是最高频的坑。 - 禁用密码前没验证密钥 。结果自己都进不去,只能去机房/控制台救。先确认密钥能登录,再禁用密码。
sshd_config改错直接重启 。先sshd -t语法检查,再保留一个活跃会话。- config 里
Host写成 IP 。Host是别名(匹配你ssh xxx里的 xxx),真实地址放HostName。写反了不生效。 ProxyJump写成ProxyCommand老语法 。新版本用ProxyJump更简洁,别照抄老教程。- 忘记 host key 变化 。服务器重装后 host key 变了,报
REMOTE HOST IDENTIFICATION HAS CHANGED,要删掉known_hosts里对应行。 - 端口转发只监听 localhost 。默认
-L只绑 127.0.0.1,想让同网段其他机器用要加-g或-L 0.0.0.0:端口:...。 - SSH 连接卡住不退出 。加
ServerAliveInterval和ServerAliveCountMax做保活。
九、原理探究:SSH 握手的五个阶段
SSH 不是简单加密,它有一整套握手协议。理解它,就能明白为什么 SSH「既安全又快」。
阶段一:TCP 连接
先建立 TCP 连接(三次握手),默认 22 端口。
阶段二:版本协商与算法协商
双方交换 SSH 版本,协商加密算法(如 chacha20-poly1305)、密钥交换算法(如 curve25519)、消息认证算法(HMAC)。
阶段三:密钥交换(KEX)
双方用 Diffie-Hellman (或 ECDH)在不安全信道上协商出一个共享密钥。关键点:即使有人全程监听,也算不出这个密钥------这就是 SSH 安全的基础。
协商出的密钥用于加密后续所有通信,同时计算出一个会话 ID。
阶段四:服务端认证(Host Key)
服务端用自己的主机密钥 签名,客户端验证这是不是「真要连的机器」。第一次连接时你看到的 fingerprint 确认,以及 known_hosts 机制,都是为了防止中间人攻击。
阶段五:用户认证
用户在加密通道内认证,方式有:
- 密码认证:密码加密传输(但服务器还是要存密码哈希,易被爆破)
- 公钥认证:客户端证明「我持有对应私钥」(不传输私钥),服务端用公钥验证签名
公钥认证的过程(为什么不传私钥也安全):
1. 客户端说:我想用这个公钥登录
2. 服务端查 authorized_keys,找到对应公钥
3. 服务端发一个随机挑战
4. 客户端用私钥对挑战签名
5. 服务端用公钥验证签名 → 通过
全程私钥不出本地,只是「用私钥签了个名」,所以比密码安全得多,也难以暴力破解。
为什么密钥登录能防爆破
密码可以被枚举穷举,而公钥认证需要持有对应私钥才能通过。攻击者没有私钥,无论试多少次都过不了------这就是云服务器几乎都推荐密钥登录的原因。
十、SSH 速查表
# 生成密钥
ssh-keygen -t ed25519 -C "comment"
# 分发公钥
ssh-copy-id user@host
# 用指定私钥/端口
ssh -i ~/.ssh/key -p 2222 user@host
# 跳板机
ssh -J jump@jumphost user@target
# 本地端口转发
ssh -L 8080:localhost:80 user@host -N -f
# 远程端口转发
ssh -R 9000:localhost:3000 user@host -N
# 动态 SOCKS 代理
ssh -D 1080 user@host
# 执行远程命令
ssh host "command"
# 保活(config 里)
# ServerAliveInterval 60
# ServerAliveCountMax 3
掌握 SSH 的三个关键升级点:密钥登录 (免密更安全)、config 别名 (省去重复输入)、ProxyJump 跳板 + 端口转发 (打通复杂网络拓扑)。把 ~/.ssh/config 维护好,你的每一次远程操作都会变得干净利落。下一篇讲远程传输,把 scp、sftp、rsync 三个命令讲透。