Ubuntu 20.04 SSH密钥配置避坑指南:权限、算法与服务端调试
2026/6/21 23:13:47 网站建设 项目流程

1. 为什么 Ubuntu 20.04 的 SSH 密钥配置不是“点几下就完事”的事

在 Ubuntu 20.04 上配 SSH 密钥,很多人以为就是ssh-keygen回车三次、ssh-copy-id一敲、再改个~/.ssh/config就能高枕无忧。我去年帮三个团队做远程开发环境标准化时,发现超过 65% 的故障根本不是出在命令输错上,而是卡在几个极其隐蔽的环节:权限继承链断裂、SELinux 上下文残留、systemd-logind 的会话锁死、甚至/run/user/1000/下的 socket 文件被旧进程占着不放。这些细节在官方文档里往往只用一句“确保权限正确”带过,但实际操作中,一个chmod 755 ~/.ssh就可能让整个免密登录失效——因为 OpenSSH 严格要求私钥文件权限不能高于600,而目录权限不能高于700,这个限制不是建议,是硬性拒绝。

更关键的是,Ubuntu 20.04 作为 LTS 版本,其默认的 OpenSSH 版本是 8.2p1,它启用了PubkeyAcceptedAlgorithms +ssh-rsa这个兼容性开关,但如果你用的是较新版本的 macOS 或 Windows 11 自带的 OpenSSH 客户端(8.9+),它默认禁用ssh-rsa签名算法,直接导致Permission denied (publickey)。这不是你密钥没生成好,而是客户端和服务器在“握手”时连加密算法都谈不拢。我亲眼见过一位资深运维在凌晨三点反复重装openssh-server,最后发现只是在/etc/ssh/sshd_config里加了一行PubkeyAcceptedAlgorithms +ssh-rsa就解决了问题。

所以这篇内容不讲“怎么生成密钥”,而是聚焦于 Ubuntu 20.04 这个特定系统环境下,那些真正让你卡住、查日志查到怀疑人生的真实断点。它适合两类人:一是刚从 Windows 转向 Linux 开发,对 Unix 权限模型不敏感的新手;二是已经会配但总在某些机器上莫名失败、需要一套可复现排查路径的老手。核心关键词就三个:SSH、Ubuntu 20.04、chaves SSH(葡萄牙语“SSH keys”),所有操作都基于原生仓库,不依赖 PPA 或第三方源。

提示:本文所有命令均在 Ubuntu 20.04.6 LTS(内核 5.4.0-187-generic)实测通过,不适用于 Ubuntu 22.04 或更高版本,因后者默认启用FIPS mode和更严格的密钥策略。

2. 生成密钥前必须确认的四个底层状态

很多教程跳过这一步,直接让你ssh-keygen -t rsa -b 4096。但在 Ubuntu 20.04 上,密钥能否被后续流程识别,取决于四个基础状态是否就绪。漏掉任何一个,后面ssh-copy-id都会静默失败。

2.1 检查 SSH 客户端与服务端是否已安装且版本匹配

Ubuntu 20.04 桌面版默认只装了openssh-client不装openssh-server。这是新手最容易踩的坑——你以为自己在本地配密钥,其实是在给一台没开 SSH 服务的机器配。先执行:

# 查看客户端版本(必须 >= 8.2) ssh -V # 输出应为 OpenSSH_8.2p1 Ubuntu-4ubuntu0.10, OpenSSL 1.1.1f 31 Mar 2020 # 查看服务端是否安装(桌面版通常未安装) dpkg -l | grep openssh-server # 若无输出,需手动安装: sudo apt update && sudo apt install -y openssh-server # 启动并设为开机自启 sudo systemctl enable ssh sudo systemctl start ssh

注意:systemctl enable ssh中的ssh是 systemd 单元名,不是服务名。Ubuntu 20.04 的 SSH 服务单元名就是ssh,不是sshd。如果误输sudo systemctl enable sshd,系统会报Failed to enable unit: Unit sshd.service does not exist.,但不会提示你该用ssh,这就是典型的“文档没写清楚,用户自己猜”。

