SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-09-10

Rocky Linux 服务器初始化安全配置指南

新装 Rocky Linux 或 AlmaLinux 服务器后的首小时操作指南。涵盖 dnf 更新、wheel 用户创建、SSH 密钥认证、firewalld 防火墙配置、dnf-automatic 自动更新及 SELinux 强制模式设置,确保您的生产环境安全可靠。

新装 Rocky Linux 服务器的首小时操作指南

为保障新装 Rocky Linux 服务器的安全,在安装任何其他软件前,必须完成以下六项操作:执行完整的 dnf upgrade,创建一个属于 wheel 组的管理用户,仅允许密钥登录 SSH,配置 dnf-automatic 自动更新,通过 firewalld 仅开放必要的服务端口,并确保 SELinux 处于 enforcing 模式。以下所有命令在 AlmaLinux 上同样适用,因为两者均基于相同的 Red Hat Enterprise Linux 源码构建。请在确保有其他访问途径的情况下执行这些命令,并在修改 SSH 或防火墙配置时,始终保持另一个 SSH 会话处于开启状态。

应锁定哪个 Rocky Linux 版本

本文基于 2026 年 5 月 29 日发布的 Rocky Linux 10.2 编写,文中的命令同样适用于 Rocky Linux 9 和 AlmaLinux 10。Rocky 10 依然搭载 DNF 4.20 作为 dnf,因此您熟悉的标志位行为保持不变。请在 10 分支上启动新服务器,而非 8 分支:8 分支在所有受支持的分支中拥有最旧的 Python 和 OpenSSL 版本,每多维护一年,您就需要花费更多精力去规避这些限制。在信任任何指南(包括本文)之前,请先确认您实际引导的系统版本。

cat /etc/rocky-release
uname -r

发行版文件会输出类似 Rocky Linux release 10.2 的内容,而 10.2 版本搭载了 6.12 内核。在 AlmaLinux 上,该文件为 /etc/almalinux-release,且 /etc/os-release 在两者中均存在。如果您尚未确定使用哪一个,Rocky Linux 与 AlmaLinux 的实际差异 比市场宣传的要小,且本页内容在两者之间并无区别。这两个发行版的存在均源于 Red Hat 在 2020 年终止了作为下游重建版的 CentOS,如果您仍在考虑是否要在服务器上使用重建版系统,阅读 该家族从 Red Hat Linux 到 CentOS 再到 Rocky 和 AlmaLinux 的演变过程 是很有价值的。

在进行任何操作前更新所有内容

sudo dnf upgrade --refresh -y
sudo dnf install -y dnf-plugins-core
sudo dnf needs-restarting -r

--refresh 会丢弃已缓存的仓库元数据。这对于在启动前几周构建的供应商镜像至关重要,因为如果不执行此操作,dnf 将会复用过期的索引,并错误地报告系统已是最新状态。随后 needs-restarting -r 会回答后续问题:当内核或核心库发生变更时,它会输出 Reboot is required to fully utilize these updates;若无变更,则输出 Reboot should not be necessary。现在执行重启,此时机器上没有运行任何服务,也没有用户依赖该系统。

创建属于 wheel 组的管理员用户

通过 SSH 以 root 身份登录意味着一旦密钥泄露,服务器将完全失控,且互联网上的所有扫描器都已知晓该用户名。请创建一个普通账户,将其加入 wheel 组,并通过 sudo 获取 root 权限。

sudo useradd -c 'admin account' deploy
sudo passwd deploy
sudo usermod -aG wheel deploy
id deploy

如果您习惯使用 Debian,Rocky 的两个细节可能会让您感到意外。在此处,useradd 会自动创建主目录,因此无需记忆 -m;此外,adduser 是指向 useradd 的符号链接,而非 Debian 中提供的交互式脚本。id deploy 必须将 wheel 列入组名中。该组即为授权的核心:Red Hat 默认的 /etc/sudoers 包含 %wheel ALL=(ALL) ALL 这一行,因此成员身份是获取 root 权限的关键,而 sudo grep -n '^%wheel' /etc/sudoers 则用于验证该行确实已启用且未被注释。事后通过 sudo 记录谁执行了什么操作也很有必要,审计服务器上的用户命令 一节涵盖了这方面的内容。

现在,在密码登录功能仍然有效的情况下,将您的公钥从本地机器复制到服务器。

