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

Rocky AlmaLinux 設定 dnf-automatic 安全更新

學會在 Rocky Linux 9 與 AlmaLinux 9 設定 dnf-automatic,啟用僅安全更新、systemd timer、電子郵件通知與可控重新開機,並避開 advisory metadata 缺漏導致的無更新陷阱。

Rocky Linux 和 AlmaLinux 上的 dnf-automatic 功能

dnf-automatic 是在 Rocky Linux 和 AlmaLinux 上取得無人值守安全更新的方式。它是一個由 systemd timer 啟動的小型程式,會讀取 /etc/dnf/automatic.conf,並套用該檔案允許的更新。安裝只需執行一個指令。本指南其餘內容將說明各項設定,這些設定會決定它能保護伺服器,還是靜默地不執行任何操作。

如果你是從 Debian 或 Ubuntu 轉換過來,這項功能就等同於 unattended-upgrades 在 Ubuntu VPS 上執行的工作。其中一項差異比其他差異都重要:套件管理程式如何定義「security」。在 Ubuntu 上,這是獨立的 archive pocket。在 RHEL 系列上,這是附加在已發布 advisory 上的 metadata,而這些 metadata 可能缺少或過期。若將 dnf-automatic 指向沒有 advisory data 的 repository,它會在回報成功的同時不安裝任何內容。

本指南以 Rocky Linux 9 和 AlmaLinux 9 為基準。這些版本使用 DNF 4(DNF 是 RHEL 系列上的套件管理程式),內容截至 August 2026。10 版本已改用 DNF5,名稱也有所變更,因此本指南會在接近結尾處提供獨立章節。以下每個指令都可在你自己的伺服器上執行,旁邊也列出預期看到的輸出。

安裝 dnf-automatic 並閱讀套件附帶的設定

啟用自動更新應納入 新 VPS 前 10 分鐘的設定,順序是在建立非 root 使用者並設定防火牆之後。如果防火牆尚未設定,Rocky 和 AlmaLinux 隨附 firewalld;執行幾個命令即可開放 SSH、開放網站監聽的連接埠,並讓這些設定在重新開機後持續生效。

sudo dnf install -y dnf-automatic
rpm -q dnf dnf-automatic
systemctl is-enabled dnf-automatic.timer

在全新安裝上,systemctl is-enabled 會輸出 disabled,因為安裝套件不會啟動任何服務。這是伺服器「已安裝 dnf-automatic」卻從未套用任何更新的最常見原因。

DNF 版本會影響其中一個選項。reboot 設定在 DNF 4.15 中由上游加入,Red Hat 於 November 2023 透過公告 RHBA-2023:6645,將其回移到 dnf-4.14.0-6.el9。Rocky 9 和 AlmaLinux 9 會重新建置該套件,因此目前的主機具備這項設定,但自 2023 年起未曾更新的主機則沒有。

設定檔位於 /etc/dnf/automatic.conf。套件附帶的版本會列出此組建支援的所有選項及其預設值,並以註解標示。編輯前先閱讀一次,因為該檔案才是此版本實際支援內容的依據。

決定行為的兩個開關

download_updatesapply_updates 位於 [commands] 區段,決定服務的行為。在 EL9(enterprise Linux 9,Rocky 9 和 AlmaLinux 9 共用的基礎版本)上,兩者預設都是 no,因此啟用後未經修改的 dnf-automatic 只會告知可用的更新。

  • 兩者都是 no:dnf-automatic 會回報可用的更新,但不會變更系統。
  • download_updates = yes 搭配 apply_updates = no:套件會下載到 DNF 快取。之後安裝時速度較快,且不需要網路,但當晚不會套用任何變更。
  • 兩者都是 yes,搭配 upgrade_type = default:所有可用的更新都會安裝,不論是否為安全性更新。
  • 兩者都是 yes,搭配 upgrade_type = security:只會安裝安全性公告中列出的套件。

對於對外提供服務的 VPS,可從以下設定開始:

