家裡這台 Proxmox VE(PVE)主機從 2022 年底安裝到現在,一直停在 PVE 7.4。PVE 7 早在 2024 年就停止支援,PVE 8 也在 2026 年 8 月底結束支援,所以這次花了一整個晚上,一路從 PVE 7.4 升級到 PVE 9.2,順便把上面跑的容器系統全部更新到還有支援的版本。這篇記錄整個過程、遇到的問題和解法,給有同樣環境的人參考。
主機環境
| 項目 | 內容 |
|---|---|
| 硬體 | Intel Celeron N5105(Jasper Lake)迷你主機、16GB 記憶體、512GB SSD |
| 網卡 | 兩張 Realtek RTL8111H 有線網卡、一張 Intel AC 3165 Wi-Fi(沒有使用) |
| 開機方式 | UEFI + GRUB |
| VM | Home Assistant OS、一台路由用途的 Debian VM |
| LXC 容器 | Jellyfin、反向代理與各種 Docker 服務、DMZ 服務(Nextcloud 等)、WordPress、Tailscale |
整體流程與結果
| 階段 | 內容 | 結果 |
|---|---|---|
| 0. 升級前準備 | 修正 GRUB、清掉測試機、補齊備份排程 | ✅ |
| 0.5 容器系統升級 | 兩台 Ubuntu 18.04、一台 Debian 11 升到有支援的版本 | ✅(過程中踩了不少坑) |
| 1. PVE 7.4 → 8.4 | Debian 11 → 12、核心 5.15 → 6.8 | ✅ 重開機約 2 分鐘 |
| 2. PVE 8.4 → 9.2 | Debian 12 → 13 | ⚠️ 新核心 7.0 開不起來,暫時鎖定在 6.8 |
階段 0:升級前準備
修正 GRUB:UEFI 開機卻裝著 BIOS 版的 GRUB
官方的升級檢查工具 pve7to8 提醒:主機是 UEFI 開機,但只裝了 grub-pc(BIOS 版),沒有 grub-efi-amd64。結果就是每次 GRUB 更新都只更新到用不到的 BIOS 版,真正用來開機的 EFI 開機檔從 2022 年安裝後就沒動過。升級到新版 Debian 時,新舊版本混用很可能直接開不了機。
修正前先備份 EFI 分割區和 /boot/grub(兩個都要,只還原其中一個會因為新舊模組不一致而開不了機),再改裝 UEFI 版,並設定同時更新備援開機檔:
tar czf /root/esp-backup.tgz -C /boot/efi .
tar czf /root/boot-grub-backup.tgz -C /boot grub
echo "grub-efi-amd64 grub2/force_efi_extra_removable boolean true" | debconf-set-selections
apt install grub-efi-amd64
過程中遇到兩個問題:
- Debian 11 的安全更新伺服器回應 404:Debian 11 的 LTS 已經結束,檔案被搬到
archive.debian.org。從封存站下載同版本的套件,比對 apt 索引裡的 SHA256 一致後,放進/var/cache/apt/archives/再用apt-get install --no-download安裝。 - dpkg 卡住:之前移除 Netdata 時刪掉了
netdata系統群組,但/var/lib/dpkg/statoverride裡還留著指向這個群組的紀錄,dpkg 讀到不存在的群組就直接中止。把那幾行刪掉之後就恢復正常。
其他準備
- 刪除不再使用的測試 VM 和容器(共 5 台),主機磁碟用量從 254G 降到 197G
- 替從來沒有備份的容器補上每週備份排程
- 暫時停用 crontab 裡每月自動重開機的排程,避免升級到一半被重開
- 備份暫存目錄改到本機(
/etc/vzdump.conf加上tmpdir: /var/tmp),suspend 模式備份時容器暫停的時間從幾分鐘縮短到幾秒
階段 0.5:容器系統升級
PVE 9 不再支援 cgroup v1,也不支援 Ubuntu 20.04 以前、Debian 11 以前的容器。所以 PVE 升級前,要先把兩台 Ubuntu 18.04 容器升到 22.04。Ubuntu 不能跳版,要 18.04 → 20.04 → 22.04 分兩次升級。
坑 1:Portainer 建立的 Docker 容器在新版 Docker 起不來
系統升級時 Docker 也跟著從 20.10 升到 24 以上,部分容器啟動時出現:
invalid CapDrop: capability not supported by your kernel or not available in the current environment: "CAP_MAC_ADMIN"
原因是透過 Portainer 建立的容器,會把「要移除的權限」逐一寫進設定,其中包含 LXC 容器裡本來就沒有的 MAC_ADMIN。新版 Docker 會檢查這份清單,直接拒絕啟動。解法是用相同參數重新建立容器,不帶這份清單。
重點:不要直接用 docker-compose 檔重建。我的反向代理(Nginx Proxy Manager)實際使用的連接埠跟 compose 檔裡寫的不一樣,資料目錄的變數也是空的。如果照 compose 檔重建,反向代理會整個連不上。比較保險的做法是升級前先把每個容器的 docker inspect 存下來,再根據實際的設定產生重建指令。
坑 2:升到 22.04 後,所有 Docker 容器都起不來
open sysctl net.ipv4.ip_unprivileged_port_start file: reopen fd 8: permission denied
這是 containerd/runc 為了修補安全漏洞(CVE-2025-52881)改了處理方式,在 PVE 的 LXC + AppArmor 環境下會被擋住。PVE 8 不會收到修正(PVE 9.1.1 之後的 LXC 才修好),所以先把 Docker 降回確認能用的版本並鎖定:
V=5:28.1.1-1~ubuntu.22.04~jammy
apt-get install -y --allow-downgrades \
docker-ce=$V docker-ce-cli=$V docker-ce-rootless-extras=$V containerd.io=1.7.27-1
apt-mark hold docker-ce docker-ce-cli docker-ce-rootless-extras containerd.io
坑 3:鎖定 Docker 後,do-release-upgrade 拒絕升級
為了讓容器在系統升級期間繼續運作,我先把 Docker 鎖定在原版本,結果 do-release-upgrade 回應「Please install all available updates for your release before upgrading」,因為被鎖定的 Docker 有新版本沒裝。解法是暫時把 Docker 的套件來源註解掉,讓系統認為沒有待更新的套件,版本升級完再改回新版本的來源。
坑 4:Mosquitto 1.x → 2.0 預設不再接受外部連線
Ubuntu 22.04 的 Mosquitto 是 2.0 版,預設只接受本機連線、也不允許匿名登入。如果原本的設定檔都用預設值,升級後所有 MQTT 裝置都會斷線。我在升級前就先加上這份設定,並在舊版上測試過可以運作:
# /etc/mosquitto/conf.d/10-listener.conf
listener 1883
allow_anonymous true
坑 5:nginx 還指向舊版 PHP
升級後 PHP 從 7.2 變成 8.1,但 nginx 設定的 fastcgi_pass 還寫著 php7.2-fpm.sock,所有 PHP 頁面都回應 502。改成指向通用的路徑,以後 PHP 再升級也不用改:
fastcgi_pass unix:/run/php/php-fpm.sock;
坑 6:TurnKey 容器升級 Debian 12 失敗,網站中斷 15 分鐘
WordPress 跑在 TurnKey Linux 的容器裡(Debian 11)。第一次升級時,容器裡的簽章金鑰太舊,apt 無法驗證 Debian 12 的主要來源,卻還能用 Debian 12 的安全更新來源,結果只裝了一半的新套件。接著的升級和自動清理把 Apache、MariaDB、PHP、Perl 都移除了,網站直接 502。
用升級前的備份還原(pct restore)之後,第二次改成每一步都先檢查:
- 先從 Debian 官方透過 HTTPS 下載 Debian 12 的
debian-archive-keyring,比對 SHA256 後安裝 apt update只要出現任何E:或W:就停止,並把來源改回去- 用
apt-get -s full-upgrade模擬,確認 Apache、MariaDB、PHP、Perl 都是「升級」而不是「移除」 - 確認網站正常之後,才執行
autoremove
第二次升級成功,但 PHP 從 7.4 升到 8.2 之後,佈景主題出現:
Array and string offset access syntax with curly braces is no longer supported
用 php -l 掃過所有佈景主題和外掛的 PHP 檔,只有 2 個檔案、4 個地方用了舊寫法 $str{$i},改成 $str[$i] 就恢復了。另外 Debian 的國際下載站非常慢,改成台灣鏡像站 ftp.tw.debian.org 後快了很多。
階段 1:PVE 7.4 → 8.4
新核心有可能讓網卡名稱改變,主機一旦失去網路,就只能接螢幕鍵盤處理。所以升級前先用 systemd 的 .link 檔,以 MAC 位址把網卡名稱固定住(名稱跟現在一樣,所以不會影響目前的網路):
# /etc/systemd/network/10-enp3s0.link
[Match]
MACAddress=xx:xx:xx:xx:xx:xx
Type=ether
[Link]
Name=enp3s0
建立後執行 update-initramfs -u -k all,讓設定在開機最早期就生效。這個做法同時也省掉了 8 → 9 時要用的 pve-network-interface-pinning。
接著照官方流程:pve7to8 --full 確認 0 個失敗 → 套件來源改成 bookworm → apt update 確認沒有錯誤 → 模擬確認 proxmox-ve、pve-manager 等核心套件不會被移除 → apt dist-upgrade。升級期間 VM 和容器都照常運作,重開機約 2 分鐘就回來了,網卡名稱和 IP 都沒變。
階段 2:PVE 8.4 → 9.2
流程跟 7 → 8 很像,差別是 PVE 9 的套件來源改用新的 deb822 格式:
# /etc/apt/sources.list.d/proxmox.sources
Types: deb
URIs: http://download.proxmox.com/debian/pve
Suites: trixie
Components: pve-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
升級本身很順利,但後面遇到三個問題:
新核心 7.0 開不起來
重開機後,畫面停在「Loading initial ramdisk」,閃一下就全黑,鍵盤沒有反應,接著主機自己重開,又卡在同一個地方。到主機前面從 GRUB 的 Advanced options 改用舊核心 6.8 開機後一切正常,再把預設核心鎖定在 6.8:
proxmox-boot-tool kernel pin 6.8.12-43-pve
proxmox-boot-tool refresh
從開機紀錄看,顯示卡驅動 i915 和有線網卡驅動都有正常載入,紀錄停在 Wi-Fi 驅動(iwlwifi)載入之前。這張 Wi-Fi 卡(Intel AC 3165)完全沒有在用,所以下一步打算把 Wi-Fi 和藍牙驅動加進黑名單,再測一次 7.0。
chrony 啟動失敗
升級過程中出現 Could not send notification to $NOTIFY_SOCKET,是新版 chrony 跟還在執行的舊版 systemd 溝通不上。重開機換成新版 systemd 後就自動恢復了,不需要處理。
主機上的 Portainer agent 無法存取 Docker
Debian 13 換成 AppArmor 4 之後,Docker 預設的 AppArmor 規則會擋住容器存取 /var/run/docker.sock,agent 一直重啟。重建時加上 --security-opt apparmor=unconfined 就好了。這個 agent 本來就有完整控制 Docker 的權限,拿掉 AppArmor 限制不會降低實際的安全性。
值得一提的是,LXC 容器裡的 Docker 在 PVE 9 上都正常,兩台容器共 21 個 Docker 容器全部正常運作。
目前狀態與待辦
- ✅ PVE 9.2.21,所有 VM 和容器正常,Jellyfin 硬體轉碼正常
- ⚠️ 核心暫時鎖定在 6.8,要找出 7.0 卡住的原因(6.8 之後不會再有安全更新)
- ⏳ PVE 9 的 LXC 已經修正 runc 的問題,之後要解除 Docker 的版本鎖定,恢復正常更新
心得
- 升級前一定要有備份,而且要確認能還原。WordPress 那次失敗,靠的就是 20 分鐘前做的備份,幾分鐘就救回來。
- 升級腳本要在第一個錯誤就停下來。
apt update有錯還繼續往下跑,是讓網站掛掉的主因。先apt update檢查、再apt-get -s模擬,確認不會移除關鍵套件才正式執行。 - 網卡名稱、GRUB 這些「開不了機就沒救」的東西,要提早處理。固定網卡名稱和修正 GRUB 都是在升級前做好,兩次 PVE 升級的網路都沒出問題。
- LXC 裡跑 Docker 要特別小心。Docker、containerd、runc、AppArmor、LXC 任何一個升版都可能讓容器起不來,升級前先存好每個容器的
docker inspect。 - 升級新核心時,要能接觸到主機。這次 7.0 開不起來,如果人不在主機旁邊,服務就會一直停著,直到有人到現場改用舊核心開機。
在天文化有限公司