ssh-copy-id deploy@203.0.113.10
ssh deploy@203.0.113.10

执行第二条命令后,您应直接进入 shell 而无需输入密码。在该会话中运行 sudo -v。它会要求输入您刚才设置的账户密码;如果 wheel 成员身份已生效,该命令将静默返回。请保持该会话开启。

为什么在 Rocky 上即使文件看起来正确,密钥登录仍会失败

ssh-copy-id 可以正确设置 SELinux 标签,因为它以文件所有者的身份写入文件。手动创建 authorized_keys 通常无法做到这一点,这是 Red Hat 系列发行版特有的陷阱,Ubuntu 中不存在此问题。以 root 身份创建 /home/deploy/.ssh,或者从 /tmp/root 复制文件时,文件会带有错误的 SELinux 标签。此时 sshd 被拒绝读取该文件,导致密钥认证失败,而 ls -l 中却显示一切正常。

ls -Z /home/deploy/.ssh/authorized_keys
sudo restorecon -Rv /home/deploy/.ssh
sudo ausearch -m AVC -ts recent

ls -Z 应当显示类型 ssh_home_t。如果文件显示为 user_home_t,或者从 /root 复制出来后显示为 admin_home_t,这就是故障所在,使用 restorecon 可以根据策略重新标记文件。ausearch 会打印出匹配的拒绝访问记录,表现为一行 avc: denied { read },其中指明了 comm="sshd",这就是区分 SELinux 问题与普通权限问题的依据。常规权限限制依然有效:目录必须为 700 模式,文件必须为 600 模式,否则 sshd 会向日志写入 Authentication refused: bad ownership or modes for file

按照 Rocky 的 sshd 配置方式禁用密码登录

/etc/ssh/sshd_config 在 Rocky 9 和 10 上,首先会加载一个包含配置片段的目录。