[commands]
upgrade_type = security
download_updates = yes
apply_updates = yes
random_sleep = 0
network_online_timeout = 60
reboot = never

network_online_timeout 是執行等待可用網路的秒數;對剛完成開機的主機而言,這項設定很重要。random_sleep 是較早期用來分散多台機器負載的方式,而現在則由 timer 負責這項工作。執行 systemctl cat dnf-automatic.service 可查看隨附服務傳遞的確切旗標。

不必等到 06:00,即可驗證檔案是否按照預期運作:

sudo systemctl start dnf-automatic.service
sudo journalctl -u dnf-automatic.service -n 50 --no-pager

journal 會顯示此次執行評估了哪些項目,以及實際執行了哪些動作。也可以從命令列強制指定單次執行的行為;這只會覆寫該次執行的檔案設定:

sudo dnf-automatic --downloadupdates --no-installupdates

Rocky 與 Alma 上 upgrade_type = security 的實際意義

DNF 不會透過比較版本號碼來判斷更新是否屬於安全性更新。它會讀取 errata 中繼資料:儲存在 repository 內、名為 updateinfo.xml 的檔案,其中每則公告都會列出修正該問題的套件。AlmaLinux 將這些公告發布為 ALSA advisories,Rocky 則發布為 RLSA。upgrade_type = security 會根據這些中繼資料建立篩選條件,只升級符合條件的套件。

這會產生兩個後果,而且都容易讓人意外。

第一,沒有中繼資料就不會有更新。如果 repository 沒有提供 updateinfo.xml,篩選條件就不會符合任何套件,執行結果會在 journal 中以這一行結束:

No security updates needed, but 3 updates available

系統並未完成修補,但也沒有回報失敗。請自行確認:

dnf updateinfo list --security
dnf check-update

如果 dnf check-update 列出套件,而 dnf updateinfo list --security 完全沒有輸出,可能是目前沒有任何待更新套件帶有公告,也可能是 repository 沒有可供讀取的公告資料。Rocky 與 AlmaLinux 都會發布這些資料,因此在這兩個發行版上,空清單通常代表實際情況。CentOS Stream 則完全不發布這些資料。

第二,security mode 並不是最小幅度的變更。dnf-automatic 會加入 security 篩選條件,然後執行一般的升級流程,因此公告中列出的套件會升級到 repository 中的最新版本,並一併更新其相依套件。若只升級到最早修正該公告的版本,幅度會更小;這項操作必須手動執行 dnf upgrade-minimal --security。dnf-automatic 沒有對應的設定。

Rocky 還有一項注意事項。Rocky 透過自己的 pipeline,根據 Red Hat 資料產生 errata;但該 pipeline 曾經落後。2025 年 9 月,使用者回報 Rocky 9 BaseOS updateinfo.xml 自 2024 年 12 月起就沒有更新,因此 --security 缺少近期公告;Rocky 維護人員也確認這是已知問題。如果你依賴 upgrade_type = security,請不時將公告清單與近期的 RLSA 公告進行比對。若系統更重視涵蓋率而非變更控管,依你選定的排程執行 upgrade_type = default 會是較安全的設定。

實際執行它的 systemd timer

sudo systemctl enable --now dnf-automatic.timer
systemctl list-timers dnf-automatic.timer

list-timers 應列出一列,並顯示約 1 天後的 NEXT 時間。表格為空表示 timer 未啟用,因此永遠不會執行。

套件提供的 timer 會在 *-*-* 6:00 執行,並使用 RandomizedDelaySec=60mPersistent=true。隨機延遲會將整個伺服器群組分散在 1 小時內執行,避免所有伺服器在同一秒存取 mirror。Persistent=true 表示伺服器若在 06:00 關機,開機後不久會執行錯過的工作,而不是略過當天的執行。

使用 drop-in 變更排程。不要編輯套件提供的 unit,因為套件升級會取代 /usr/lib/systemd/system 下的檔案。