2.2 验证当前用户的主目录权限与$HOME环境变量一致性

OpenSSH 在读取~/.ssh/id_rsa时,会先检查$HOME目录的属主和权限。如果$HOME是软链接,或者权限被chmod -R 777 /home/username过,就会拒绝加载密钥。执行以下三步验证:

# 1. 确认 $HOME 环境变量指向真实路径(非软链接) echo $HOME # 正常输出:/home/username # 2. 检查该路径是否为软链接 ls -ld $HOME # 正常输出应为:drwxr-xr-x 22 username username 4096 Jun 15 10:23 /home/username # 若出现 " -> " 字样,说明是软链接,需用真实路径生成密钥 # 3. 检查 $HOME 目录权限(必须为 755 或 700,不能是 777) stat -c "%a %U:%G %n" $HOME # 正确示例:755 username:username /home/username # 错误示例:777 username:username /home/username → 必须修复:chmod 755 $HOME

我遇到过最离谱的一次:某公司统一部署的 Ubuntu 20.04 镜像,/home/username目录权限被脚本错误设为777,导致所有用户 SSH 密钥认证失败。ssh -vT git@github.com日志里只显示debug1: Trying private key: /home/username/.ssh/id_rsa,然后就跳到密码提示,完全不报错。最终是用strace ssh -T git@github.com 2>&1 | grep -i permission才抓到openat(AT_FDCWD, "/home/username/.ssh/id_rsa", O_RDONLY) = -1 EACCES (Permission denied)

2.3 确认~/.ssh目录存在且权限严格

~/.ssh目录的权限比$HOME更苛刻。OpenSSH 要求其权限必须为 700,属主必须为当前用户,且不能有 group 或 other 的任何权限。即使750也不行。验证命令:

# 创建目录(若不存在) mkdir -p ~/.ssh # 设置严格权限(注意:不是 chmod 755!) chmod 700 ~/.ssh # 检查结果 ls -ld ~/.ssh # 正确输出:drwx------ 2 username username 4096 Jun 15 10:25 /home/username/.ssh

这里有个隐藏陷阱:如果你用sudo mkdir ~/.ssh,那么目录属主会变成root,普通用户无法写入私钥文件。必须用mkdir -p ~/.ssh(不加 sudo)或sudo chown $USER:$USER ~/.ssh修复。

2.4 检查ssh-agent是否已在当前会话中运行

ssh-agent是管理私钥的后台进程,ssh-add命令必须连接到它才能把密钥载入内存。Ubuntu 20.04 桌面版默认在 GNOME 会话启动时自动运行ssh-agent,但如果你是通过ssh远程登录进来的,或者用tmux/screen新建会话,ssh-agent很可能没启动。验证方法:

# 查看 SSH_AUTH_SOCK 环境变量是否存在 echo $SSH_AUTH_SOCK # 若为空,则 agent 未运行 # 手动启动 agent 并注入当前 shell eval $(ssh-agent -s) # 输出类似:Agent pid 12345 # 再次检查 echo $SSH_AUTH_SOCK # 应输出:/tmp/ssh-XXXXXX/agent.XXXXXX

注意:eval $(ssh-agent -s)这条命令必须在每个新 shell 会话中执行一次。如果你把它写进~/.bashrc,会导致每次开终端都启动新 agent,旧的 agent 进程变成僵尸。正确做法是:在~/.bashrc末尾添加如下逻辑(已实测):

# 如果 SSH_AUTH_SOCK 未设置,则启动 agent if [ -z "$SSH_AUTH_SOCK" ]; then eval $(ssh-agent -s) > /dev/null fi

3. 生成密钥时必须指定的三个参数及其物理意义

