Linux SSH 服务配置完全指南:sshd_config 逐项解读与生产最佳实践
SSH 是每台 Linux 服务器的"后门",配置错一次就可能把自己锁在门外或被暴力打穿。本文按 OpenSSH 8.x/9.x 官方默认顺序,逐项解释 sshd_config 中最常见 80+ 指令(端口、监听、协议、密钥、认证、PAM、登录限制、SCP/SFTP、端口转发、安全加固、日志审计、匹配块 Match),配套 4 套面向生产的配置模板(通用最小化 / 跳板机堡垒机 / Git/CI 密钥登录 / 禁用密码但保留公网入口),并给出 15 个高频排障场景(超时自动断开、跳板机端口转发被拒、sftp subsystem 错误、密钥正确仍要输密码、密钥类型不被接受、banner 未显示、PAM 拒绝等),以及 systemd 起停重载、改配置后如何"不把自己锁在门外"双会话验证流程。
一、SSH 与 sshd 是什么
OpenSSH 全家桶的角色
flowchart LR C["客户端<br/>ssh / scp / sftp / ssh-keygen<br/>(~/.ssh 配置)"] -- "22/tcp" --> S["服务器<br/>sshd (守护进程)<br/>/etc/ssh/sshd_config"] S --> P["PAM 栈<br/>/etc/pam.d/sshd"] S --> A["授权文件<br/>~/.ssh/authorized_keys<br/>(公钥校验)"] S --> L["wtmp/btmp/Journal<br/>登录审计"]
OpenSSH:绝大多数发行版自带的 SSH 实现(客户端 + 服务端 + 工具集)。
ssh:客户端命令,用来连别人。
sshd:服务端守护进程(
sshd末尾多一个d= daemon),监听 22 端口处理进入的连接。sshd_config:本文主角——sshd 的主配置文件,路径固定
/etc/ssh/sshd_config(部分发行版还有/etc/ssh/sshd_config.d/*.conf覆盖优先级更高)。配置覆盖顺序(后出现的覆盖前者):
sshd_config→sshd_config.d/*.conf(字典序)→Match块按匹配命中顺序。
改配置的铁律:永不把自己锁在门外
⚠️ 黄金法则:改完 sshd_config 永远不要直接
systemctl restart sshd。正确流程:
- 开 2 个 SSH 窗口:窗口 A 已登录保持连接(= 保险带),窗口 B 用新配置测试。
- 改完配置先语法检查:
sshd -t→ 0 退出码才允许重载。sshd -T(打印合并后的实际生效配置)——用来排查「我明明改了怎么没生效」。systemctl reload sshd(软重载,不中断窗口 A)。- 窗口 B 新开一个连接确认登录成功;成功再关闭窗口 A,失败立即在 A 里回滚并再次 reload。
二、配置的读入顺序与检查方法
# 1) 语法检查(最常用)
sshd -t && echo OK
# 2) 打印实际生效的完整配置(合并 include + match 后的最终值)
# 非常适合查:我改的 Port 是不是真的生效了?
sshd -T | grep -Ei 'port|listenaddress|permitroot|passwordauth|pubkey'
# 3) 模拟某用户/某源 IP,看 Match 块命中后的效果
# 例:用 root 从 10.0.0.5 登录会得到什么最终配置
sshd -T -C user=root,host=10.0.0.5,addr=10.0.0.5
# 4) 查某发行版默认的 sshd_config 模板(防止被你改烂后想对比)
# Debian/Ubuntu 把默认值放到 /usr/share/openssh,RHEL 在 /etc/ssh/sshd_config.rpmnew
ls /usr/share/openssh 2>/dev/null; ls /etc/ssh/*.rpmnew 2>/dev/null三、sshd_config 常见指令逐项解读
说明:下面默认按 OpenSSH 8.x/9.x 组织;个别指令(如
PubkeyAcceptedAlgorithms)在 8.5+ 改名,老版本用PubkeyAcceptedKeyTypes。一切以你本机man sshd_config为准。
2.1 基本网络监听
| 指令 | 默认值 | 作用 | 生产建议 |
|---|---|---|---|
Port 22 | 22 | 监听 TCP 端口,可写多行监听多个端口 | 跳板机建议多开一个备份端口(如 Port 22 + Port 22022),防止防火墙误配 |
ListenAddress 0.0.0.0 | 全部 IPv4 地址 | 绑定网卡地址;IPv6 用 ListenAddress :: | 内网机改成只绑内网 IP,减少暴露面 |
AddressFamily any | any | 地址族:inet / inet6 / any | 纯 IPv6 主机可写 inet6;双栈留 any |
2.2 主机密钥(Host Key)——服务器的身份证
| 指令 | 默认值 | 作用 | 说明 |
|---|---|---|---|
HostKey /etc/ssh/ssh_host_rsa_key | RHEL/Debian 都自带 | RSA 主机密钥文件 | 新发行版一般不写死这几条,sshd -T 会列出实际路径 |
HostKey /etc/ssh/ssh_host_ecdsa_key | — | ECDSA 主机密钥 | 256/384/521 三种曲线任选 |
HostKey /etc/ssh/ssh_host_ed25519_key | — | Ed25519 主机密钥 | 推荐优先算法,签名更快更小 |
HostKeyAlgorithms | 自动选择 | 允许客户端协商的主机密钥算法列表 | 老旧客户端(如 JSch 老版本)连不上时,把 ssh-rsa 加回来 |
RekeyLimit default none | default | 会话多长数据量/多久后重协商一次密钥 | 保持默认即可;高安全环境可 1G 30m |
💡 客户端首次连接时提示的
The authenticity of host can't be established就是在让你校验服务器 Host Key 指纹。ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub能拿到服务器指纹,和客户端显示的核对后再输 yes。
2.3 协议与加密套件(Ciphers / MACs / KexAlgorithms)
| 指令 | 说明 |
|---|---|
Ciphers | 允许的对称加密算法。推荐保守写法:Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr |
MACs | 完整性校验算法:MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 |
KexAlgorithms | 密钥交换算法:OpenSSH 9 默认就挺安全,要锁死可以:curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512 |
🔐 安全基线(PCI-DSS / 等保)审核常查:禁用 CBC 模式、禁用 SHA-1、禁用小于 3072 位的 DH 组。
ssh-audit(开源工具)会直接给出合规审计报告。
2.4 日志与审计
| 指令 | 默认 | 作用 | 建议 |
|---|---|---|---|
SyslogFacility AUTH | AUTH | 写到 syslog 哪个设施 | 保持 AUTH;某些系统需要 AUTHPRIV 分开日志 |
LogLevel INFO | INFO | 日志级别:QUIET/FATAL/ERROR/INFO/VERBOSE/DEBUG | 生产用 VERBOSE(会记录公钥指纹,方便排障);不要 DEBUG(会记录大量敏感协商与会话元数据,仅用于临时排障,禁止生产环境使用) |
PrintMotd yes | yes | 登录后打印 /etc/motd 内容 | 想自定义 Banner 时用后面的 Banner 指令 |
PrintLastLog yes | yes | 显示上次登录时间和来源 IP | 建议 yes,用户自己能第一时间发现异常登录 |
Banner /etc/ssh/banner | 无 | 认证前显示的法律/警告文本 | 合规必备,放一句「未授权访问将被记录」 |
Compression delayed | delayed | 是否压缩会话传输 | delayed = 认证后才开压缩(防止 pre-auth 攻击);建议保留 |
TCPKeepAlive yes | yes | TCP 层发送 keepalive 探测 | 配合下一节的 ClientAlive 组合使用 |
2.5 连接存活(超时与保活)
flowchart LR S[sshd] -- "每 ClientAliveInterval 秒<br/>发一次空探测" --> C[客户端] C -- 回复 --> S S -- "连续 ClientAliveCountMax 次无回复<br/>主动断开" --> X[TCP 断开]
| 指令 | 作用 | 生产跳板机示例 |
|---|---|---|
ClientAliveInterval 60 | 服务端多久给客户端发一次保活探测(秒) | 30 或 60 |
ClientAliveCountMax 3 | 连续多少次探测无响应才断开 | 3(即 3 分钟无响应后断) |
LoginGraceTime 60 | 客户端连上后多少秒内必须完成认证,否则踢掉 | 45,缩短暴力破解窗口 |
MaxStartups 10:30:100 | 未完成认证的并发连接数阈值:超过 10 后开始按 30% 概率拒绝新连接,到 100 全拒 | 公网机设 20:30:60 |
MaxSessions 10 | 同一条 TCP 会话可开的多路复用通道数上限 | 保持默认 |
MaxAuthTries 6 | 单次连接最多输错几次密码 | 公网机建议 3 |
💡 很多人误以为”我配置了 keepalive 怎么还是断”——中间设备(NAT、防火墙、LB)强制 10 分钟清会话,此时客户端侧也得开:
~/.ssh/config里写ServerAliveInterval 30,让客户端也主动发探测。
2.6 用户/组准入:谁能登录?谁被禁止?
| 指令 | 作用 | 优先级(由高到低:Deny > Allow) |
|---|---|---|
DenyUsers alice bob | 黑名单用户 | 最优先(不管 Allow 怎么写,Deny 直接拒) |
DenyGroups badguys | 黑名单用户组 | |
AllowUsers ops@10.0.0.0/24 jenkins | 白名单用户,支持 user@host 限制来源 | 推荐:生产只用 Allow 不用 Deny |
AllowGroups ops deploy | 白名单用户组 | 只允许 ops/deploy 组登录 |
执行顺序:DenyUsers → DenyGroups → AllowUsers → AllowGroups。全部不写默认允许所有人(只要认证通过)。
⚠️ 坑:用了
AllowUsers但漏写了 root(或自己的账号),重载后直接把自己拒在外。一定要配合上面”双会话 + reload”流程。
2.7 根用户登录与密码登录
| 指令 | 默认/选项 | 说明 | |
|---|---|---|---|
PermitRootLogin prohibit-password | prohibit-password | yes(允许,危险)/ no(完全禁止,推荐)/ prohibit-password(公钥能登但密码不行)/ forced-commands-only | |
PasswordAuthentication yes | yes | 是否允许密码登录 | 公网必须 no;内网机也建议 no |
PermitEmptyPasswords no | no | 允许空密码登录吗?永远 no | |
ChallengeResponseAuthentication no | 与 PAM 联动 | OpenSSH 9 里这个字段常显示 deprecated,等价于 KbdInteractiveAuthentication | |
KbdInteractiveAuthentication yes | yes | 键盘交互式认证(PAM、OTP 二次验证走这里) | 开了 2FA 才 yes,纯密钥登录可 no |
PubkeyAuthentication yes | yes | 公钥认证总开关 | 必然 yes |
AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 | 默认两个位置 | 从用户 home 下读哪些文件作为公钥列表 | 不要改默认;目录权限必须 700 文件 600,属主必须是登录用户本人,否则 sshd 会默默忽略 |
PubkeyAcceptedAlgorithms | 8.5+ 用这个,之前叫 PubkeyAcceptedKeyTypes | 允许的公钥算法列表 | 老客户端连不上时把 ssh-rsa 加回来 |
AuthorizedKeysCommand / AuthorizedKeysCommandUser | 无 | 公钥不从本地文件读,改为调脚本从 LDAP/AD/Vault 拉 | 中大型公司用这个统一管理公钥,脚本必须以非 root 身份运行(第二个参数指定运行用户) |
UsePAM yes | RHEL/Debian 都 yes | 启用 PAM 栈(含密码校验、密码过期提醒、2FA、限制、审计) | 几乎必 yes;改成 no 后所有 PAM 模块都失效 |
AuthenticationMethods publickey,keyboard-interactive | 单个任意方法通过即可 | 多因子组合写法:逗号=AND 逗号分隔,空格=OR 逗号分隔 | 2FA 强制要求:publickey,keyboard-interactive(先公钥再 OTP,两者都要) |
┌──────────────────────────────────────────────┐
│ AuthenticationMethods 的 AND/OR 语义 │
├────────────────────────────────────────────┤
│ publickey password │
│ → OR 语义:密码 OR 公钥 任一通过即可 │
│ │
│ publickey,keyboard-interactive │
│ → AND 语义:必须先公钥成功,再OTP成功 │
└──────────────────────────────────────────────┘2.8 登录后 shell 与 TTY
| 指令 | 作用 | 建议 |
|---|---|---|
PermitTTY yes | 是否分配 pty(交互式终端) | 流水线/CI 只跑命令可设 no,防止用户搞出交互 shell |
ForceCommand /opt/gate-shell.sh | 忽略客户端指定的命令,强制执行固定命令 | 跳板机、Git 服务器(git-shell)、sftp-only 用户常用 |
X11Forwarding no | X11 图形转发 | 生产一律 no,没有用到图形界面 |
AllowTcpForwarding no / yes / remote / local | 端口转发总开关(详见 2.9) | 普通服务器 no,跳板机按需局部开 |
GatewayPorts no | 远程转发时绑定在远端 0.0.0.0 还是 127.0.0.1 | 默认 no 更安全,只有明确需要外部访问才 yes |
AllowAgentForwarding no | 允许把 ssh-agent 转发到远端吗? | 公网/跳板机要 no;agent 转发=把本地私钥签名能力借给远端,被入侵就悲剧 |
AllowStreamLocalForwarding no | Unix socket 转发 | 几乎不用,默认 no 更安全 |
PermitTunnel no | 建 tun 设备(把 SSH 当 IPsec/VPN 用) | 不用就关 |
DisableForwarding yes | OpenSSH 9.0+ 新增:一键关闭所有转发(= 上面 4 条全关) | 生产通用服务器直接写这条,简单安全 |
2.9 端口转发四兄弟(容易混乱的一组)
flowchart LR L["本地转发 -L<br/>ssh -L 8080:内网Web:80 跳板机<br/>用户机:8080 → 跳板机 → 内网Web:80"] R["远程转发 -R<br/>ssh -R 2222:本地:22 云服务器<br/>外网访问 云:2222 → 家里主机:22"] D["动态转发 -D (SOCKS)<br/>ssh -D 1080 跳板机<br/>浏览器设 socks5://127.0.0.1:1080"] W["反向隧道 / 多跳板<br/>ProxyJump / ProxyCommand<br/>先 hop 到跳板再到目标机"]
对应 sshd_config 控制项:
| 指令 | 控制的功能 | 跳板机常用值 |
|---|---|---|
AllowTcpForwarding local | -L 和 -R 的总开关;local 只允许本地转发 | local(内网穿透禁止 -R 时) |
GatewayPorts clientspecified | -R 的绑定地址;clientspecified 允许客户端显式写 *:2222 | 内网穿透才开,默认 no |
PermitOpen host:port host2:port2 | 允许 -L 只转发到哪些目标 | 白名单模式,严格控制穿透范围 |
DisableForwarding yes | 一键关所有转发 | 普通业务服务器推荐 |
2.10 SFTP / SCP 子系统
| 指令 | 作用 | 说明 |
|---|---|---|
Subsystem sftp /usr/libexec/openssh/sftp-server | 注册 SFTP 子系统路径 | Debian 是 /usr/lib/openssh/sftp-server;写错了 sftp 直接连不上 |
Subsystem sftp internal-sftp | 用 sshd 内置的 sftp 实现(不是外部程序) | 推荐 + ChrootDirectory 的唯一正确组合,性能更好、权限检查更严 |
ChrootDirectory /home/sftp/%u | 把用户锁在指定目录(chroot jail) | ① 目录属主必须是 root:root;② 目录权限不能高于 755(不能有任何写权限给非 root);③ 用户要上传文件必须在里面再建一个”用户可写子目录” |
ForceCommand internal-sftp | 和 ChrootDirectory 配合:该用户只能用 sftp,不能起 shell |
🔥 最常见 Chroot 报错:
fatal: safely_chroot: stat("/home/sftp/alice"): Permission denied。十有八九是目录属主不是 root,或目录权限写了 775/777。严格检查stat /home/sftp/alice:Uid 必须是 0( root ),Mode 不能有 w 给 group/other。
2.11 其他高频指令
| 指令 | 作用 | |
|---|---|---|
UseDNS no | 对客户端 IP 反解 DNS 做 host 匹配 | 公网机建议 no;慢连接头号杀手,DNS 一挂每次登录慢 10 秒 |
GSSAPIAuthentication no | Kerberos 认证 | 没搭 AD/FreeIPA 就关,否则每次登录尝试 GSS 失败耗时间 |
AcceptEnv LANG LC_* | 允许客户端把哪些环境变量带进服务端 | 只放行 LANG/LC_,不要随便加 PATH,小心 PATH 注入 |
SendEnv(客户端) | — | 和 AcceptEnv 配对;要传变量两边都得开 |
StrictModes yes | 检查 .ssh 目录与 authorized_keys 的权限/属主 | 必须 yes,关了会忽略权限错误,安全风险 |
IgnoreRhosts yes | 忽略 .rhosts / .shosts 信任文件 | 必须 yes,老式 rlogin 遗留 |
HostbasedAuthentication no | 基于主机的信任(类似 rsh) | 必须 no |
PermitUserEnvironment no | 是否读 ~/.ssh/environment 文件 | 必须 no,防止 PATH/LD_PRELOAD 注入 |
PidFile /var/run/sshd.pid | sshd 主进程 PID 路径 | 不用改 |
Ciphers / MACs / KexAlgorithms / HostKeyAlgorithms | 已在 2.3 节讲过 | 配合 ssh-audit 扫描建议值 |
CASignatureAlgorithms | CA 签名允许的算法(证书登录) | 用 SSH 证书才关心 |
TrustedUserCAKeys /etc/ssh/ca.pub | 受信任的用户 CA 公钥(证书登录) | SSH 证书体系必开 |
四、Match 块:按用户/组/来源 IP 精细化差异化配置
当你想”所有用户都禁密码,唯独监控机那个专门拉指标的用户只能来自 10.0.0.0/24 且能密码登录”,全局开关做不到,用 Match 块:
# ========== 全局 ==========
PasswordAuthentication no
PermitRootLogin no
DisableForwarding yes
X11Forwarding no
# ========== 只对 ops 组成员生效:允许端口转发做跳板 ==========
Match Group ops
AllowTcpForwarding yes
AllowAgentForwarding no
PermitTTY yes
# ========== 只对监控账号 zabbix:只能从监控机来 + 强制执行脚本 ==========
Match User zabbix Address 10.0.1.15,10.0.1.16
PasswordAuthentication yes
PermitRootLogin no
PermitTTY no
ForceCommand /usr/local/bin/zabbix-agent-check.sh
DisableForwarding yes
# ========== 只对 sftpusers 组:chroot + 只能 sftp ==========
Match Group sftpusers
ChrootDirectory /sftp/%u
ForceCommand internal-sftp
X11Forwarding no
AllowTcpForwarding no
PermitTTY noMatch 块可使用的判断条件:
| Match 条件 | 含义 | 示例 |
|---|---|---|
User | 用户名(通配 *) | User alice, deploy_* |
Group | 用户组 | Group ops,!temp_ops |
Host | 客户端输入的 Host 名(注意是客户端指定、不是反解 DNS) | Host *.internal.corp |
Address | 客户端源 IP / CIDR | Address 10.0.0.0/8,!10.0.0.99 |
LocalAddress | 服务器端连接到的 IP(多网卡服务器) | LocalAddress 192.168.122.1 |
All | 以上都匹配 | All |
验证 Match 是否命中:
sshd -T -C user=zabbix,addr=10.0.1.15,host=gateway观察 PasswordAuthentication 是否变成 yes。
五、四套面向生产的配置模板
4.1 模板 A:通用最小化(内网业务服务器)
适用:普通 Web/DB/K8s worker,运维走跳板机,公网不暴露 22。
# /etc/ssh/sshd_config
Port 22
ListenAddress 0.0.0.0
ListenAddress ::
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
SyslogFacility AUTHPRIV
LogLevel VERBOSE
LoginGraceTime 45
MaxStartups 20:30:60
MaxAuthTries 3
ClientAliveInterval 60
ClientAliveCountMax 3
PermitRootLogin no
AllowGroups ops deploy
DenyUsers root test
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication no
PermitEmptyPasswords no
KbdInteractiveAuthentication no
UsePAM yes
StrictModes yes
IgnoreRhosts yes
PermitUserEnvironment no
X11Forwarding no
PrintMotd no
PrintLastLog yes
UseDNS no
GSSAPIAuthentication no
# 9.0+ 一行关掉所有转发
DisableForwarding yes
# 如果 OpenSSH < 9.0,用等价写法:
# AllowTcpForwarding no
# AllowAgentForwarding no
# AllowStreamLocalForwarding no
# PermitTunnel no
AcceptEnv LANG LC_*
Subsystem sftp internal-sftp4.2 模板 B:堡垒机 / 跳板机(公网暴露、支持局部转发)
适用:公网可直达,用户需从本机跳板到内网服务器。
Port 22
Port 22022 # 双端口,防 22 被防火墙误封
ListenAddress 0.0.0.0
TCPKeepAlive yes
LoginGraceTime 30
MaxAuthTries 3
MaxStartups 30:50:80
ClientAliveInterval 30
ClientAliveCountMax 3
Banner /etc/ssh/banner
PermitRootLogin no
AllowGroups ops
AllowTcpForwarding local # 只允许 -L 本地转发(跳板→内网),禁止 -R 把内网暴露出去
AllowAgentForwarding no # 严禁借 agent,跳板机被攻破也不能借私钥
X11Forwarding no
PermitTunnel no
GatewayPorts no
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication yes
# 强 2FA:必须先公钥,再 OTP
AuthenticationMethods publickey,keyboard-interactive
UsePAM yes
LogLevel VERBOSE
UseDNS no
GSSAPIAuthentication no
# 只允许 ops 组的端口转发白名单
Match Group ops
PermitOpen 10.0.0.100:6443 10.0.0.101:6443 10.0.0.10:* 10.0.0.20:3306二次验证的 Google Authenticator PAM 安装:
# RHEL dnf install -y google-authenticator qrencode # Debian apt install -y libpam-google-authenticator # 每个要启 2FA 的用户自己执行: google-authenticator -t -d -f -r 3 -R 30 -W # /etc/pam.d/sshd 首行加: # auth required pam_google_authenticator.so nullok # nullok = 没配过的用户先跳过;全部用户配置完了去掉 nullok。
4.3 模板 C:Git / CI 服务器(纯密钥 + 多用户 + 禁用交互 TTY)
PermitRootLogin no
AllowGroups gitlab-runner deployer jenkins
PubkeyAuthentication yes
AuthorizedKeysCommand /opt/bin/fetch-authkeys.sh
AuthorizedKeysCommandUser nobody
PasswordAuthentication no
KbdInteractiveAuthentication no
X11Forwarding no
DisableForwarding yes
PermitTTY no
# 个别 CI 账号需要 ssh 进目标机部署,局部开转发
Match Group deployer
AllowTcpForwarding local
PermitTTY yes4.4 模板 D:SFTP-only 用户组(chroot 隔离上传下载)
# /etc/ssh/sshd_config
Subsystem sftp internal-sftp
Match Group sftpusers
ChrootDirectory /sftp/%u
ForceCommand internal-sftp
X11Forwarding no
DisableForwarding yes
PermitTTY no
PasswordAuthentication no
PubkeyAuthentication yes配套初始化脚本:
# 执行一次即可
groupadd sftpusers
useradd -m -G sftpusers -s /usr/sbin/nologin alice
install -d -o root -g root -m 755 /sftp/alice # 755 属主 root,Chroot 要求
install -d -o alice -g sftpusers -m 700 /sftp/alice/uploads
# 给 alice 放公钥(chroot 后 home 还是 /home/alice,sshd 仍能读到 authorized_keys)
install -d -o alice -g alice -m 700 /home/alice/.ssh
cat >> /home/alice/.ssh/authorized_keys # <-- 粘贴公钥
chown alice:alice /home/alice/.ssh/authorized_keys && chmod 600 /home/alice/.ssh/authorized_keys六、systemd 与日常运维命令速查
# 重载配置(不改端口、证书、监听地址时推荐,零中断)
systemctl reload sshd
# 重启(改了端口、HostKey 等才需要)
systemctl restart sshd
# 开机自启
systemctl enable sshd
# 看状态 + 最近日志
systemctl status sshd
journalctl -u sshd -n 50 --no-pager
# 持续追踪登录失败(暴力破解实时监控)
journalctl -u sshd -f | grep -Ei 'fail|invalid|error'
# 谁登过(最近)
last -n 30
lastlog -u ops
# 谁试图登但失败(btmp 日志)
lastb -n 30
# 把所有正在连接的会话列出来(含来源 IP、登录用户、pty)
ss -tnp | grep sshd
# 临时 ban IP(fail2ban 自动做)
fail2ban-client status sshd
fail2ban-client set sshd banip 1.2.3.4七、15 个高频排障场景
6.1 改完配置自己登不上了 → 双会话+reload 流程(见 0.2 节)
6.2 客户端:Connection closed by 1.2.3.4 port 22
服务器侧原因常见:MaxStartups 被打满、SELinux 在强制模式下把 sshd 限制了、AllowUsers 没把你放进去。 排障:服务器跑 journalctl -u sshd -e,同时 sshd -d 前台调试模式看实时拒绝原因。
6.3 Permission denied (publickey).——明明公钥放对了
用 -vvv 抓协商细节:
ssh -vvv ops@目标机 2>&1 | grep -Ei 'offer|publickey|sign|accept|fail|pubkey|auth'服务器侧常见根因列表:
┌───────────────────────────────────────────────────────────────────┐
│ 公钥认证失败 80% 的根因(按概率排序) │
├──────────────────────────────────────────────────────────────────┤
│ 1) StrictModes 校验未通过,sshd 默默忽略 authorized_keys │
│ $ ls -ld ~ ~/.ssh ~/.ssh/authorized_keys │
│ ~ = 700, .ssh = 700, authorized_keys = 600 │
│ 全部属主 = 登录用户本人,不能是 root │
│ 2) authorized_keys 里粘贴公钥时多了换行/空格/隐藏字符 │
│ 3) 服务端 PubkeyAuthentication = no(少见,但可能被 Match 改) │
│ 4) 用户 home 目录是 NFS,且 no_root_squash 下 sshd root 不可读 │
│ 5) SELinux:restorecon -Rv ~/.ssh/ │
│ 6) 客户端私钥算法不在服务端 PubkeyAcceptedAlgorithms 内 │
│ 7) 私钥设了密码但 ssh-agent 没载入,导致一直在输入私钥密码 │
└───────────────────────────────────────────────────────────────────┘6.4 Server refused our key 但日志里啥都不写
LogLevel INFO 调 VERBOSE,reload 之后再连一次:
sed -i 's/^LogLevel INFO/LogLevel VERBOSE/' /etc/ssh/sshd_config
systemctl reload sshd
journalctl -u sshd -fVERBOSE 会打印 userauth_pubkey: key type ssh-rsa not in PubkeyAcceptedAlgorithms [preauth] 这种致命线索。
6.5 用 ssh-rsa 老密钥无法登录(OpenSSH 8.8+ 默认禁用 SHA-1 签名)
OpenSSH 8.8 起把 ssh-rsa(注意:是 RSA 密钥的 SHA-1 签名算法,不是 RSA 密钥本身)从默认列表剔除了。 正确修复不是改 sshd_config 全局放开,而是升级客户端算法:把客户端密钥换成 ed25519:
ssh-keygen -t ed25519 -C "work email" # 推荐
ssh-keygen -t rsa -b 4096 # 旧客户端兼容也得 4096 位如果必须短期兼容(客户端是老设备),局部开一个用户:
Match User olddevice Address 10.1.2.3
PubkeyAcceptedAlgorithms +ssh-rsa6.6 每次登录都要等 10 秒才出密码提示
90% 是 UseDNS yes 导致服务端反解超时。改 UseDNS no + GSSAPIAuthentication no reload 即可。
6.7 idle 一段时间就断:ClientAliveInterval 配置正确但还是断
客户端也得开 ServerAliveInterval,两边配合;中间 NAT/LB 也会主动清连接,此时只能缩短客户端探测(30s 一次):
# ~/.ssh/config 客户端
Host *
ServerAliveInterval 30
ServerAliveCountMax 3
TCPKeepAlive yes6.8 sftp 连上就断,报 Received message too long
99% 原因是用户 shell 的 rc 脚本(.bashrc .profile)里有 echo 输出,被 sftp 客户端当成协议数据了。改 rc 文件,让非交互 shell 直接 return:
# 在 .bashrc 第一行加:
[[ $- != *i* ]] && return6.9 ChrootDirectory 报错 Permission denied
- Chroot 路径的每一层属主必须是 root;2) 每一层不能有 group/other 的写权限。正确权限样例:
drwxr-xr-x root root /sftp
drwxr-xr-x root root /sftp/alice
drwx------ alice sftpusers /sftp/alice/uploads ← 只有这个子目录是 alice 可写6.10 跳板机上 -L 端口转发被拒绝
检查:AllowTcpForwarding 是否允许;PermitOpen 是否把目标加入白名单;DisableForwarding 是否不小心开在全局。sshd -T -C user=你的账号 核对最终值。
6.11 -R 远程转发绑定到 0.0.0.0 了还是不能从外部访问
GatewayPorts 默认 no,此时 -R 只绑 127.0.0.1。改成 GatewayPorts clientspecified,并在客户端用:
ssh -R '*:2222:127.0.0.1:22' 云端IP # 注意 *:2222 才绑全网,直接写 2222 默认绑 127同时服务器防火墙要放行 2222 入站。
6.12 bad ownership or modes for chroot directory
见 6.9;另外注意 internal-sftp 要配对,不要写外部 /usr/libexec/sftp-server 再配 Chroot,会有权限问题。
6.13 PAM: Authentication failure for root from 1.2.3.4,但密码是对的
PAM 限制:/etc/security/access.conf(Deny root 从非控制台登录)、/etc/security/limits.conf(maxlogins)、faillock(连续输错被临时锁)。看 PAM 日志:journalctl -u sshd -e 里会写具体哪个 PAM 模块拒绝了。 解锁 faillock:
faillock --user root --reset
# 老发行版
pam_tally2 --user root --reset6.14 Banner 设置了但不显示
Banner 是密码提示前显示;用 sftp/非交互会话、或者用了 GSSAPIAuthentication 先尝试快速认证都会跳过 banner 文本;此外文件要所有用户可读:chmod 644 /etc/ssh/banner。
6.15 生产怎么验证配置?安全基线扫描工具
# ssh-audit:一键看算法、证书、版本、已知漏洞
git clone https://github.com/jtesta/ssh-audit.git && cd ssh-audit
./ssh-audit.py note.robinzen.cn:22
# 另一个:Lynis 系统审计(含 SSH 章节)
lynis audit system --quick --tests-from-group ssh八、附:OpenSSH 关键版本特性速记
| 版本 | 关键变化 |
|---|---|
| OpenSSH 7.0 | 禁用 ssh-dss DSA 密钥;引入 ssh-ed25519 主机密钥 |
| OpenSSH 7.4 | 移除 SSHv1 协议支持;StreamLocalBindUnlink;新增 DisableForwarding 指令;修复 UseRoaming(CVE-2016-0777) |
| OpenSSH 8.2 | U2F/FIDO 支持(ssh-keygen -t ecdsa-sk);弃用 ssh-rsa(SHA-1) |
| OpenSSH 8.5 | PubkeyAcceptedKeyTypes 改名 PubkeyAcceptedAlgorithms |
| OpenSSH 8.8 | 默认禁用 ssh-rsa(SHA-1) 签名算法(老客户端连不上的根因) |
| OpenSSH 9.0 | 新增 DisableForwarding yes;scp 默认改用 sftp 协议(兼容 SFTP-only 服务器) |
| OpenSSH 9.2+ | sshd_config.d/*.conf 普遍支持;修正 PermitOpen 匹配 CIDR |
💡 本机查看版本:
sshd -V(部分发行版用ssh -V,显示同一个版本号)。
一句话总结:PermitRootLogin no + PasswordAuthentication no + AllowGroups/AllowUsers + DisableForwarding + 双会话 reload = sshd 生产安全的 5 个必选项;剩下的配置项就按本文对照表按需打开。