适用:所有 Linux 耗时:约 40 分钟 前置:E4(网络排查)、E1(权限)

SSH 是 Linux 世界里最重要的一个工具——它让你能操作任何一台联网的机器。

这一篇从"连上去"讲到"连得安全、连得省事"。


一、SSH 是什么,一句话

加密的远程命令行。

你的电脑  ──── 加密隧道 ────→  另一台机器
(客户端)                      (服务端,跑 sshd)

关键点:全程加密。你在里面敲的东西,中途经过的任何路由器都看不到明文。

这也是为什么 SSH 能替代 telnet/rlogin——那些是明文的,密码在网上裸奔。


二、最简单的连接

ssh 用户名@IP地址
ssh zhangsan@192.168.1.100
ssh root@47.242.169.126

第一次连接会问:

The authenticity of host '192.168.1.100' can't be established.
ED25519 key fingerprint is SHA256:xxxxx.
Are you sure you want to continue connecting (yes/no)?

输 yes 回车。 这是"指纹确认"——防止有人中间人攻击。确认后会记到 ~/.ssh/known_hosts,以后不再问。

如果指纹变了(比如重装了服务器),会警告 REMOTE HOST IDENTIFICATION HAS CHANGED。 可能是重装,也可能是被攻击。 确认是前者的话:

ssh-keygen -R 192.168.1.100     # 删掉旧记录

不要习惯性 -o StrictHostKeyChecking=no——那等于关掉这层保护。


三、常用参数

参数作用例子
-p 端口指定端口(不是 -P)ssh -p 2222 user@host
-i 密钥文件指定私钥ssh -i ~/.ssh/mykey user@host
-v详细输出(排障用)ssh -v user@host
-N不执行命令(只建隧道)ssh -N -L ...
-f后台运行ssh -f -N -L ...
-L本地端口转发见第七节
-R远程端口转发见第七节

端口参数是小写 -p。scp 才是大写 -P。这个不一致坑过很多人。


四、密钥登录:不用记密码,还更安全

原理(一句话)

你有一对钥匙:
  私钥(id_ed25519)    ← 留在自己电脑上,绝不外传
  公钥(id_ed25519.pub)← 放到目标机器的 authorized_keys 里

连接时:服务器用公钥出一道题,只有你的私钥能答对 → 证明是你

私钥永远不离开你的机器,所以比密码安全——服务器被攻破,也拿不到你的私钥。

第一步:生成密钥对

ssh-keygen -t ed25519 -C "你的备注"

一路回车(默认路径 ~/.ssh/id_ed25519)。

如果要设密码短语(passphrase):可以设,更安全(私钥被偷了也用不了),但每次用要输。 建议:个人电脑可以不设,笔记本建议设。

-t ed25519 是现代推荐(比 RSA 短、快、安全)。老系统可能不支持,那就用 -t rsa -b 4096。

生成后:

ls -l ~/.ssh/
# id_ed25519        ← 私钥(权限必须 600,绝不能给别人)
# id_ed25519.pub    ← 公钥(可以随便给)

第二步:把公钥放到目标机器

方法 A:一条命令(最简单)

ssh-copy-id 用户名@目标IP

输入一次密码,之后就能免密登录。

方法 B:手动(ssh-copy-id 不可用时)

# 在本地
cat ~/.ssh/id_ed25519.pub
# 复制输出的整行

# 登录目标机器
ssh 用户名@目标IP
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "刚才复制的那一整行" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

权限必须对,否则 SSH 会拒绝使用:

  • ~/.ssh → 700
  • ~/.ssh/authorized_keys → 600

第三步:验证

ssh 用户名@目标IP
# 应该不问密码,直接进去了

五、配置文件:把常用连接存起来

每次敲 ssh -p 2222 zhangsan@192.168.1.100 太累。写进 ~/.ssh/config:

nano ~/.ssh/config
Host myserver
    HostName 192.168.1.100
    User zhangsan
    Port 2222
    IdentityFile ~/.ssh/id_ed25519

Host work
    HostName 47.242.169.126
    User root
    IdentityFile ~/.ssh/id_ed25519

之后只要:

ssh myserver
ssh work

这个配置文件值得花五分钟配好。 尤其机器多了以后。

更多有用选项:

Host *
    ServerAliveInterval 60      # 每 60 秒发心跳,防止空闲断线
    ServerAliveCountMax 3       # 3 次没响应就断开
    Compression yes             # 压缩传输(慢网络有用)
    AddKeysToAgent yes          # 自动加载密钥到 agent

六、ssh-agent:密码短语只输一次

如果你给私钥设了密码短语,每次都要输很烦。ssh-agent 能帮你在一个会话里记住。

# 启动 agent(大多数桌面环境已自动启动)
eval "$(ssh-agent -s)"

# 把密钥加进去(输一次密码短语)
ssh-add ~/.ssh/id_ed25519

# 看已加载的
ssh-add -l

之后这个终端里所有 SSH 连接都不用再输。

写进 ~/.bashrc 自动加载(可选):

if [ -z "$SSH_AUTH_SOCK" ]; then
    eval "$(ssh-agent -s)" > /dev/null
    ssh-add ~/.ssh/id_ed25519 2>/dev/null
fi

七、端口转发:SSH 的隐藏超能力

这是 SSH 最被低估的功能。 能把远程的端口"搬"到本地,或反过来。

场景 1:远程数据库不让公网访问,但你要连

ssh -L 3307:127.0.0.1:3306 zhangsan@服务器IP

意思:把服务器上的 3306 映射到我本地的 3307。

之后本地连 127.0.0.1:3307 就等于连服务器的 MySQL。而 MySQL 依然只监听服务器本地,公网访问不到。

本地 3307  ──加密隧道──→  服务器 127.0.0.1:3306

场景 2:只建隧道,不开 shell

ssh -N -L 3307:127.0.0.1:3306 zhangsan@服务器IP

-N = 不执行远程命令,只转发。不占一个 shell。

后台运行:

ssh -f -N -L 3307:127.0.0.1:3306 zhangsan@服务器IP

场景 3:让远程机器访问我的服务(-R)

ssh -R 8080:127.0.0.1:8000 zhangsan@服务器IP

意思:把我本地的 8000 暴露到服务器的 8080。

用途:本地开发时,让别人通过服务器访问你的开发环境(做演示、给客户看)。

⚠️ -R 默认只绑服务器本地。要让外部访问,服务器 sshd_config 里需要 GatewayPorts yes。 这有安全风险——等于把你的本地服务暴露出去。用完就断。


八、断线了怎么办:tmux / screen

SSH 断线,正在跑的命令会被杀掉。 长任务(编译、下载、备份)会被打断。

解法:在远程机器上跑 tmux,断线后重连还能接上。

# 在远程机器上
sudo apt install tmux
tmux new -s work        # 新建会话

# 里面跑你的长任务

# 断线了,重新 ssh 上去
tmux attach -t work     # 接回来,任务还在跑

tmux 常用:

操作按键
断开(任务继续跑)Ctrl + B 然后 d
列出会话tmux ls
接回会话tmux attach -t 名字
新建窗口Ctrl + B 然后 c
切换窗口Ctrl + B 然后 数字

原则:任何超过 5 分钟的命令,都放进 tmux 里跑。 这条能省你无数次重来。


九、服务器端的加固(如果你是管理员)

看 SSH 服务状态

systemctl status ssh        # Debian 系
systemctl status sshd       # RPM 系

注意服务名不一样,这是最容易搞混的。

三个必做的加固

编辑 /etc/ssh/sshd_config:

# 1. 禁止 root 直接登录(改用普通用户 + sudo)
PermitRootLogin no

# 2. 只允许密钥登录,禁用密码
PasswordAuthentication no
PubkeyAuthentication yes

# 3. 改端口(可选,减少扫描噪音)
Port 2222

改完必须验证配置再重启:

sudo sshd -t          # 语法检查
sudo systemctl reload ssh    # 平滑重载,不断现有连接

⚠️ 最危险的错误:改完配置把自己锁在外面。 安全做法:保持当前 SSH 会话不断开,另开一个窗口测试新连接。新连接能进,再关旧的。 验证失败就改回来——旧会话还在,你还能救。

看谁在尝试登录

sudo lastb                        # 失败的登录记录
sudo grep "Failed password" /var/log/auth.log | tail -20
sudo journalctl -u ssh -n 50

公网服务器上,你会看到大量暴力破解尝试(每秒几十次都常见)。这就是为什么密码登录必须关。