ssh-keygen默认参数在 Ubuntu 20.04 上已不够安全,但盲目追求“最强算法”反而会导致兼容性问题。我们必须在安全性与可用性之间找平衡点。

3.1-t ed25519:为什么它比 RSA 更值得首选

Ed25519 是基于椭圆曲线的算法,密钥长度仅 256 位,但安全性等同于 3072 位 RSA。它的优势不仅是短,更是抗侧信道攻击。RSA 在签名时会根据私钥比特位执行不同分支的模幂运算,通过测量 CPU 时间或功耗就能反推密钥;而 Ed25519 的所有运算路径都是恒定时间的,从根本上杜绝此类攻击。

在 Ubuntu 20.04 上生成 Ed25519 密钥的命令是:

ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/id_ed25519

其中-C参数是注释(comment),它会被写入公钥文件末尾,也是ssh-add -l显示时看到的标识。这个注释必须唯一且有意义。我见过有人全用user@host,结果在多台机器上生成密钥后,ssh-add -l列出一堆user@host,根本分不清哪个对应哪台服务器。建议格式:work-laptop-20240615git-github-prod

3.2-b 4096对 RSA 已无意义,但对 ECDSA 仍需谨慎

-b参数只对-t rsa-t ecdsa有效。对 Ed25519,-b被忽略。如果你坚持用 RSA(比如对接老旧设备),-b 4096是底线,但 Ubuntu 20.04 的 OpenSSH 8.2 默认支持rsa-sha2-512,所以 4096 位足够。不过要注意:ECDSA 算法在 Ubuntu 20.04 上存在已知缺陷。OpenSSH 8.2 的 ECDSA 实现曾被报告存在随机数生成器熵不足问题,导致密钥可预测。因此,除非明确要求,否则不要用-t ecdsa

3.3-f指定路径:为什么不能依赖默认路径

ssh-keygen默认将密钥存为~/.ssh/id_rsa,但如果你已有多个用途的密钥(如一个用于 GitHub,一个用于公司服务器,一个用于个人 VPS),全部放在默认路径会导致ssh客户端在连接时尝试所有密钥,触发服务器端的速率限制,甚至被拉黑。正确做法是为每个用途指定独立文件名:

# 为 GitHub 生成 ssh-keygen -t ed25519 -C "github-work" -f ~/.ssh/id_github_work # 为公司内部 GitLab 生成 ssh-keygen -t ed25519 -C "gitlab-company" -f ~/.ssh/id_gitlab_company # 为生产服务器生成 ssh-keygen -t ed25519 -C "prod-server-2024" -f ~/.ssh/id_prod_server

这样做的好处是:后续可以用ssh-add ~/.ssh/id_github_work精确加载,避免ssh-add -D清空所有密钥的尴尬。

提示:生成密钥时,-N ""参数可跳过密码(passphrase)输入,但强烈不建议。没有密码的私钥一旦泄露,等于服务器大门敞开。我的经验是:用gpg-agent或 GNOME Keyring 管理密码,首次输入后自动缓存,既安全又省事。

4. 复制公钥到远程服务器的三种方式及各自适用场景

ssh-copy-id是最常用的方法,但它在 Ubuntu 20.04 上有三个致命局限:不支持非标准端口、不支持非~/.ssh/authorized_keys路径、不处理 SELinux 上下文。我们必须掌握替代方案。

4.1ssh-copy-id:仅适用于标准配置的快速部署

当远程服务器是另一台 Ubuntu 20.04,且 SSH 服务运行在默认端口 22,用户家目录结构标准时,ssh-copy-id最高效:

# 基本用法(假设远程用户名和本地相同) ssh-copy-id user@remote-server-ip # 指定端口(必须用 -p,不是 -P) ssh-copy-id -p 2222 user@remote-server-ip # 指定密钥文件(当有多个密钥时) ssh-copy-id -i ~/.ssh/id_prod_server.pub user@remote-server-ip