sudo systemctl edit dnf-automatic.timer
[Timer]
OnCalendar=
OnCalendar=*-*-* 03:30
RandomizedDelaySec=30m

空白的 OnCalendar= 行是必要的。OnCalendar 會累加,因此如果沒有先重設,原本的 06:00 項目會保留,並再加入第二個項目,導致工作每天執行 2 次。使用 systemctl list-timers dnf-automatic.timer 確認結果,並查看 NEXT 欄位。相同的 drop-in 規則也適用於其他排程項目,詳見撰寫 systemd service 與 timer unit

接下來是容易踩到的陷阱。套件另外提供 3 個 timer:dnf-automatic-notifyonly.timerdnf-automatic-download.timerdnf-automatic-install.timer。每個 timer 都會使用命令列旗標啟動相同的程式,而這些旗標會覆寫設定檔中的 download_updatesapply_updates。如果在 dnf-automatic.timer 旁啟用其中 1 個,工作就會以 2 種不同的行為執行 2 次,看起來就像設定檔被忽略。啟用 1 個 timer,然後檢查:

systemctl list-unit-files 'dnf-automatic*'

如何知道何時安裝了某項軟體?

emit_via 會控制 [emitters] 區段中的回報方式。在 systemd 下,stdio emitter 會將內容寫入 journal。這是可靠的選項,因為不需要安裝其他元件:

sudo journalctl -u dnf-automatic.service --since -7d --no-pager

motd emitter 會將報告寫入 /etc/motd,並取代該檔案原有的內容。如果該檔案也用來放置登入橫幅,請不要啟用此 emitter。

email emitter 會透過 SMTP(簡易郵件傳輸協定)連線到 email_hostemail_port。這兩項預設值分別為 localhost 和 25。新建的 VPS 通常沒有程式在該處監聽,因此連線會被拒絕,也不會寄出郵件。依賴此功能前,請先執行 ss -lnt | grep ':25';如果輸出為空,請設定僅轉送郵件的 Postfix。郵件功能正常時,主旨會顯示 Updates applied on 'web01'.,名稱取自 system_name

其他情況下,command emitter 會將報告透過標準輸入傳給您指定的程式:

[emitters]
emit_via = stdio, command
system_name = web01.example.com
send_error_messages = yes

[command]
command_format = /usr/local/bin/notify-ops
stdin_format = {body}

send_error_messages 的預設值為 no,這表示執行失敗時完全不會回報。請啟用它。只回報成功結果的修補系統比完全沒有修補系統更糟,因為沒有訊息會被解讀為系統正常。

dnf-automatic 不會重新啟動服務

安裝套件會取代磁碟上的檔案。已在執行中的程序會繼續使用記憶體中的舊程式碼,因此,已修補的函式庫對上個月啟動的 daemon 不會產生作用。已安裝與實際生效之間的落差,正是 unattended patching 需要重新啟動政策,而不只是安裝政策的原因。

sudo dnf install -y dnf-plugins-core
dnf needs-restarting -s
dnf needs-restarting -r

-s 會列出在啟動後檔案曾變更的 systemd 服務。-r 只回答一個問題,並輸出以下兩個區塊之一:

Core libraries or services have been updated since boot-up:
  * kernel
Reboot is required to fully utilize these updates.
No core libraries or services have been updated since boot-up.
Reboot should not be necessary.

-r 並非深度分析。它會檢查固定的套件清單:kernelkernel-corekernel-rtglibclinux-firmwaresystemddbusdbus-brokerdbus-daemonmicrocode_ctl。如果其中一個套件是在上次開機後安裝,便會得到第一個結果。當系統上的其他元件也需要重新開機才能生效時,請將自訂套件名稱加入 /etc/dnf/plugins/needs-restarting.d/ 下、檔名以 .conf 結尾的檔案。

腳本有一點需要注意:dnf needs-restarting -r 在需要重新開機與命令本身執行失敗時都會傳回非零狀態,因此無法只靠退出狀態區分這兩種情況。請讀取輸出的文字。

