如果你的目标是让一台远程服务器能用密钥登录,并把同一套凭证交给 AI Agent(Cursor、Claude Code 这类)直接操作它,那么最先要解决的是「自己先能用密钥登上去」这件事。我自己排这类问题时按这个顺序来:先确认密钥对生成了、公钥确实写进了服务器对应用户的 ~/.ssh/authorized_keys,再去管 sshd_config 加固和交给 Agent 用。在 Windows 上跑 ssh-copy-id 报错「不是内部或外部命令」,原因不是命令拼错了,而是机器里压根没有 OpenSSH 客户端。
先把密钥登录跑通
在本地用 ssh-keygen 生成一对密钥是最常用的入口,推荐用 ed25519 算法,密钥更短、签名更快,安全性上和 RSA-2048 同档 [2][5]:
ssh-keygen -t ed25519 -C "your@email"
如果服务端是比较老的系统、不认 ed25519,再退回 ssh-keygen -t rsa -b 4096 [2]。一路上让你输入 passphrase(密码短语)的时候,建议设一个——私钥就算被人拷走,没有这层也登不上 [5]。
接下来把公钥推到服务器。Linux/macOS 上一条 ssh-copy-id 就够了 [2][4]:
ssh-copy-id user@server
它会自动在服务器上建好 ~/.ssh 目录、把公钥追加进 authorized_keys,权限也都设对。非默认端口要带 -P 指定,否则会失败。
Windows 上第一次跑 ssh-copy-id 经常直接撞上这个错:
'ssh-copy-id' 不是内部或外部命令,也不是可运行的程序或批处理文件。
这不是命令拼错了,是系统里没有 OpenSSH 客户端。Win10 之后可以从「设置 → 应用 → 可选功能 → 添加功能」里勾选安装 OpenSSH 客户端 [3]。装完新开一个终端窗口再跑 ssh-copy-id 即可。不想折腾可选功能的话还有个更轻的办法:如果你本机装了 Git(开发机上基本都有),在 Git Bash 里直接执行 ssh-copy-id user@server,因为 Git Bash 自带 OpenSSH,这一招经常省事不少 [3]。两条路二选一,没必要因为这一条命令去重装系统环境。
推完之后,服务器侧三件套必须做对,否则 sshd 会直接拒绝认证、也不会给友好提示。~/.ssh 目录是 700、authorized_keys 文件是 600,两者属主都是登录用户本人 [2][5]:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
sshd 对权限非常敏感——authorized_keys 哪怕是 644(多了组读权限)都会被拒,因为它认为这个文件可能被别人改过。常见踩坑场景:用 root 账号帮普通用户建的 .ssh 目录,属主成了 root,登录时一样会被拒。建议建完立刻 ls -la ~/.ssh 看一眼权限和属主。
sshd_config 加固:顺序比内容更重要
能免密登录之后,再来收紧 /etc/ssh/sshd_config。这个文件的修改原则只有一条:永远先确认新配置能登录,再把旧通道堵上 [2][5]。
具体顺序建议这样:先用编辑器打开 /etc/ssh/sshd_config,确认 PubkeyAuthentication yes;PasswordAuthentication 暂时保留 yes,不要一次性关掉。保存后执行 systemctl restart sshd。改完配置立刻新开一个 SSH 窗口登一次,确认密钥登录通——失败了旧的密码登录还能救命,成功了再把 PasswordAuthentication no、PermitRootLogin no 写进去、再 restart 一次 [1][2]。
可参考的参数清单(具体值视环境调整)[1][2]:
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication no
PermitRootLogin no
ChallengeResponseAuthentication no
顺序反了最坏的情况是自己被锁在门外,云上机器没有控制台就只能走重装流程。
把这套密钥交给 AI Agent 用
到这里你手里已经有一把能登录服务器的私钥了,下一步是把它接进 AI Agent。在动手之前有一件事必须先想清楚:别把自己日常用的那把私钥交给 Agent。
正确做法是单独为这个 Agent 生成一把专用密钥。比如 ssh-keygen -t ed25519 -f ~/.ssh/cursor_agent_key,然后只把这一把的公钥追加到服务器的 authorized_keys 里。这样无论 Agent 那边出了什么问题(人员变动、密钥泄露、Agent 流程被滥用),你只需要在服务端删掉对应那一行就完成撤销,不会牵连到你自己日常用的其他服务器 [5]。
密钥怎么「交给」Agent 取决于具体工具,但有一件事是通用的:在本地 ~/.ssh/config 里给这台服务器起一个清晰的别名。
Host prod-app
HostName 1.2.3.4
User deploy
Port 2222
IdentityFile ~/.ssh/cursor_agent_key
配完之后,AI Agent 只需要知道 ssh prod-app 这一条命令就够了,不用关心 IP、端口、私钥路径在哪儿——也不会把私钥本身暴露在调用参数里。私钥文件保持 600 权限,路径写进 config 里比通过环境变量传要稳定得多,环境变量在很多 Agent 进程里不容易跨调用持久保留。
如果你有多个 Agent 或多个同事共用同一台服务器,authorized_keys 里直接一行一条公钥追加就行 [5]。不需要单独建目录、不需要写脚本管理,谁出问题删一行就对谁负责。
连接还是失败,按这个顺序排
走到「公钥明明放进去了,连接时还是 Permission denied (publickey)」这一步,几乎所有原因都落在三处。不要去试网上的万能攻略,按这个顺序往下查 [2][5]。
第一类是文件权限和属主。ls -la ~/.ssh/ 看一下,authorized_keys 必须是 600、.ssh 必须是 700、两者属主都是登录用户本人。再用 restorecon -FRv ~/.ssh(只在 SELinux 强制模式下需要)修一下安全上下文——SELinux 开着的话,权限对、上下文不对,一样会被拒。第二类是 sshd_config 里 PubkeyAuthentication 是不是真的 yes。改完一定要 restart,别只看配置文件就觉得生效了。第三类是公钥内容本身:拷贝的时候不要用 Windows 记事本打开 .pub 文件再去复制粘贴,换行符会被吃;建议直接 cat ~/.ssh/id_rsa.pub 在终端打印,或者用 ssh-copy-id 自动追加。
服务端看不到日志就只能盲排。按发行版看 journalctl -u sshd --no-pager -n 50(systemd 系列)或 tail -n 50 /var/log/auth.log(Debian/Ubuntu 传统路径)[5]。日志里出现 Authentication refused: bad ownership or modes for directory 就直接对应文件权限问题;出现 Could not open authorized keys 就是文件路径不对或者文件压根不存在。
客户端调试用 ssh -vvv user@server,能看完整的密钥交换流程——哪个私钥被尝试了、服务端到底拒绝了哪一把、为什么拒。这一步能省掉八成的排查时间。
FAQ
同一台服务器要让多个 AI Agent / 多个同事共用,authorized_keys 怎么组织?
一行一条公钥直接追加就行,不需要额外目录或脚本 [5]。建议每个人、每个 Agent 都用独立的密钥对,谁出问题按行撤销最干净,也不容易误伤。
私钥设了 passphrase,AI Agent 每次连接都要手动输怎么办?
可以用 ssh-agent 把解锁后的私钥缓存在内存里供后续调用——passphrase 这一层防护在「私钥被盗」这种场景下依然有效,不用为了自动化放弃它 [2][5]。不过不同 AI Agent 对 ssh-agent 的调用方式不一样,ssh-agent 在 Agent 进程里的继承也不总是干净的,资料里没覆盖到具体工具就不展开讲了。如果你用的 Agent 有密钥管理面板,把私钥直接交给它通常比走 ssh-agent 更省事。
参考来源
[1] 配置Linux服务器SSH远程密钥登录-阿里云开发者社区
[2] SSH密钥登录配置全指南:从原理到实践-百度开发者中心
[3] 配置远程服务器ssh密钥登录 – Synnn – 博客园
[4] 使用SSH密钥远程服务器_配置ssh使用密钥远程登录-CSDN博客


暂无评论内容