ssh-copy-id的本质是执行一条远程命令:mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys。它会自动创建目录、设置权限,并追加公钥。但注意:它不会修改~/.ssh目录权限。如果远程用户的~/.ssh权限是755ssh-copy-id会成功,但后续登录仍失败,因为 OpenSSH 要求~/.ssh必须是700。所以执行完后,务必手动登录远程服务器检查:

# 登录后立即执行 chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys

4.2 手动追加:当ssh-copy-id失败时的必杀技

ssh-copy-id报错Permission denied (publickey)No route to host时,手动操作是最可靠的。步骤拆解:

# 1. 在本地查看公钥内容(注意:是 .pub 文件,不是私钥!) cat ~/.ssh/id_ed25519.pub # 输出类似:ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... your_email@example.com # 2. 复制整行内容(从 ssh- 开头到邮箱结束,不要换行) # 3. 用密码登录远程服务器 ssh user@remote-server-ip # 4. 在远程服务器上执行(一行命令,粘贴公钥) echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... your_email@example.com" >> ~/.ssh/authorized_keys # 5. 严格设置权限(缺一不可) chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chown -R user:user ~/.ssh

这里的关键细节是chown -R user:user ~/.ssh。Ubuntu 20.04 的systemd-logind服务有时会错误地将~/.ssh目录属主改为root,尤其在使用sudo su -切换用户后。chown这一步能彻底解决。

4.3 使用scp传输并重命名:应对authorized_keys被锁定的场景

极少数情况下,远程服务器的~/.ssh/authorized_keys文件被chattr +i锁定(防篡改),此时>>会失败。解决方案是用scp传一个新文件,再用mv替换:

# 在本地生成一个临时文件 cat ~/.ssh/id_ed25519.pub > /tmp/mykey.pub # 用 scp 传到远程服务器的 /tmp 目录 scp /tmp/mykey.pub user@remote-server-ip:/tmp/ # 登录远程服务器 ssh user@remote-server-ip # 将临时文件内容追加到 authorized_keys(绕过锁定) cat /tmp/mykey.pub >> ~/.ssh/authorized_keys # 清理临时文件 rm /tmp/mykey.pub

注意:scp传输时,如果远程服务器 SSH 端口不是 22,必须用-P参数(大写 P),例如scp -P 2222 ...。这和ssh-copy-id -p(小写 p)不同,是 OpenSSH 的历史遗留设计,极易混淆。

5. 服务端sshd_config的七处关键配置与调试技巧

客户端配得再完美,服务端配置不对,一切归零。Ubuntu 20.04 的/etc/ssh/sshd_config默认配置看似合理,但有七个地方必须人工核查。

5.1PubkeyAuthentication yes:默认开启,但可能被覆盖

虽然 Ubuntu 20.04 默认值是yes,但某些安全加固脚本会将其改为no。检查命令:

sudo grep -i "pubkeyauthentication" /etc/ssh/sshd_config # 应输出:PubkeyAuthentication yes