fail2ban:自动封 IP

sudo apt install fail2ban
sudo systemctl enable --now fail2ban

默认配置就能用(5 次失败封 10 分钟)。但在有些系统上默认配置不生效,需要检查:

sudo fail2ban-client status sshd
sudo iptables -L -n | grep f2b    # 看有没有真封

这个坑我踩过:fail2ban 配了 banaction = firewallcmd-rich-rules 但系统没跑 firewalld → 每次 ban 都报错,IP 一个没封,日志里还显示"Total banned: 14"全是假动作。 正确做法:banaction = iptables-multiport,然后实测封一个测试 IP 看 iptables 里有没有条目。


十、动手:五个练习

练习 1:生成密钥并查看

ssh-keygen -t ed25519 -C "test-key"
ls -l ~/.ssh/
cat ~/.ssh/id_ed25519.pub

注意:id_ed25519(无后缀)是私钥,内容绝对不能贴给任何人。

练习 2:配一个 ssh config 条目

nano ~/.ssh/config
Host test
    HostName 127.0.0.1
    User 你的用户名

保存后:

ssh test      # 连自己(需要 sshd 在跑)

练习 3:验证权限检查

chmod 644 ~/.ssh/id_ed25519     # 故意改错
ssh -v 某主机 2>&1 | grep -i "bad permissions"

会看到警告。改回来:

chmod 600 ~/.ssh/id_ed25519

这个练习让你亲眼看到"权限不对 SSH 就不用"的行为。

练习 4:本地端口转发(有第二台机器时)

ssh -N -L 8080:127.0.0.1:80 用户名@目标IP
# 另开一个终端
curl http://127.0.0.1:8080

练习 5:tmux 断线恢复

# 在远程机器上
tmux new -s test
# 跑一个长命令
ping 8.8.8.8

# Ctrl+B 然后 d   (断开)
tmux ls
tmux attach -t test   # 接回来,ping 还在跑

十一、验证:你过关了吗

  • 会用 ssh 用户@IP 连接
  • 会用 ssh-keygen 生成密钥,知道私钥/公钥的区别
  • 会用 ssh-copy-id 配免密登录
  • 知道 ~/.ssh 要 700、私钥要 600
  • 会写 ~/.ssh/config 简化连接
  • 会用 scp/rsync 传文件(见下一篇)
  • 会用 -L 做本地端口转发
  • 会用 tmux 让长任务熬过断线
  • 知道改 sshd 配置时不能断开当前会话

十二、不行怎么办

Q1:Permission denied (publickey) 三个原因,按顺序查:

# ① 私钥权限太宽
ls -l ~/.ssh/id_ed25519     # 必须是 -rw-------

# ② 公钥没放对
ssh 用户@主机 "cat ~/.ssh/authorized_keys"   # 看有没有你的公钥

# ③ 用错了密钥
ssh -v 用户@主机 2>&1 | grep "Offering public key"

Q2:Connection refused SSH 服务没跑,或端口不对:

# 在目标机器上
systemctl status ssh
ss -ltnp | grep :22

或者防火墙拦了(云服务器还要看安全组)。

Q3:Connection timed out 包没到——网络不通或防火墙丢包。见 E4 网络排查。

Q4:REMOTE HOST IDENTIFICATION HAS CHANGED 指纹变了。先确认是不是重装/换机器,是的话:

ssh-keygen -R 主机IP

Q5:连上了但很卡、经常断 加心跳:

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

Q6:ssh-copy-id 不存在 手动做(见第四节方法 B),或者用一行命令:

cat ~/.ssh/id_ed25519.pub | ssh 用户@主机 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Q7:改了 sshd_config 后连不上了 如果旧会话还在:改回来,systemctl reload ssh。 如果已经断了:只能通过云控制台的 VNC/串口登录,或者本地控制台。

这就是为什么要"保持旧会话不断开再测试新连接"。


十三、一句话总结

ssh 用户@IP 连上去;ssh-keygen + ssh-copy-id 免密。

~/.ssh/config 存连接;-L 做隧道;tmux 防断线。

服务器端:关密码登录、禁 root、装 fail2ban——但改配置时别断了后路。


← 上一篇 T2|压缩与归档 下一篇 → T4|文件传输:scp / rsync / sftp