批量服务器免密登录配置:从生成密钥到批量分发实操
管理多台 Linux 服务器时,如果每次登录都输密码,重复劳动不说,自动化脚本也没法跑。
批量服务器免密登录配置的核心只有两步:在管理机生成一对 SSH 密钥,然后把公钥追加到每台目标服务器的 ~/.ssh/authorized_keys。
难点不在原理,而在批量分发和排错。
下面按可以照做的顺序展开。
适用前提与准备工作
这套流程适合你有一台固定的管理机(本地电脑或跳板机),需要免密登录一批 Linux 服务器,系统一般是 CentOS、Ubuntu、Debian 等常见发行版。
需要满足几个条件:
- 管理机能通过 SSH 用密码登录目标服务器,且知道各机器的 IP、端口、用户名。
- 目标服务器开放了 SSH 端口,防火墙和云安全组没有拦截。
- 建议先整理一份服务器清单文件,例如
hosts.txt,每行一个 IP,方便后续批量执行。
先在管理机生成密钥。
如果已有 ~/.ssh/id_rsa 且不想覆盖,可以换一个文件名:
ssh-keygen -t rsa -b 4096 -C "ops@admin" -f ~/.ssh/id_rsa
执行过程中会提示输入 passphrase,直接回车表示不设密码;
如果设了密码,免密登录时仍要输入该密码,达不到全自动效果,脚本场景建议留空。
生成完成后检查文件权限:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
权限过松时,SSH 可能直接忽略密钥,表现为“还是让我输密码”。
用 ssh-copy-id 逐台分发公钥
服务器数量在十台以内,最简单的方式是 ssh-copy-id。
它会把公钥追加到目标机器的 authorized_keys,并自动处理目录权限。
假设目标用户是 root,端口是默认 22:
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.10
如果 SSH 不是 22 端口,加上 -p 参数:
ssh-copy-id -i ~/.ssh/id_rsa.pub -p 2222 root@192.168.1.10
多台机器可以配合 for 循环,从清单文件读取 IP:
while read ip; do
ssh-copy-id -i ~/.ssh/id_rsa.pub root@$ip
done < hosts.txt
执行时会逐台要求输入一次目标服务器密码,输入正确后公钥写入成功。
完成后立刻验证:
ssh root@192.168.1.10 "hostname && whoami"
如果不再提示密码,并且返回了主机名和用户名,说明这一台的免密已经生效。
用 Ansible 批量下发公钥
机器数量多、或者端口和用户不统一时,逐台输入密码依然很累。
这时可以用 Ansible 的 authorized_key 模块批量完成。
前提是控制机已安装 Ansible,并且能通过密码或已有密钥连上目标机。
先准备 inventory 文件 inventory.ini:
[web]
192.168.1.10
192.168.1.11
192.168.1.12
[web:vars]
ansible_user=root
ansible_ssh_pass=你的密码
ansible_ssh_common_args='-o StrictHostKeyChecking=no'
再执行一次性的公钥下发 playbook:
- hosts: web
gather_facts: no
tasks:
- name: 下发 SSH 公钥
authorized_key:
user: root
state: present
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
保存为 push_key.yml 后运行:
ansible-playbook -i inventory.ini push_key.yml
看到 changed 或 ok 且没有 unreachable,就表示公钥已经写入。
之后可以把 inventory 中的明文密码去掉,改用密钥连接,避免密码留在文件里。
简化连接与批量验证
公钥分发成功后,可以在管理机写 ~/.ssh/config,给每台机器起别名,省去每次敲 IP 和端口:
Host web01
HostName 192.168.1.10
User root
Port 22
IdentityFile ~/.ssh/id_rsa
之后直接 ssh web01 即可。
批量验证时,用一段循环一次性检查所有机器:
while read ip; do
echo "=== $ip ==="
ssh -o BatchMode=yes -o ConnectTimeout=5 root@$ip "echo ok" 2>&1
done < hosts.txt
BatchMode=yes 的作用是禁止交互式输入密码,如果某台仍需密码,会直接报错而不是卡住。
输出全是 ok 就说明批量免密全部生效;
出现 Permission denied 或超时的机器需要单独排查。
常见报错与避坑要点
- 仍然提示输入密码:先看目标机
~/.ssh是否为 700、authorized_keys是否为 600,属主是否是登录用户。权限不对时 SSH 会拒绝使用公钥。 - 公钥写到了错误用户:
ssh-copy-id root@ip写的是 root 的目录,如果你实际用ubuntu登录,需要改成ubuntu@ip,两者互不通用。 Permission denied (publickey):检查目标机/etc/ssh/sshd_config中PubkeyAuthentication是否为yes,修改后需要重载sshd。- 连接超时:确认端口、云安全组和本机防火墙放行,先用
telnet ip 22或nc -zv ip 22测通再谈免密。 - 私钥别乱传:只需要分发公钥
id_rsa.pub,私钥id_rsa留在管理机并保持 600 权限。 - 批量操作前先备份:如果要修改
sshd_config或清理authorized_keys,先复制原文件,避免把自己锁在服务器外。
两个高频疑问
免密后还需要保留密码登录吗? 建议保留一段时间作为回退通道,确认所有自动化脚本和登录都正常后,再考虑在 sshd_config 中关闭密码登录。
直接关闭而密钥又配错,可能导致无法登录。
换了管理机怎么办? 把新管理机的公钥按同样流程追加到目标服务器即可,旧公钥可以后续在 authorized_keys 中删除。
删除时按行操作,不要整文件清空,避免误删其他同事的密钥。
批量服务器免密登录配置本身不复杂,真正影响成功率的是权限、用户、端口和网络这几处细节。
建议先用一台机器跑通全流程,确认 ssh -o BatchMode=yes 能返回结果,再扩展到全部服务器,最后用验证脚本统一复查一遍。