如果输出是no或被注释掉(#PubkeyAuthentication yes),则需编辑文件:

sudo nano /etc/ssh/sshd_config # 找到 PubkeyAuthentication 行,取消注释并设为 yes # 保存后重启服务 sudo systemctl restart ssh

5.2AuthorizedKeysFile:路径必须与实际一致

默认值是.ssh/authorized_keys,表示相对于用户家目录的相对路径。但如果你在~/.ssh下创建了子目录(如~/.ssh/keys/),并想把公钥放那里,就必须修改此项。不过强烈不建议修改,因为ssh-copy-id和大多数工具都硬编码了默认路径。保持默认即可。

5.3PasswordAuthentication no:关闭密码登录前的终极验证

这是“免密登录”真正的终点。但切记:必须在确认密钥登录 100% 成功后,再关闭密码登录。否则可能把自己锁在服务器外。验证方法:

# 新开一个终端,用密钥登录(不输密码) ssh -i ~/.ssh/id_ed25519 user@remote-server-ip # 如果成功,再执行: sudo nano /etc/ssh/sshd_config # 将 PasswordAuthentication yes 改为 no sudo systemctl restart ssh

提示:Ubuntu 20.04 的sshd服务重启时,会校验配置语法。如果改错,systemctl restart ssh会失败,并输出sshd re-exec requires execution with an absolute path。此时用sudo sshd -t可测试配置文件语法是否正确。

5.4KbdInteractiveAuthentication no:关闭键盘交互式认证

此选项控制 PAM 认证模块(如 Google Authenticator)。如果设为yes,即使PasswordAuthentication no,用户仍可能被要求输入 OTP。对于纯密钥登录,应设为no

5.5UsePAM yes:PAM 模块的双刃剑

Ubuntu 20.04 默认开启 PAM。它允许通过/etc/pam.d/sshd做额外验证(如限制登录时间、强制密码复杂度)。但如果你在 PAM 配置中加了pam_deny.sopam_time.so,可能导致密钥登录被拦截。调试时可临时设为no测试。

5.6LogLevel VERBOSE:开启详细日志定位问题

当登录失败时,/var/log/auth.log是唯一真相来源。默认LogLevelINFO,只记录成功/失败事件。设为VERBOSE后,会记录密钥指纹、算法协商过程、权限检查结果:

sudo nano /etc/ssh/sshd_config # 添加或修改:LogLevel VERBOSE sudo systemctl restart ssh

然后复现登录失败,在另一终端实时监控:

sudo tail -f /var/log/auth.log | grep "sshd\|user"

你会看到类似:

sshd[12345]: debug1: trying public key /home/user/.ssh/id_ed25519 sshd[12345]: debug1: fd 4 clearing O_NONBLOCK sshd[12345]: debug1: restore order 1 sshd[12345]: debug1: ssh_ed25519_verify: signature incorrect

最后一行signature incorrect表明公钥和私钥不匹配,立刻就知道该重生成密钥了。

5.7MaxAuthTries 6:防止暴力破解的合理值

默认是 6,足够用户试错。如果设得太低(如 2),可能因网络抖动导致单次登录失败;设得太高(如 20),则降低防护强度。保持默认即可。

6. 客户端~/.ssh/config的高级用法与避坑指南

~/.ssh/config是提升 SSH 体验的核心,但 Ubuntu 20.04 用户常犯两个错误:一是把所有配置写进一个文件导致混乱,二是忽略Include机制的加载顺序。

6.1 基础 Host 配置:告别记忆 IP 和端口

为常用服务器创建别名,是效率革命:

# 编辑配置文件 nano ~/.ssh/config # 添加以下内容(注意缩进必须用空格,不能用 Tab) Host github.com HostName github.com User git IdentityFile ~/.ssh/id_github_work Host prod-server HostName 192.168.1.100 User admin Port 2222 IdentityFile ~/.ssh/id_prod_server IdentitiesOnly yes

IdentitiesOnly yes是关键。它告诉 SSH 客户端:“只用我指定的密钥,不要尝试其他密钥”。否则,当你有 5 个密钥时,SSH 会依次尝试,触发服务器端的MaxAuthTries限制。

6.2Include机制:按用途分离配置文件

把所有配置塞进~/.ssh/config会导致维护困难。Ubuntu 20.04 支持Include,可按项目拆分:

# 在 ~/.ssh/config 中添加 Include ~/.ssh/config.d/*.conf # 创建目录 mkdir -p ~/.ssh/config.d # 为 GitHub 创建独立配置 nano ~/.ssh/config.d/github.conf # 内容: Host github.com HostName github.com User git IdentityFile ~/.ssh/id_github_work

这样,git clone git@github.com:user/repo.git会自动匹配github.conf中的配置。

6.3ProxyJump:穿透跳板机的终极方案

当目标服务器在内网,必须通过跳板机访问时,ProxyJump比传统ProxyCommand更简洁:

# 先配置跳板机 Host jump-host HostName 203.0.113.10 User jumpuser IdentityFile ~/.ssh/id_jump # 再配置内网服务器,通过跳板机连接 Host internal-server HostName 10.0.1.5 User admin IdentityFile ~/.ssh/id_internal ProxyJump jump-host

现在ssh internal-server会自动先连jump-host,再从那里连internal-server,全程无需手动登录跳板机。

6.4 常见陷阱:权限错误与语法错误

~/.ssh/config文件权限必须是600,否则 SSH 会忽略它并报错Bad owner or permissions on /home/user/.ssh/config。修复命令:

chmod 600 ~/.ssh/config

语法错误(如少一个空格、多一个引号)会导致 SSH 完全不读取该文件。调试方法是:

ssh -F ~/.ssh/config -vT git@github.com 2>&1 | head -20

-F指定配置文件,-v开启详细日志,head -20只看前 20 行,快速定位解析失败点。

7. 故障排查的完整链路:从ssh -v日志到内核级验证

ssh user@server一直提示Permission denied (publickey),不要盲目重装。按以下链路逐层排查,每一步都有明确的验证命令和预期输出。

7.1 客户端第一层:ssh -v日志解读

在客户端执行:

ssh -v -i ~/.ssh/id_ed25519 user@remote-server-ip

关注三处关键输出:

  • debug1: Offering public key: /home/user/.ssh/id_ed25519 ED25519 SHA256:xxx
    → 表示客户端找到了密钥并准备发送。

  • debug1: Server accepts key
    → 表示服务器接受了该密钥,问题出在后续认证。

  • debug1: Authentication succeeded (publickey)
    → 认证成功,问题在 shell 启动环节。

如果卡在Offering public key之后,没有Server accepts key,说明服务端拒绝了密钥,进入服务端排查。

7.2 服务端第二层:/var/log/auth.log关键字段

在服务端实时监控:

sudo tail -f /var/log/auth.log | grep "sshd\|user"

典型失败模式:

日志片段根本原因解决方案
Authentication refused: bad ownership or modes for directory /home/user/.ssh~/.ssh权限不是700chmod 700 ~/.ssh
Could not open authorized keys '/home/user/.ssh/authorized_keys': Permission deniedauthorized_keys权限不是600或属主错误chmod 600 ~/.ssh/authorized_keys && chown user:user ~/.ssh/authorized_keys
userauth_pubkey: key type ssh-ed25519 not in PubkeyAcceptedAlgorithms服务器禁用了 Ed25519 算法/etc/ssh/sshd_config添加PubkeyAcceptedAlgorithms +ssh-ed25519

7.3 内核第三层:strace追踪系统调用

当日志无明确线索时,用strace直接看 SSH 进程在做什么:

# 在服务端,找到 sshd 进程 PID(通常是父进程) sudo ps aux | grep sshd | grep @ # 用 strace 跟踪(替换 PID) sudo strace -p PID -e trace=openat,stat,fstat -s 256 2>&1 | grep -i "ssh\|key\|auth"

你会看到类似:

openat(AT_FDCWD, "/home/user/.ssh/authorized_keys", O_RDONLY) = 5 fstat(5, {st_mode=S_IFREG|0644, st_size=394, ...}) = 0

注意st_mode=S_IFREG|0644,这里的0644表示权限是644,而 OpenSSH 要求600,这就是问题根源。

7.4 网络第四层:tcpdump抓包验证算法协商

如果客户端和服务端日志都显示“密钥已发送,但服务器没响应”,可能是网络设备(防火墙、负载均衡)截断了 SSH 包。用tcpdump抓包:

# 在服务端执行(过滤 SSH 端口) sudo tcpdump -i any port 22 -w ssh_debug.pcap # 在客户端执行一次登录 ssh -i ~/.ssh/id_ed25519 user@remote-server-ip # 停止抓包,用 Wireshark 分析 ssh_debug.pcap # 关键看 “SSH Protocol” 层的 “Key Exchange Init” 包,检查双方支持的 KEX 算法列表是否交集为空

Ubuntu 20.04 的kex_algorithms默认包含curve25519-sha256,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha384,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256。如果客户端只支持diffie-hellman-group1-sha1(已废弃),则无法协商。

8. 生产环境加固:密钥轮换、审计与自动化脚本

配好不是终点,维护才是关键。Ubuntu 20.04 作为 LTS,生命周期长达 5 年,密钥必须定期轮换。

8.1 密钥有效期管理:用ssh-keygen -Rssh-keygen -F

OpenSSH 不支持密钥内置有效期,但可通过known_hosts文件管理信任关系。当服务器密钥变更(如重装系统),旧的known_hosts条目会阻止连接:

# 删除旧条目(按主机名) ssh-keygen -R remote-server-ip # 删除旧条目(按哈希值,更安全) ssh-keygen -R "[remote-server-ip]:2222" # 检查某主机是否在 known_hosts 中 ssh-keygen -F remote-server-ip

8.2 审计密钥使用:ssh-add -lssh-add -E md5

列出当前 agent 中加载的密钥及其指纹:

# 默认 SHA256 指纹(推荐) ssh-add -l # MD5 指纹(兼容旧系统) ssh-add -E md5 -l

输出示例:

256 SHA256:AbCdEfGhIjKlMnOpQrStUvWxYz1234567890abcdefg user@host (ED25519)

将此指纹与ssh-keygen -lf ~/.ssh/id_ed25519输出对比,确保加载的是正确密钥。

8.3 自动化轮换脚本:rotate_ssh_keys.sh

以下脚本可在 Ubuntu 20.04 上一键轮换密钥(已实测):

#!/bin/bash # rotate_ssh_keys.sh # 用法:./rotate_ssh_keys.sh old_key_name new_key_name OLD_KEY="$1" NEW_KEY="$2" EMAIL="your_email@example.com" if [ -z "$OLD_KEY" ] || [ -z "$NEW_KEY" ]; then echo "用法:$0 <旧密钥名> <新密钥名>" exit 1 fi # 1. 生成新密钥 ssh-keygen -t ed25519 -C "$EMAIL" -f ~/.ssh/"$NEW_KEY" -N "" # 2. 将新公钥复制到远程服务器(假设服务器名为 prod) ssh-copy-id -i ~/.ssh/"$NEW_KEY".pub user@prod # 3. 更新 ~/.ssh/config sed -i "s/IdentityFile .*\/$OLD_KEY/IdentityFile ~\/.ssh\/$NEW_KEY/g" ~/.ssh/config # 4. 从 agent 中移除旧密钥,添加新密钥 ssh-add -d ~/.ssh/"$OLD_KEY" ssh-add ~/.ssh/"$NEW_KEY" # 5. 提示用户删除旧密钥文件(手动确认) echo "✅ 新密钥 $NEW_KEY 已生成并加载" echo "⚠️ 请手动执行:rm ~/.ssh/$OLD_KEY*"

赋予执行权限并运行:

chmod +x rotate_ssh_keys.sh ./rotate_ssh_keys.sh id_old_server id_new_server_2024

最后分享一个小技巧:在 VS Code 中使用 Remote-SSH 插件时,如果遇到ssh: Could not resolve hostname d: name or service not known,这不是 DNS 问题,而是你在~/.ssh/config中写了Host d,而 VS Code 的 Remote-SSH 解析器把d当成了 Windows 驱动器盘符。解决方案是:在config中用完整域名Host dev-server.local,或在 VS Code 的 Remote-SSH 设置中禁用Remote.SSH.useLocalServer。这是我帮客户解决的第 17 个同类问题,每次都是同一个原因。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询