March 3Mar 3 適用環境 作業系統:Debian 13 VPS規格:2 vCPU / 2GB RAM 權限要求:需具備 root 權限或 sudo 權限 網路需求:需能連線至 Debian 官方套件庫 ---------- 前言 ---------- 對於長期運行的論壇網站,自動安全更新是降低人工維護成本、及時修補已知漏洞的第一道防線 然而,不加控制的自動更新同樣可能破壞生產環境,例如,核心升級觸發重開機、PHP版本跳升導致擴充套件相容性斷裂等 本文的目標是在「及時修補安全漏洞」與「維持服務穩定」之間取得平衡,並提供足夠的監控機制讓團隊掌握每一次更新的狀態 ----------------------- 事前準備與快照備份 ----------------------- 強烈建議:在任何系統層級變更前,先對VPS建立快照(Snapshot)或映像備份 這是生產環境的基本操作紀律,不論操作多熟練皆不應跳過 --------------------- 確認目前系統版本 --------------------- cat /etc/os-release uname -r 預期輸出 PRETTY_NAME="Debian GNU/Linux 13 (trixie)" ... 6.12.xx+deb13-cloud-amd64 ---------------------------- 確認APT套件庫來源正常 ---------------------------- apt update 若出現 404 Not Found 或 GPG 錯誤,必須先修正 /etc/apt/sources.list 再繼續,否則後續步驟都無意義 Debian 13 標準 sources.list 參考 deb http://deb.debian.org/debian trixie main contrib non-free-firmware deb http://deb.debian.org/debian trixie-updates main contrib non-free-firmware deb http://security.debian.org/debian-security trixie-security main contrib non-free-firmware --------------------- 全面更新現有套件 --------------------- 在設定自動更新前,應先手動將系統更新至最新狀態,確保基線一致 apt update -y && apt upgrade -y 提示:升級過程若出現「是否覆蓋設定檔?」提示,建議選 N(保留原有設定) 避免覆蓋 /etc/nginx/nginx.conf、/etc/mysql/ 等自訂組態 ------------------------- 升級後清理多餘套件 ------------------------- apt autoremove --purge -y apt clean ---------------------- 安裝必要套件 ---------------------- apt install -y unattended-upgrades apt-listchanges needrestart 說明: unattended-upgrades 自動安全更新的核心引擎 apt-listchanges 更新前顯示套件變更摘要,有助於審閱 changelog needrestart 偵測哪些服務使用了已更新的函式庫,提示需重啟的服務 新手容易遺漏:needrestart 是避免「套件已更新但舊版函式庫仍在記憶體中執行」的關鍵工具 例如 OpenSSL 更新後,若 Nginx 未重啟,仍會繼續使用舊版 libssl,安全修補形同虛設 ------------------------ 啟用自動安全更新 ------------------------ 啟用自動安全更新 dpkg-reconfigure --priority=low unattended-upgrades 畫面將出現: Automatically download and install stable updates? <Yes> / <No> 選擇 <Yes>,確認啟用自動下載並安裝穩定版更新 ----------------------------------- 設定更新來源規則(僅安全更新) ----------------------------------- 此檔案定義哪些套件庫的更新會被自動安裝,以及各項行為控制 寫入生產環境設定 vi /etc/apt/apt.conf.d/50unattended-upgrades 貼上以下內容 // ========================= // 自動安全更新設定 - LNMP 環境 // 最後修改:請填入日期與操作人員 // ========================= Unattended-Upgrade::Origins-Pattern { // Debian 官方穩定版 "origin=Debian,codename=${distro_codename},label=Debian"; // Debian 安全更新(兩種格式皆需保留,視 Debian 版本而定) "origin=Debian,codename=${distro_codename},label=Debian-Security"; "origin=Debian,codename=${distro_codename}-security,label=Debian-Security"; }; // 套件黑名單:以下套件不會被自動更新 Unattended-Upgrade::Package-Blacklist { // 核心:自動更新核心可能觸發重開機或模組相容性問題 "linux-image-*"; "linux-headers-*"; "linux-modules-*"; // PHP:版本跳升可能破壞論壇擴充套件(如 IPS、XenForo) // 若確認論壇相容,可移除以下黑名單項目 "php*"; // MySQL / MariaDB:主版本升級需要手動 schema 遷移 "mysql-server*"; "mariadb-server*"; // Nginx:主要設定變更需人工確認 // 安全性修補通常可接受,依環境決定是否保留此黑名單 // "nginx*"; }; // 是否自動重開機(生產環境強烈建議 false) Unattended-Upgrade::Automatic-Reboot "false"; // 若上方設定為 true,指定重開機時間(避開尖峰時段) Unattended-Upgrade::Automatic-Reboot-Time "08:00"; // 是否允許在有使用者登入時自動重開機 Unattended-Upgrade::Automatic-Reboot-WithUsers "false"; // 自動移除已不需要的核心套件(節省 /boot 空間) Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; // 自動移除更新後不再需要的相依套件 Unattended-Upgrade::Remove-New-Unused-Dependencies "true"; // 自動移除已廢棄套件 Unattended-Upgrade::Remove-Unused-Dependencies "true"; // 寄送更新通知 Email(需有 MTA,如 msmtp / postfix) // Unattended-Upgrade::Mail "your-sre-team@example.com"; // Unattended-Upgrade::MailReport "on-change"; // only-on-error | on-change | always // 分割差異:僅在發生錯誤時寄信(減少通知噪音) Unattended-Upgrade::MailOnlyOnError "true"; // 詳細日誌(建議 production 環境開啟,便於事後審計) Unattended-Upgrade::Verbose "false"; // 最小化 APT 輸出(減少日誌雜訊) Unattended-Upgrade::MinimalSteps "true"; 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter 提醒:php* 黑名單在論壇環境非常重要 Debian 安全更新有時會一併跳升 PHP 次版本(如 8.2 → 8.3) 可能導致舊版論壇外掛或 composer.lock 鎖定的套件出現相容性問題,應先在測試環境驗證後再手動升級 ------------------------ 啟用自動更新排程 ------------------------ APT的定期排程由 apt.conf.d/20auto-upgrades 控制 編輯 vi /etc/apt/apt.conf.d/20auto-upgrades 貼上以下內容 // 每天更新套件清單 APT::Periodic::Update-Package-Lists "1"; // 每天下載可升級的套件(但不安裝,由 Unattended-Upgrade 控制) APT::Periodic::Download-Upgradeable-Packages "1"; // 每 7 天自動清除已下載但不再需要的套件快取 APT::Periodic::AutocleanInterval "7"; // 每天執行自動更新(值為間隔天數) APT::Periodic::Unattended-Upgrade "1"; 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter ---------------------------------------------------- 重啟 unattended-upgrades 服務使設定生效 ---------------------------------------------------- 啟用 systemctl enable unattended-upgrades 重啟 systemctl restart unattended-upgrades 確認服務狀態,預期輸出應包含 active (running) systemctl status unattended-upgrades ------------------------------------------------ 確認 needrestart 設定(避免服務靜默中斷) ------------------------------------------------ needrestart 在套件更新後自動偵測哪些服務仍在使用舊版函式庫,是LNMP環境特別重要的環節 ----------------- 查看預設設定 ----------------- cat /etc/needrestart/needrestart.conf | grep -v '^#' | grep -v '^$' ------------------ 調整重啟模式 ------------------ 編輯 vi /etc/needrestart/needrestart.conf 搜尋 $nrconf{restart} 接著修改以下設定(生產環境建議使用 i 互動模式) # 模式說明 # l = list only(僅列出,不重啟)← 生產環境推薦,人工確認後再重啟 # i = interactive(互動詢問) # a = automatically(自動重啟服務,不含核心)← 可接受,但需謹慎 $nrconf{restart} = 'l'; 建議:若論壇有 SLA 要求,應使用 l 模式,搭配後述的 Cron 監控,由維運人員在離峰時段手動重啟 --------------------------------- 手動檢查需要重啟的服務 --------------------------------- needrestart -k 輸出示範: NEEDRESTART-VER: 3.x NEEDRESTART-SVC: nginx.service NEEDRESTART-SVC: php8.3-fpm.service NEEDRESTART-SVC: mariadb.service 看到以上輸出時,依序重啟(建議在低流量時段執行) systemctl restart nginx systemctl restart php8.3-fpm systemctl restart mariadb ----------------------------- 重啟後確認各服務狀態 ----------------------------- systemctl status nginx php8.3-fpm mariadb -------------------- 重開機驗證 -------------------- 初次設定完成後建議重開機,確保核心與服務以乾淨狀態啟動 重開機 reboot 重開機後驗證清單 確認自動更新服務正在運行,應顯示 active (running) systemctl status unattended-upgrades 確認排程設定正確載入 apt-config dump APT::Periodic 預期顯示 APT::Periodic ""; APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::AutocleanInterval "7"; APT::Periodic::Unattended-Upgrade "1"; 模擬執行自動更新(--dry-run 不會實際安裝套件) unattended-upgrade --dry-run --verbose 確認LNMP核心服務正常 (此時還未安裝LNMP服務) systemctl status nginx systemctl status php8.3-fpm systemctl status mariadb 確認論壇網站可正常回應 (此時還未安裝LNMP服務) curl -I http://localhost ---------------------------------------- 強制執行一次完整更新(驗證流程) ---------------------------------------- unattended-upgrade --verbose 執行後 查看日誌確認無錯誤 tail -50 /var/log/unattended-upgrades/unattended-upgrades.log ----------------------------- 監控自動更新執行狀態 ----------------------------- 啟用 systemctl enable cron 啟動 systemctl start cron 檢查狀態,確認已運行 active (running) systemctl status cron ---------------------建立監控腳本---------------------比起直接在 crontab 寫複雜指令,建議將監控邏輯封裝成獨立腳本,方便維護與版本控管建立vi /usr/local/bin/check-unattended-upgrades.shcheck-unattended-upgrades.sh貼上以下內容儲存檔案並離開vi編輯器按 Esc,輸入 :wq,按 Enter Edited June 2Jun 2 by Jack
May 20May 20 Author -------------------- 給予執行權限 -------------------- chmod +x /usr/local/bin/check-unattended-upgrades.sh chown root:root /usr/local/bin/check-unattended-upgrades.sh ------------------------------- 設定 Cron 排程 ------------------------------- 編輯 crontab -e 在未尾加入以下內容 # ==================== # 自動更新監控排程 # ==================== # 每天早上 7:00 檢查自動更新是否有錯誤 0 7 * * * /usr/local/bin/check-unattended-upgrades.sh # 每天早上 6:00 檢查 needrestart(列出需重啟服務但不自動重啟) 0 6 * * * /usr/sbin/needrestart -k >> /var/log/needrestart-daily.log 2>&1 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter------------------------ 驗證監控腳本 ------------------------ /usr/local/bin/check-unattended-upgrades.sh -------------------------- 定期維護建議 -------------------------- 查看日誌目錄 ls -lah /var/log/unattended-upgrades/ 即時監看日誌 tail -f /var/log/unattended-upgrades/unattended-upgrades.log 查看詳細除錯日誌 tail -f /var/log/unattended-upgrades/unattended-upgrades.log.1 建議每週至少檢查一次,確認: 無 ERROR 字樣 有正常的 Packages that will be upgraded: 記錄(或「無可用更新」) 更新時間點符合預期 unattended-upgrades 的日誌自帶 logrotate 設定,通常不需額外設定。確認方式: cat /etc/logrotate.d/unattended-upgrades --------------------------------------- 定期清理舊核心(釋放 /boot 空間) --------------------------------------- 僅在確認新核心運作正常後執行(重開機後驗證 uname -r 版本) 查看目前使用的核心 uname -r 列出所有已安裝核心 dpkg --list | grep linux-image 自動移除舊核心(保留當前使用版本) apt autoremove --purge -y -------------------------- 手動檢查安全性 CVE -------------------------- 自動更新補的是套件層級的安全修補,但部分 CVE 需要手動確認影響範圍: 查看 Debian Security Tracker(需連網) https://security-tracker.debian.org/tracker/ 本機檢查哪些套件有可用的安全更新 apt list --upgradable 2>/dev/null | grep -i security ----------------------- 測試環境先行原則 ----------------------- 對於任何計畫性的手動升級(特別是黑名單中的 PHP、MariaDB、Nginx),務必遵循: 測試環境驗證 → 確認服務正常 → 安排維護時窗 → 生產環境升級 → 監控 15分鐘
May 20May 20 Author ------------------- 常見問題排除 ------------------- 問題一:服務未自動更新 確認服務狀態 systemctl status unattended-upgrades 若未啟動,手動啟動 systemctl start unattended-upgrades systemctl enable unattended-upgrades 確認排程設定 apt-config dump APT::Periodic::Unattended-Upgrade 問題二:套件被保留(held back) 查看被保留的套件 apt-mark showhold 查看升級摘要 apt upgrade --simulate 問題三:更新失敗(網路問題) 確認 DNS 解析正常 host deb.debian.org 測試套件庫連線 curl -I http://deb.debian.org/debian/dists/trixie/Release 重建套件快取 apt clean apt update 問題四:/boot 空間不足導致核心更新失敗 查看 /boot 使用狀況 df -h /boot ls -lah /boot/ 確認目前使用的核心版本 uname -r 移除舊核心(請確認要移除的版本不是目前使用中的) apt autoremove --purge linux-image-<舊版本號> 問題五:unattended-upgrades 鎖定(lock file 問題) 確認是否有 lock 檔 ls -la /var/lib/dpkg/lock* ls -la /var/lib/apt/lists/lock 確認是否有 apt 進程在執行 ps aux | grep apt 若無相關進程但 lock 仍存在(系統崩潰後的殘留) 確認無 apt 進程後再執行 rm /var/lib/dpkg/lock-frontend rm /var/lib/dpkg/lock dpkg --configure -a 問題六:更新後 Nginx / PHP-FPM / MariaDB 無法啟動 查看各服務錯誤日誌 journalctl -xe -u nginx --since "1 hour ago" journalctl -xe -u php8.3-fpm --since "1 hour ago" journalctl -xe -u mariadb --since "1 hour ago" 測試 Nginx 設定檔語法 nginx -t 測試 PHP-FPM 設定 php-fpm8.3 --test 若為設定檔被覆蓋導致,從備份恢復 (這也是為什麼升級時要選 N 保留原有設定) --------------------------------- LNMP 論壇環境特別注意事項 --------------------------------- PHP 版本管理 論壇軟體(IPS、XenForo 等)對 PHP 版本相依性非常敏感 建議將 PHP 相關套件加入黑名單,並採用手動控制PHP版本升級的策略 查看目前安裝的 PHP 套件 dpkg --list | grep php 手動鎖定特定 PHP 版本(避免自動升級) apt-mark hold php8.3 php8.3-fpm php8.3-mysql php8.3-common 確認鎖定狀態 apt-mark showhold -------------------------------- MariaDB / MySQL 保護 -------------------------------- 資料庫的主版本升級(如 MariaDB 10.x → 11.x)需要執行 mysql_upgrade 或 mariadb-upgrade,否則可能導致資料字典不一致 絕對不能讓自動更新自行完成主版本跳升 鎖定 MariaDB apt-mark hold mariadb-server mariadb-client mariadb-common ------------------------ Nginx 安全更新策略 ------------------------ Nginx 的安全更新風險相對低,但仍可能因 header 行為變更影響論壇的 CSP / CORS 設定 建議: 移除 50unattended-upgrades 中 Nginx 的黑名單註解(讓安全更新自動安裝) 但在 Cron 監控中加入 Nginx 重啟後的健康檢查 ------------------------------ 記憶體考量(2 GB RAM) ------------------------------ 2GB RAM 的 VPS 在自動更新期間(通常在凌晨),系統負載會短暫升高 建議在 50unattended-upgrades 中確認 MinimalSteps "true" 已啟用,讓更新分批執行,降低記憶體峰值壓力 同時確認論壇的 PHP-FPM 設定合理 查看 PHP-FPM 進程設定(避免 OOM) cat /etc/php/8.3/fpm/pool.d/www.conf | grep -E "pm\.|max_children|memory" 建議 pm.max_children 不超過 (可用記憶體 MB / 平均每個 PHP 進程記憶體) 的計算結果 在 2GB 環境下,若 MariaDB + Nginx 各佔約 200 MB,PHP-FPM 可用約 1.2 GB,建議 pm.max_children = 10~15(視每個進程實際用量而定) -------------------------- 附錄:快速驗證清單 -------------------------- 完成所有設定後,執行以下快速驗證: 1. 自動更新服務正常運行 systemctl is-active unattended-upgrades 2. 排程設定正確 apt-config dump APT::Periodic 3. 更新來源設定無語法錯誤 apt-config dump | grep -A 20 "Unattended-Upgrade::Origins" 4. 乾跑測試無錯誤 unattended-upgrade --dry-run --verbose 2>&1 | tail -20 5. LNMP 服務全部正常 for svc in nginx php8.3-fpm mariadb; do echo -n "$svc: " systemctl is-active $svc done 6. 監控腳本可正常執行 /usr/local/bin/check-unattended-upgrades.sh && cat /var/log/unattended-upgrades-last-run.txt 7. 確認黑名單套件已鎖定 apt-mark showhold Edited June 3Jun 3 by Jack
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.