SSH 到底解决了什么问题? #
SSH(Secure Shell)最常见的用途,是让本地计算机安全地连接远程 Linux 服务器。
最简单的连接方式是:
ssh root@123.123.123.123 -p 6000这里包含了几个信息:
root:远程服务器上的登录用户123.123.123.123:服务器 IP6000:SSH 服务端口ssh:使用 OpenSSH 客户端建立连接
如果每次都输入这么长的一串命令,会比较麻烦。
因此 SSH 提供了 SSH Key、ssh-agent 和 ~/.ssh/config 等机制,可以把登录过程变得更加方便。
最终我们希望达到这样的效果:
ssh cloud甚至可以让:
scp test.zip cloud:/root/
sftp cloud都直接使用同一个连接配置。
Windows 上的 SSH 文件在哪里? #
Windows OpenSSH 通常使用:
C:\Users\用户名\.ssh\例如:
C:\Users\abc\.ssh\其中可能存在:
.ssh/
├── id_ed25519
├── id_ed25519.pub
├── config
└── known_hosts这些文件作用不同。
| 文件 | 作用 |
|---|---|
id_ed25519 |
SSH 私钥,必须保护好 |
id_ed25519.pub |
SSH 公钥,可以放到服务器 |
config |
SSH 客户端配置 |
known_hosts |
保存已经验证过的服务器主机信息 |
其中最重要的原则是:
私钥留在自己的电脑上,公钥放到服务器上。
不要把 id_ed25519 私钥发给任何人。
生成第一对 SSH Key #
推荐使用 Ed25519:
ssh-keygen -t ed25519程序会询问:
Enter file in which to save the key:直接按 Enter,可以使用默认路径:
C:\Users\abc\.ssh\id_ed25519然后会询问:
Enter passphrase:建议设置一个 passphrase。
完成后会得到:
id_ed25519
id_ed25519.pub可以检查:
Get-ChildItem $HOME\.ssh -Force例如:
Mode Length Name
---- ------ ----
-a---- 464 id_ed25519
-a---- 102 id_ed25519.pub这里:
id_ed25519是私钥。
id_ed25519.pub是公钥。
私钥、公钥和 SSH 登录是什么关系? #
可以把它简单理解成:
本地 Windows
id_ed25519
│
│ 私钥
│
▼
SSH 客户端
│
│ 证明“我拥有对应的私钥”
▼
Debian 服务器
~/.ssh/authorized_keys
│
│ 保存公钥
▼
验证通过服务器不需要保存你的私钥。
服务器只需要保存你的公钥。
因此:
Windows
└── id_ed25519 ← 私钥,只保存在本地
Debian
└── ~/.ssh/authorized_keys
← 保存公钥这是 SSH Key 认证最核心的结构。
在 Debian 上手动安装公钥 #
先在 Windows 查看公钥:
Get-Content $HOME\.ssh\id_ed25519.pub得到类似:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... abc@DESKTOP-aabbcc1122复制完整的一行。
然后登录 Debian。
创建 SSH 目录 #
mkdir -p ~/.ssh设置目录权限:
chmod 700 ~/.ssh创建 authorized_keys #
nano ~/.ssh/authorized_keys把刚才复制的公钥粘贴进去。
例如:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... abc@DESKTOP-aabbcc1122保存后:
chmod 600 ~/.ssh/authorized_keys现在服务器上的结构大致是:
/root/
└── .ssh/
└── authorized_keys如果当前登录用户不是 root,那么 ~ 会对应当前用户的家目录。
例如:
/home/debian/.ssh/~ 到底是什么?
#
在 Linux 中:
~代表当前用户的家目录。
可以通过:
echo $HOME查看。
如果当前用户是 root:
~
=
/root如果当前用户是 debian:
~
=
/home/debian所以:
~/.ssh并不是固定的 /root/.ssh。
它表示:
当前登录用户家目录下面的
.ssh。
另外,Linux 中以 . 开头的文件和目录默认不会被普通 ls 显示。
因此:
ls可能看不到 .ssh。
使用:
ls -la就可以看到隐藏目录。
检查 SSH 目录:
ls -la ~/.sshssh-agent 是什么? #
如果私钥设置了 passphrase,每次使用私钥时理论上都可能需要解锁。
ssh-agent 可以理解成一个本地的“私钥使用代理”。
大致流程:
第一次使用 SSH Key
id_ed25519
│
│ 输入 passphrase
▼
ssh-agent
│
│ 保存已经解锁的身份
▼
后续 SSH / SCP / SFTP 使用这样就不需要每次重新输入私钥 passphrase。
注意:
ssh-agent不会把私钥上传到服务器。
它主要负责在本机管理已经加载的身份。
Windows 上启用 ssh-agent #
Windows 自带 OpenSSH Authentication Agent 服务。
查看状态:
Get-Service ssh-agent如果看到:
Status Name DisplayName
------ ---- -----------
Stopped ssh-agent OpenSSH Authentication Agent可以设置为自动启动:
Set-Service -Name ssh-agent -StartupType Automatic如果出现:
Access is denied说明当前 PowerShell 没有足够权限。
此时需要使用:
以管理员身份运行 PowerShell
然后执行:
Set-Service -Name ssh-agent -StartupType Automatic
Start-Service ssh-agent检查:
Get-Service ssh-agent应该看到:
Running ssh-agent OpenSSH Authentication Agent把 SSH Key 加入 ssh-agent #
回到普通 PowerShell:
ssh-add $HOME\.ssh\id_ed25519输入创建 SSH Key 时设置的 passphrase。
成功后类似:
Identity added: C:\Users\abc\.ssh\id_ed25519检查 agent 中的身份:
ssh-add -l可能看到:
256 SHA256:xxxxxxxxxxxxxxxx... C:\Users\abc\.ssh\id_ed25519 (ED25519)这里显示的是公钥指纹,不是私钥内容。
ssh-agent、passphrase 和私钥之间的关系
#
三个东西不要混淆:
私钥 #
id_ed25519真正用于身份认证的秘密材料。
passphrase #
保护私钥的密码。
它不是服务器登录密码。
ssh-agent #
本地进程,用来管理已经解锁的 SSH Key。
可以理解成:
id_ed25519
│
│ passphrase 解锁
▼
ssh-agent
│
│ 提供身份认证
▼
SSH / SCP / SFTP配置 ~/.ssh/config
#
当服务器越来越多时,每次输入:
ssh root@123.123.123.123 -p 6000会非常麻烦。
可以创建:
C:\Users\abc\.ssh\config例如:
Host cloud
HostName 123.123.123.123
User root
Port 6000
IdentityFile ~/.ssh/id_ed25519这里:
Host cloud是自己定义的别名。
它不是服务器真实的主机名。
于是:
ssh cloud就相当于:
ssh root@123.123.123.123 -p 6000SSH 会自动读取:
HostName
User
Port
IdentityFile为什么建议保留 IdentityFile? #
如果只有一个 SSH Key,OpenSSH 有时可以直接从 ssh-agent 找到合适的 Key。
但以后可能有多个 Key:
id_ed25519
id_work
id_github
id_server这时候可以明确指定:
IdentityFile ~/.ssh/id_ed25519告诉 SSH:
连接这个 Host 时使用这个身份。
所以即使当前不是绝对必要,也建议在配置中明确写出来。
SSH Config 不只是给 ssh 用的 #
这是 config 非常方便的一点。
例如:
Host cloud
HostName 123.123.123.123
User root
Port 6000
IdentityFile ~/.ssh/id_ed25519之后:
SSH #
ssh cloudSCP #
本地上传:
scp test.zip cloud:/root/服务器下载到本地:
scp cloud:/root/test.zip C:\Users\abc\Desktop\SFTP #
sftp cloud这些命令都可以使用 cloud 这个 Host 配置。
SFTP 和 SCP 怎么选择? #
SCP #
适合偶尔传一个文件:
scp test.zip cloud:/root/或者:
scp cloud:/root/test.zip C:\Users\abc\Desktop\复制目录:
scp -r project cloud:/root/SFTP #
适合交互式管理文件:
sftp cloud进入后可以:
ls
cd /root
lcd C:\Users\abc\Desktop
put test.zip
get log.txt其中:
ls查看远程目录。
cd进入远程目录。
lcd切换本地目录。
put上传文件。
get下载文件。
WinSCP 与 OpenSSH Config #
如果平时更喜欢图形化文件管理,可以使用 WinSCP 的 SFTP。
WinSCP 可以导入 OpenSSH 的配置。
例如已经存在:
C:\Users\abc\.ssh\config内容:
Host cloud
HostName 123.123.123.123
User root
Port 6000
IdentityFile ~/.ssh/id_ed25519在 WinSCP 登录界面可以通过:
Tools → Import Sites → OpenSSH config导入 cloud。
这样就不需要重新手动填写:
IP
用户名
端口具体界面可能随 WinSCP 版本变化。
需要注意:
WinSCP 导入 OpenSSH Config 后,会把连接信息转换成 WinSCP 自己的站点配置;它并不意味着以后每次打开 WinSCP 都实时读取 OpenSSH
config。
因此可以把它理解成:
OpenSSH config
│
│ Import
▼
WinSCP SiteOpenSSH 和 WinSCP 的职责可以这样划分 #
一个比较舒服的 Windows SSH 工作流是:
Windows Terminal
│
└── OpenSSH
│
├── ssh cloud
├── scp
└── sftp
WinSCP
│
└── SFTP 图形化文件管理两者可以共享同一套服务器信息,但 WinSCP 有自己的站点配置。
如果习惯命令行:
ssh cloud非常方便。
如果需要拖拽文件:
WinSCP → SFTP更加直观。
多台服务器时的 Config #
当服务器增加以后,可以继续往同一个 config 里添加:
Host cloud
HostName 123.123.123.123
User root
Port 6000
IdentityFile ~/.ssh/id_ed25519
Host work
HostName 10.10.10.20
User dev
Port 22
IdentityFile ~/.ssh/id_work
Host github
HostName github.com
User git
IdentityFile ~/.ssh/id_github于是:
ssh cloud
ssh work
ssh github分别连接不同的目标。
这也是 SSH Config 真正开始体现价值的地方:
把复杂的连接参数隐藏在配置文件中,让命令本身变得简单。
跳板机 / Bastion Host #
如果服务器不能直接从公网访问,而必须经过一台跳板机,可以使用 ProxyJump。
例如:
Host bastion
HostName 123.123.123.123
User root
Port 6000
IdentityFile ~/.ssh/id_ed25519
Host internal
HostName 10.0.0.100
User root
Port 22
IdentityFile ~/.ssh/id_ed25519
ProxyJump bastion以后:
ssh internal实际路径是:
Windows
│
│ SSH
▼
bastion
│
│ SSH
▼
internalProxyJump 的作用是让 SSH 连接经过指定的跳板机。
它和 SSH 端口转发不是同一个概念。
SSH 端口转发 #
例如:
ssh -L 8080:10.0.0.100:8080 bastion意思是:
本地 localhost:8080
│
│ SSH 隧道
▼
bastion
│
▼
10.0.0.100:8080本地访问:
http://localhost:8080实际可能访问的是内网服务器:
10.0.0.100:8080因此:
ProxyJump主要解决:
SSH 登录经过跳板机。
而:
-L / -R / -D主要解决:
网络流量通过 SSH 隧道转发。
known_hosts 是什么? #
第一次连接一台 SSH 服务器时,经常会看到:
The authenticity of host '...' can't be established.
Are you sure you want to continue connecting?确认后,OpenSSH 会把服务器的主机密钥记录到:
C:\Users\abc\.ssh\known_hosts以后再次连接时,SSH 会检查服务器身份是否发生异常变化。
因此:
authorized_keys和:
known_hosts不要混淆。
authorized_keys #
在服务器上。
作用:
哪些客户端公钥允许登录我?
known_hosts #
在客户端上。
作用:
我以前见过哪些服务器,它们的主机身份是什么?
可以简单记成:
服务器:
authorized_keys
↓
“谁可以登录我?”
客户端:
known_hosts
↓
“我连接的服务器是不是之前那台?”常见安全原则 #
私钥永远不要上传 #
不要把:
id_ed25519上传到服务器。
不要发给别人。
不要提交到 Git 仓库。
不要放进公开网盘。
服务器只需要:
id_ed25519.pub对应的公钥内容。
给私钥设置 passphrase #
生成 Key 时建议设置 passphrase。
这样即使私钥文件意外泄露,也多了一层保护。
不要随便删除 known_hosts #
如果 SSH 提示:
REMOTE HOST IDENTIFICATION HAS CHANGED不要第一时间无脑删除 known_hosts。
服务器重装、IP 复用等情况确实可能导致主机密钥变化,但也可能意味着存在安全问题。
应该先确认服务器是否真的更换了主机密钥。
一套推荐的 Windows SSH 工作流 #
最终可以整理成:
C:\Users\abc\.ssh\
│
├── id_ed25519
│ └── 私钥
│
├── id_ed25519.pub
│ └── 公钥
│
├── config
│ └── SSH 连接配置
│
└── known_hosts
└── 已知服务器身份ssh-agent:
ssh-agent
│
└── 管理已经加载的 SSH Key服务器:
~/.ssh/
└── authorized_keys
└── 保存允许登录的公钥日常使用:
ssh cloud文件上传:
scp test.zip cloud:/root/文件下载:
scp cloud:/root/test.zip .交互式 SFTP:
sftp cloud图形化文件管理:
WinSCP
└── SFTP从零到现在,完整流程 #
如果以后需要重新配置一台服务器,可以按照这个思路:
生成 Key
↓
id_ed25519 + id_ed25519.pub
↓
启动 ssh-agent
↓
ssh-add id_ed25519
↓
把公钥放到服务器
↓
~/.ssh/authorized_keys
↓
测试 SSH Key 登录
↓
创建 ~/.ssh/config
↓
Host cloud
↓
ssh cloud
↓
scp / sftp / WinSCP最终,把复杂的:
ssh root@123.123.123.123 -p 6000变成:
ssh cloud这就是 SSH Config 最直接的价值。
而更完整地看,SSH Key、ssh-agent、authorized_keys、config、known_hosts 并不是互相独立的几个知识点,它们实际上共同组成了一套 SSH 工作流:
本地 Windows
┌─────────────────────────────────────┐
│ │
│ id_ed25519 ← 私钥 │
│ │ │
│ ▼ │
│ ssh-agent │
│ │ │
│ ▼ │
│ OpenSSH │
│ │ │
│ ├── config → cloud │
│ │ │
│ └── known_hosts │
│ │
└──────────────┬──────────────────────┘
│
│ SSH
▼
┌─────────────────┐
│ Debian Server │
│ │
│ ~/.ssh/ │
│ └─ authorized_keys
│ │
└─────────────────┘理解了这套关系之后,SSH 的各种命令就不再是需要死记硬背的一堆参数,而只是对这套体系的不同操作。