Include /etc/ssh/sshd_config.d/*.conf

sshd 会保留其找到的第一个关键字值,由于 include 位于文件顶部,因此配置片段的优先级高于主配置文件;在多个配置片段中,文件名排序靠前的优先。服务商和云镜像通常会在该目录中留下一个 50-cloud-init.conf,将 PasswordAuthentication yes 设置为启用。编号大于 50 的文件会静默失效。请先检查目录,然后创建一个排序更靠前的文件。

ls -l /etc/ssh/sshd_config.d/
sudo tee /etc/ssh/sshd_config.d/01-hardening.conf >/dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
EOF
sudo chmod 600 /etc/ssh/sshd_config.d/01-hardening.conf
sudo sshd -t

KbdInteractiveAuthentication 是大多数指南遗漏的配置项。PasswordAuthentication no 关闭了常规密码验证路径,但 PAM 的 keyboard-interactive 是通往相同密码提示符的第二条路径,因此如果保持开启,刚才所做的更改将失效。sshd -t 会解析配置文件,如果语法有效则不输出任何内容。请直接询问守护进程的最终决策,而不是仅读取你自己的配置文件。

sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication) '

所有四行配置应与你写入的内容一致。如果 passwordauthentication yes 返回了其他值,说明有另一个配置片段优先级更高,此时 ls 会显示具体是哪一个文件。确认无误后再重载服务,且务必保持当前会话处于打开状态。

sudo systemctl reload sshd

在关闭第一个终端前,请打开第二个终端并尝试登录。如果被锁定在 VPS 之外,恢复访问只能通过服务商提供的控制台,其速度远慢于其他任何方式。sshd_config 中需要修改的内容不止这四行,加固 VPS 上的 SSH 涵盖了其余的配置步骤。

仅通过 firewalld 开放您运行的服务

Rocky 默认安装并启用了 firewalld,这是本检查清单与 Ubuntu 版本的主要区别(Ubuntu 中 ufw 虽存在但处于未激活状态)。不同服务商提供的镜像配置各异,请在修改前先检查当前状态。

sudo firewall-cmd --state
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --list-all

--state 会输出 runningnot running。在标准镜像中,默认区域为 public,而 --list-all 会列出该区域中允许的服务。ssh 是其中之一,这也是您能够登录的原因。仅添加您实际提供的服务,不要添加其他内容。

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-services

--permanent 标志会将规则写入区域文件,但不会更改当前运行的防火墙状态。如果不加此标志添加规则,规则会立即生效,但在下次 --reload 或重启后失效。忘记使用 --reload 是导致您确信已添加的规则未出现在 --list-services 中的原因。如果您希望先测试再提交,可以先不加 --permanent 添加规则,确认服务响应正常后,再运行 sudo firewall-cmd --runtime-to-permanent。区域和富规则的功能远不止于此,VPS 的 firewalld 基础知识 中有详细介绍。

防火墙无法向您展示的一点是:大多数服务商在您的服务器前端运行了第二个网络数据包过滤器。如果 firewall-cmd --list-all 显示端口已开放,但外部连接仍然被拒绝,通常是因为该端口在服务商侧被拦截。因此,在排查服务器问题前,请先检查服务商的控制面板。

EPEL 和 CRB,仅在软件包需要时启用

Rocky 的官方仓库刻意保持精简,通过两个额外仓库来补充缺失内容。CRB(CodeReady Builder)仓库包含基础仓库中未提供的开发头文件和库。EPEL(Extra Packages for Enterprise Linux)是 Fedora 项目为该系列发行版构建的社区软件仓库,fail2ban 以及数千个其他软件包均位于此处。

sudo dnf config-manager --set-enabled crb
sudo dnf install -y epel-release
sudo dnf repolist

crb 是 Rocky 和 AlmaLinux 上的仓库 ID。Rocky 8 将同一仓库称为 powertools,而在 Red Hat Enterprise Linux 上则称为 codeready-builder-for-rhel-10-x86_64-rpms,这就是为什么直接复制的指令会因 Error: No matching repo to modify: crb 而失败。epel-release 软件包位于 Rocky 的 extras 仓库中,该仓库默认已启用,因此无需手动导入密钥。仅在有特定需求时才启用这两个仓库,因为每增加一个额外仓库,自动更新时就会多一个数据源。在 Rocky 和 AlmaLinux 上启用 EPEL 和 CRB 一文介绍了优先级和锁定(pinning)的相关内容。

使用 dnf-automatic 实现自动安全更新

如果服务器停止接收补丁,上述所有配置在三周后都将失效。Rocky 没有 unattended-upgrades。其等效方案是 dnf-automatic,它包含一个配置文件和一个 systemd 定时器,Rocky 10.2 发布版本为 4.20。

sudo dnf install -y dnf-automatic

编辑 /etc/dnf/automatic.conf。以下关键设置决定了具体执行方式。

[commands]
upgrade_type = default
random_sleep = 3600
download_updates = yes
apply_updates = yes
reboot = never

[emitters]
emit_via = stdio

apply_updates 在默认配置文件中被设置为 no。这是本节中最容易踩的坑:安装软件包并启用定时器后,如果直接离开,机器每天早上只会下载更新,但不会安装任何补丁。请将其设置为 yes,随后检查运行记录以确认更新是否生效。

sudo systemctl enable --now dnf-automatic.timer
systemctl list-timers dnf-automatic.timer
journalctl -u dnf-automatic.service --since -7d

list-timers 应该会在次日显示 NEXT 时间,如果运行失败或未执行任何操作,日志中会说明原因。有两个细节很容易出错。该软件包还附带了 dnf-automatic-install.timerdnf-automatic-download.timerdnf-automatic-notifyonly.timer,这些单元会强制覆盖你的配置文件并使用其固定的行为,因此请仅启用 dnf-automatic.timer,否则你刚才编辑的文件将被忽略。

第二个细节是 upgrade_type。将其设置为 security 听起来很稳妥,但在基于重建的发行版上,这反而风险更高,因为它依赖于随软件包发布的公告元数据(updateinfo.xml),而 Rocky 的部分分支曾出现过元数据滞后的情况。在正式依赖此功能前,请先在自己的服务器上进行测试。

sudo dnf updateinfo list --available --security

如果系统存在待更新项但列表为空,说明元数据未将任何内容标记为安全修复,因此 upgrade_type = security 将不会安装任何内容。default 会升级所有内容,在企业级稳定分支上,这通常是一组规模较小且经过充分测试的变更。在 Rocky 和 AlmaLinux 上运行 dnf-automatic 涵盖了通知发送、重启设置以及如何锁定软件包版本等内容。

在仅使用密钥的服务器上是否需要暴力破解防护?

在配置了 PasswordAuthentication noKbdInteractiveAuthentication no 后,SSH 暴力破解攻击无法成功,因为没有可供猜测的密码。此时剩下的问题仅是日志冗余以及拒绝连接时消耗的少量 CPU 资源。这就是在小型服务器上使用 fail2ban 的真实原因:它能让 journalctl -u sshd 重新变得可读。如果服务器上运行了任何基于密码认证的服务,那么部署该防护的必要性会显著增加。

fail2ban 包含在 EPEL 仓库中,因此请先启用该仓库。Rocky 10 将获得 1.1.0 版本。

sudo dnf install -y fail2ban-server fail2ban-firewalld fail2ban-selinux fail2ban-systemd

fail2ban-firewalld 是此处关键的子软件包。若不安装它,fail2ban 会尝试使用 iptables 命令执行封禁,而在使用 firewalld 的系统上,这意味着两个工具会在互不知情的情况下同时修改同一个 nftables 规则集。fail2ban-selinux 提供了策略模块,允许守护进程在 SELinux 保持强制模式(enforcing)的情况下正常工作。默认情况下不会启用任何 jail,且 jail.conf 会在软件包更新时被覆盖,因此请将您的配置存放在其旁边的独立文件中。

sudo tee /etc/fail2ban/jail.d/sshd.local >/dev/null <<'EOF'
[sshd]
enabled = true
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
EOF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

backend = systemd 会读取 journal 而非 /var/log/secure,这在最小化镜像中是正确的选择,因为 journal 始终存在,而日志文件仅在安装了 rsyslog 时才会生成。fail2ban-client status sshd 应显示包含过滤器和动作部分的 jail 配置,以及一个初始为空的已封禁地址列表。在公网 IP 上,该列表很快就会被填满。请使用 sudo firewall-cmd --list-rich-rules 确认封禁操作已实际生效至防火墙。将 bantime 设置为小时而非天,并将您自己的固定 IP 地址添加到同一文件中的 ignoreip 列表,因为配置错误的 jail 第一个锁定的通常就是您自己。

保持 SELinux 强制模式,并执行端口变更所需的 semanage 操作

互联网上关于 Rocky 最常见的建议是设置 SELINUX=disabled 并重启。请勿这样做。SELinux 是你选择该系列发行版而非 Ubuntu 的主要原因之一,其内置策略是为这些仓库中的软件编写的,默认安装的 nginxpodman 在此策略下无需任何修改即可运行。Docker 是常见的例外,因为它来自这些仓库之外,且其绑定挂载(bind mounts)在标记前会被拒绝,这也是 在 Rocky 或 AlmaLinux 上安装 Docker 一文花费大部分篇幅讲解的内容。首先确认你当前的状态。

getenforce
sudo sestatus

getenforce 应输出 Enforcing。某些服务商提供的镜像会预设为 Permissive,这只会记录拒绝信息而不会拦截任何操作,因此请读取该值,不要想当然。当出现故障时,拒绝记录已经为你写好了。

sudo ausearch -m AVC -ts recent

在服务器加固初期,唯一会触碰策略的地方是将 SSH 端口从 22 移走。sshd 策略仅允许绑定标记为 ssh_port_t 的端口,而 22 是唯一带有该标签的端口。如果直接设置 Port 2222 而不执行其他操作,守护进程将拒绝启动,并在 journalctl -u sshd 中产生如下错误:

error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.

解决方法只需一条命令,外加安装提供该工具的软件包。

sudo dnf install -y policycoreutils-python-utils
sudo semanage port -a -t ssh_port_t -p tcp 2222
sudo semanage port -l | grep ssh_port_t
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload

semanage 在 Rocky 10 中默认未安装,因此大多数人遇到的第一个错误是 semanage: command not found,而不是任何提及 SELinux 的信息。完整的操作序列(包括在验证新端口有效前保持 22 端口开放)请参考 在 SELinux 和 firewalld 下更改 SSH 端口。关于上下文、布尔值以及当你安装的服务确实触发策略限制时该如何处理,服务器 SELinux 基础 提供了更深入的讲解。

在小型 VPS 上可以省略的操作

并非所有配置在单台小型服务器上都有必要。

  • 保持 SELinux 为 enforcing 模式。保持默认无需额外成本,且上述 semanage 命令足以解决初次使用时可能遇到的唯一问题。
  • 保持 dnf-automaticapply_updates = yes 配合使用。未打补丁的服务器是导致实际生产事故的主要原因。
  • 如果 SSH 是唯一监听服务且仅允许密钥登录,则可跳过 fail2ban。它虽然能减少日志中的噪声,但会引入额外的守护进程,并增加将自己锁定在服务器外的风险。systemctl status fail2ban 可以显示该单元的内存占用,你可以据此评估它在你的机器上的开销。
  • 除非有特定软件包需求,否则无需启用 EPEL 和 CRB。启用软件仓库是一项长期决策,它决定了后续更新的来源。
  • 无需更改 SSH 默认端口。这只能减少日志中扫描器的噪声,无法阻挡任何针对性攻击。

唯一绝对不能省略的是:在修改 SSH 或防火墙配置时,务必保持另一个 SSH 会话处于开启状态;并在需要之前,提前掌握如何通过服务商提供的串口控制台(serial console)进行访问。对于从 Debian 或 Ubuntu 转来的用户,dnf 与 apt 命令对照表 可以帮助快速建立操作习惯,而 Ubuntu 上的 unattended-upgrades 则提供了同等功能的自动化方案。此列表的发行版通用版本请参考 新购 VPS 后的前十分钟,关于账户权限的深入探讨请参考 VPS 上的最小权限用户账户,该文对 wheel 组内成员的权限管理有更详细的说明。

FAQ

我应该在 Rocky Linux 服务器上禁用 SELinux 吗?

不应该。拒绝访问(denial)是一条提示信息,它会指出策略未预期的文件或端口。请使用 sudo ausearch -m AVC -ts recent 读取日志,然后通过 restorecon 修复标签,或设置服务所需的布尔值。如果必须放宽限制,可在调试期间将 SELINUX=permissive 设置在 /etc/selinux/config 中,这样系统只会记录拒绝信息而不会拦截任何操作。请避免使用 SELINUX=disabled,因为一旦禁用,系统将停止维护文件标签,导致后续恢复强制模式时,必须在下次启动时对磁盘进行完整重标记。

如果 SSH 仅限密钥登录,我还需要 fail2ban 吗?

对于 SSH 本身而言不需要。在设置了 PasswordAuthentication noKbdInteractiveAuthentication no 并通过 sudo sshd -T 确认生效后,暴力破解尝试因没有密码可猜,无论尝试多少次都无法成功。此时 fail2ban 的作用仅在于让日志更清爽,并略微减少处理被拒绝连接时的 CPU 开销。一旦服务器上运行了其他接受密码登录的服务(如邮件服务器或 Web 应用登录),它就有了运行价值。

为什么以 root 身份创建 .ssh 目录后,密钥登录失败?

因为该文件带有错误的 SELinux 标签,导致 sshd 被拒绝读取。请使用 ls -Z /home/deploy/.ssh/authorized_keys 进行检查。其类型应为 ssh_home_t,而以 root 身份创建或从 /root 复制出来的文件通常显示为 admin_home_t。请运行 sudo restorecon -Rv /home/deploy/.ssh 根据策略重新标记该文件。使用 sudo ausearch -m AVC -ts recent 确认诊断结果,它会打印一行 avc: denied { read } 并指出 comm="sshd"。同时检查常规权限:目录应为 700,文件应为 600。

Rocky Linux 上有什么可以替代 unattended-upgrades?

dnf-automatic,通过 sudo dnf install -y dnf-automatic 安装,并由 /etc/dnf/automatic.confdnf-automatic.timer 驱动。请在 [commands] 部分设置 apply_updates = yes,因为默认配置为 no,否则定时器只会下载更新而不会安装。仅启用 dnf-automatic.timer,不要启用其他单元,因为该软件包自带的额外定时器会覆盖你的配置文件,强制执行其固有的行为。

我应该在新服务器上使用 Rocky Linux 8 吗?

优先选择 10 版本,如果依赖的软件尚未提供 10 版本的构建,则选择 9 版本。Rocky 8 在受支持的分支中拥有最旧的 Python 和 OpenSSL 版本,因此越来越多的新软件不再提供针对该版本的软件包。这会导致你不得不从源码编译,或在原本追求简洁的机器上添加第三方仓库。请使用 cat /etc/rocky-release 检查当前运行系统的实际版本,因为服务商提供的标记为 "Rocky Linux" 的镜像,有时版本比控制面板显示的要旧。