重新啟動服務是較小的變更,通常也是正確的做法。請從已開啟的第二個 SSH 工作階段重新啟動 SSH daemon,這樣即使設定錯誤,也不會把自己鎖在系統外。新 kernel 是只能重新開機才能處理的情況,因為執行中的 kernel 無法直接取代。如果要將某天早上的更新分成這兩類,哪些更新需要重新開機,哪些只需要重新啟動服務 會逐一檢查輸出中的套件。

容器屬於另一種情況,因為 dnf-automatic 只會修補主機上的套件,不會修改映像中內建的 userland。因此,執行 Rocky Linux 或 AlmaLinux 上的 Docker Engine 的主機,也需要重新拉取映像並重建容器,修正內容才會套用到實際提供網路流量的程式碼。

主機應該自行重新開機嗎?

[commands]
reboot = when-needed
reboot_command = shutdown -r +5 'Rebooting after applying package updates'

reboot = never 是預設值。when-changed 會在套用任何更新後重新開機。when-needed 只會在 needs-restarting -r 背後的檢查判定核心套件已替換時重新開機。這是大多數單一伺服器管理者想要的設定,並搭配自行選定的計時器時段。預設的 reboot_command 會透過 shutdown 提前五分鐘通知已登入的使用者,你也可以將這段時間延長。

啟用前,請先確認兩件事。所有相依的服務都必須能在開機時自行啟動。手動啟動的 Docker Compose 堆疊通常就是缺少這項設定。你也需要供應商提供的主控台或救援存取權限,因為無法開機的 kernel 無法透過 SSH 修復。如果缺少其中任何一項,請保留 reboot = never,並在查看 journal 後自行重新開機。

Rocky、AlmaLinux 與 CentOS Stream:三者的差異

在 Rocky 9 與 AlmaLinux 9 上,上述內容完全相同,包括設定路徑與 unit 名稱。兩者都會發布 errata,因此 upgrade_type = security 有可供篩選的資料。前文所述的 Rocky 過時 errata,是兩者日常行為實際出現差異的少數情況之一。因此,如果主機尚未建置,請將這項差異與區分兩者的相容性承諾及較舊 CPU 支援一併納入考量。

CentOS Stream 是例外,而且差異很明顯。Stream 的軟體庫不包含 updateinfo.xml,因此安全性篩選條件永遠無法符合,每次執行都會回報 No security updates needed。在 Stream 上,請使用 upgrade_type = default,並接受系統會安裝所有更新。Stream 的版本也領先 RHEL,因此相同設定在 Stream 主機上的變動幅度,會比 Rocky 或 AlmaLinux 主機更大。這項差異不是套件封裝造成的偶然結果,而是 Red Hat 在 2020 年決定將 CentOS 改為 RHEL 的 rolling preview 所致;這項決定也促成了 Rocky Linux 與 AlmaLinux 的誕生

Rocky 10 與 AlmaLinux 10 改用 DNF5,因此部分名稱有所變更。上游 DNF5 文件將計時器列為 dnf5-automatic.timer,將隨附的預設值放在 /usr/share/dnf5/dnf5-plugins/automatic.conf,而你的覆寫設定仍放在 /etc/dnf/automatic.confdownload_updates 的預設值也從 no 改為 yes,並新增 distro-sync 作為 upgrade_type。advisory 查詢指令為 dnf advisory list,並保留 updateinfo 作為別名。在從針對 9 撰寫的指南複製套件或 unit 名稱前,請先確認你的版本實際安裝了哪些內容:

dnf list --available '*automatic*'
systemctl list-unit-files '*automatic*'

許多針對此主題發布的指南仍只涵蓋 Rocky 8。自這些指南撰寫後,可用的選項已有增加,因此請檢查自己主機上的註解檔案,不要直接依賴舊文章。

失敗情況與你會看到的字串

