











Alliot 的 PVE 使用的是 no-subscription 软件源,Web 管理页面的订阅状态也顺手做了处理。不过负责返回订阅状态的 /usr/share/perl5/PVE/API2/Subscription.pm 属于 pve-manager 软件包,每次更新都会被覆盖,升级完还得再手动修改一次。一次两次还行,次数多了确实麻烦。
APT 本身支持 Hook,可以在 dpkg 完成一轮软件包安装或升级后执行脚本。这里利用 DPkg::Post-Invoke,让 PVE 更新完成后自动把订阅状态补丁重新打回去。
先创建一个用于恢复补丁的脚本:
1 | vim /usr/share/proxmox-ve/pve-apt-post-hook |
目前机器上使用的脚本如下:
1 | #!/usr/bin/env bash |
加上执行权限:
1 | chmod +x /usr/share/proxmox-ve/pve-apt-post-hook |
脚本会先检查目标文件是否存在,再判断 NotFound 是否还在。已经打过补丁时会直接退出,避免每次安装普通软件包都去重启 PVE 服务;只有 pve-manager 更新将文件恢复后,才会执行替换并重启 pvedaemon 与 pveproxy。
PVE 自带的 APT Hook 配置位于 /etc/apt/apt.conf.d/10pveapthook,在文件末尾加入 DPkg::Post-Invoke:
1 | DPkg::Pre-Install-Pkgs { "/usr/share/proxmox-ve/pve-apt-hook"; }; |
前四行是 PVE 原有的配置,不要覆盖,只需要追加最后一行。
10pveapthook 属于 proxmox-ve 软件包,修改后再升级这个包时,dpkg 有可能询问是否保留本地配置。如果不想修改软件包自带的文件,也可以单独创建 /etc/apt/apt.conf.d/99pve-post-hook,文件中只保留下面这一行,效果相同:
1 | DPkg::Post-Invoke { "/usr/share/proxmox-ve/pve-apt-post-hook"; }; |
两种配置方式选一种即可,不要在两个文件中重复添加。
使用 apt-config dump 可以查看 APT 合并后的实际配置:
1 | apt-config dump | grep -A2 'DPkg::Post-Invoke' |
输出中能看到脚本路径便说明 Hook 已经加载:
1 | DPkg::Post-Invoke ""; |
也可以先手动执行一次脚本测试:
1 | /usr/share/proxmox-ve/pve-apt-post-hook |
如果当前已经打过补丁,会直接返回:
1 | attempting pve-no-subscription patch |
之后再执行 apt upgrade,只要这一轮操作调用了 dpkg,结束时便会运行该脚本。这里需要注意,apt update 只是更新软件包索引,并不会触发 DPkg::Post-Invoke。
APT 会将 Hook 的退出状态作为整次操作结果的一部分,如果脚本以非 0 状态退出,即使前面的软件包已经完成安装,APT 最后仍可能显示执行失败。因此 Hook 脚本最好能够重复执行,并正确处理文件不存在、内容已经修改等情况。
date: 2026-08
当前家里的 PVE 已经升级到 pve-manager 9.2.4,这套 Hook 仍然可以正常使用。PVE 9.2.4 中原始的订阅状态字符串已经是小写的 notfound,不过脚本里的 grep -i 与 sed /gi 都忽略大小写,所以不受影响。
这种方式本质上还是对 PVE 文件做文本替换,如果后续版本修改了文件路径或订阅状态的实现逻辑,脚本也需要跟着调整,并不是配置一次就可以永远不管。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。