惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
量子位
博客园 - 聂微东
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
V
Visual Studio Blog
雷峰网
雷峰网
T
Tailwind CSS Blog
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
有赞技术团队
有赞技术团队
博客园 - 叶小钗
Microsoft Azure Blog
Microsoft Azure Blog
T
The Blog of Author Tim Ferriss
U
Unit 42
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
小众软件
小众软件
阮一峰的网络日志
阮一峰的网络日志
Y
Y Combinator Blog

Alliot's blog

Codex第三方API使用生图接口 域名切换到blog.alliot.tech Docker 代理配置机制与作用域 Docker 代理配置机制与作用域 2025年底的安卓搞机备忘录 2025年底的安卓搞机备忘录 ArgoCD部署应用出现metadata.annotations过大问题 ArgoCD部署应用出现metadata.annotations过大问题 APC UPS更换电池校准容量 APC UPS更换电池校准容量 M1 Mac安装低版本Node.js M1 Mac安装低版本Node.js Ansible使用Bitwarden存储Vault密码 Ansible使用Bitwarden存储Vault密码 Cloudflare Tunnel前置代理支持 Cloudflare Tunnel前置代理支持 CDN场景下配置Vaultwarden启用fail2ban CDN场景下配置Vaultwarden启用fail2ban 中银香港丝滑开户总结 中银香港丝滑开户总结 从指定路径更新雷池WAF证书 从指定路径更新雷池WAF证书 AWS ECS使用EBS作为Volume AWS ECS使用EBS作为Volume 浅浅的调教一下国产智障电视 浅浅的调教一下国产智障电视 Nginx proxy_pass到AWS ALB的504问题 Nginx proxy_pass到AWS ALB的504问题 OpenV**手动指定路由规则 OpenV**手动指定路由规则
利用 APT Hook 在 PVE 更新后自动执行脚本
Alliot · 2024-03-25 · via Alliot's blog

  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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env bash
set -e

FIND="NotFound"
ACTIVE="Active"
FILE=/usr/share/perl5/PVE/API2/Subscription.pm
ARG="$1"

apply_razor1911_crack() {
sed -i "s/$FIND/$ACTIVE/gi" "$FILE"
echo "restarting services..."
systemctl restart pvedaemon
systemctl restart pveproxy
echo "success: subscription updated from: $FIND to $ACTIVE"
}

echo "attempting pve-no-subscription patch"

if ! [ -n "$ARG" ]; then
if ! test -f "$FILE"; then
echo "$FILE does not exist! are you sure this is pve?"
exit 0
fi

if ! grep -i "$FIND" "$FILE"; then
echo "pve appears to be patched."
exit 0
fi
fi

echo "attempting replacement in $FILE..."
apply_razor1911_crack

加上执行权限:

1
chmod +x /usr/share/proxmox-ve/pve-apt-post-hook

  脚本会先检查目标文件是否存在,再判断 NotFound 是否还在。已经打过补丁时会直接退出,避免每次安装普通软件包都去重启 PVE 服务;只有 pve-manager 更新将文件恢复后,才会执行替换并重启 pvedaemonpveproxy

注册 APT Hook

PVE 自带的 APT Hook 配置位于 /etc/apt/apt.conf.d/10pveapthook,在文件末尾加入 DPkg::Post-Invoke

1
2
3
4
5
DPkg::Pre-Install-Pkgs { "/usr/share/proxmox-ve/pve-apt-hook"; };
DPkg::Tools::Options::/usr/share/proxmox-ve/pve-apt-hook "";
DPkg::Tools::Options::/usr/share/proxmox-ve/pve-apt-hook::Version "2";
DPkg::Tools::Options::/usr/share/proxmox-ve/pve-apt-hook::InfoFD "20";
DPkg::Post-Invoke { "/usr/share/proxmox-ve/pve-apt-post-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
2
DPkg::Post-Invoke "";
DPkg::Post-Invoke:: "/usr/share/proxmox-ve/pve-apt-post-hook";

也可以先手动执行一次脚本测试:

1
/usr/share/proxmox-ve/pve-apt-post-hook

如果当前已经打过补丁,会直接返回:

1
2
attempting pve-no-subscription patch
pve appears to be patched.

之后再执行 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 -ised /gi 都忽略大小写,所以不受影响。

  这种方式本质上还是对 PVE 文件做文本替换,如果后续版本修改了文件路径或订阅状态的实现逻辑,脚本也需要跟着调整,并不是配置一次就可以永远不管。