完全沒有執行任何工作。 systemctl list-timers dnf-automatic.timer 顯示空白表格,而 systemctl is-enabled dnf-automatic.timer 顯示 disabled。套件已安裝,但計時器從未安裝。

工作有執行,但沒有安裝任何項目。 日誌中會出現 No security updates needed, but 3 updates available。安全性篩選器沒有比對到任何項目,原因可能是沒有待處理項目具有安全性公告,也可能是套件庫未發布公告資料。

某項設定看起來沒有生效。 DNF 會在除錯層級的 automatic.conf 中記錄未知選項,然後使用預設值。因此,拼錯的鍵值不會產生任何作用,也不會發出警告。請寫入 apply_update = yes,而 apply_updates 會維持在 no,導致系統持續下載,卻從未安裝。每次修改後,執行 sudo systemctl start dnf-automatic.service 並查看日誌,不要只相信設定檔。

工作每天執行兩次。 目前啟用了兩個計時器。systemctl list-unit-files 'dnf-automatic*' 會顯示是哪兩個計時器,額外的計時器可能會傳入優先於設定檔的旗標。

沒有收到郵件。 可能是沒有程式在連接埠 25 上接收 email 發送器的連線,也可能是 send_error_messages 仍為 no,而唯一值得報告的事件是錯誤。

已修補的服務仍回報舊版本。 磁碟上的檔案已更新,但記憶體中的程序仍是舊版本。dnf needs-restarting -s 會列出需要重新啟動的服務。

FAQ

dnf-automatic 在 Rocky Linux 上只會安裝安全性更新嗎?

只有在 upgrade_type = security 設定於 /etc/dnf/automatic.conf 時才會,而且儲存庫也必須發布 errata 中繼資料。Rocky Linux 和 AlmaLinux 都會發布這類資料,因此篩選器有可比對的公告。隨附的預設值是 upgrade_type = default;一旦 apply_updates = yes,就會安裝所有可用更新。

為什麼 dnf-automatic 顯示「不需要安全性更新,但有 3 個可用更新」?

DNF 會讀取儲存庫中的 updateinfo.xml 來判斷哪些更新屬於安全性更新;每則公告都會列出修正該問題的套件。這些中繼資料遺失或過期時,安全性篩選器會找不到任何相符項目,但一般更新仍在等待安裝,因此會顯示這行訊息。CentOS Stream 完全不發布 errata,因此出現這種情況是預期行為。在 Rocky 或 AlmaLinux 上,請比較 dnf updateinfo list --securitydnf check-update,並確認中繼資料為最新版本。

dnf-automatic 會在 kernel 更新後重新啟動伺服器嗎?

除非明確要求,否則不會。reboot 選項的預設值是 never。設定 reboot = when-needed 後,只有在 dnf needs-restarting -r 背後的檢查發現自開機後某個核心套件(例如 kernelglibc)已被替換時,執行程序才會重新啟動。reboot = when-changed 則會在套用任何更新後重新啟動。兩者都使用 reboot_command;其預設值為 shutdown -r +5,並會向已登入的使用者顯示警告訊息。

如何變更 dnf-automatic 的執行時間?

執行 sudo systemctl edit dnf-automatic.timer,並加入 [Timer] 區段;先放置空白的 OnCalendar= 行,再填入排程,例如 OnCalendar=*-*-* 03:30。這個空白行是必要的,因為 OnCalendar 會累積設定;省略該行會保留隨附的 06:00 執行時間,並再加入第二個排程。使用 systemctl list-timers dnf-automatic.timer 驗證,並讀取 NEXT 欄位。

伺服器會自行安裝修補程式,我還需要檢查嗎?

需要。dnf-automatic 只會安裝套件,之後不會執行其他處理。它不會重新啟動 daemon;除非 emit_via 指定了你實際查看的 emitter,否則也不會產生你看得到的報告。至少應將 emit_via 設為 stdio,啟用 send_error_messages 以便回報失敗情況,並在修補時段結束後執行 dnf needs-restarting -s,找出仍在執行舊版程式碼的服務。