Homepage 集成 Proxmox 指南:API Token 配置与集群资源监控 Widget 实战
本指南围绕 Homepage 项目中的 Proxmox 服务 Widget(widget 配置文档)展开,讲解如何创建具备只读审计权限的 API Token、在 proxmox.yaml 与 services.yaml 中完成连接配置,并深入源码剖析 Widget 统计 QEMU VM、LXC 容器数量以及集群 CPU/内存占用率的底层实现。读完本文,你将能够在一页式仪表盘中实时监控整个 Proxmox 集群的负载,并可为单个 VM/LXC 服务叠加运行状态徽标。
Widget 能力概览:一屏掌握集群负载
Proxmox Widget 的核心职责是读取 Proxmox 集群中两类虚拟化资源的统计信息:
- QEMU 虚拟机(VMs)与 LXC 容器(LXC) 的运行数量 / 总数,例如
1 / 2表示共 2 个 VM 中 1 个处于 running 状态; - CPU 与内存使用率,以百分比形式展示,并在负载偏高时通过主题色高亮提示。
该能力由 widget 定义 与 前端组件 协同实现:前者声明 API 端点与代理方式,后者负责过滤、聚合与渲染。
从源码结构可以确认,CPU/内存使用率并非只统计"集群第一个节点",而是对集群中所有处于 online 状态的节点做聚合求和(见下文源码解析)。仅当设置了可选的 node 参数时,统计范围才会收敛到该单一节点。
第一步:创建只读 API Token(PVEAuditor)
Widget 通过 Proxmox REST API(/api2/json)获取数据,因此需要一个具备读取权限的 API Token。官方文档推荐的权限模型是最小化授权:为独立用户、独立 Token 分别授予 PVEAuditor 角色,并开启权限分离(Privilege Separation)。
以下是官方推荐流程(同样完整收录于 配置文档):
- 登录 Proxmox 管理门户,点击顶部 Datacenter;
- 展开 Permissions,点击 Groups;
- 点击 Create 按钮新建用户组,命名为类似
api-ro-users的名称; - 进入 Permissions "文件夹",点击 Add -> Group Permission:
- Path:
/ - Group: 上一步创建的组(如
api-ro-users) - Role:
PVEAuditor - Propagate: 勾选
- Path:
- 展开 Permissions,点击 Users;
- 点击 Add 新建用户:
- User name: 建议使用
api等易识别的名称 - Realm:
Linux PAM standard authentication - Group: 选择第 4 步创建的组
- User name: 建议使用
- 展开 Permissions,点击 API Tokens;
- 点击 Add 创建 Token:
- User: 选择第 6 步创建的用户
- Token ID: 建议按用途命名,例如
homepage - Privilege Separation: 勾选
- 回到 Permissions 菜单;
- 点击 Add -> API Token Permission:
- Path:
/ - API Token: 选择第 8 步创建的 Token
- Role:
PVE Auditor - Propagate: 勾选
- Path:
创建完成后,系统会展示一次 Token 的 Secret(即密码部分),务必及时保存。PVEAuditor 是只读角色,足以支撑 Widget 的所有查询,同时避免了给 Token 授予过大的管理权限。
第二步:配置 Proxmox 连接(proxmox.yaml)
Widget 本身不直接保存 Proxmox 凭据,集群级连接信息统一维护在 proxmox.yaml 中。项目在首次启动时会把 配置模板 复制到运行目录,模板内容如下:
---
# pve:
# url: https://proxmox.host.or.ip:8006
# token: username@pam!Token ID
# secret: secret
取消注释并按实际环境填写:
pve: # 键名必须与你的 Proxmox 节点名一致
url: https://proxmox.host.or.ip:8006
token: username@pam!Token ID
secret: secret
关键要点:
- 键名即节点名:配置文件中每个顶层键(如
pve)必须与实际 Proxmox 节点名匹配,后续服务配置中的proxmoxNode字段会按此键名查找连接信息(见 proxmox 配置文档)。 - 多节点:如需监控多个节点,可在同一文件中追加多个顶层键,服务配置中通过
proxmoxNode指向对应节点。 - 环境变量替换:配置文件在加载时支持环境变量替换,加载逻辑位于 proxmox.js 配置解析:先执行
checkAndCopyConfig("proxmox.yaml")确保文件存在,再读取并调用substituteEnvironmentVars完成变量注入,最后用yaml.load解析为对象。因此像token: ${PROXMOX_TOKEN}这类写法可以直接引用环境变量,避免把密钥明文写死在 YAML 中。
第三步:在 services.yaml 中挂载 Widget
在 services.yaml 的某个服务条目下添加 widget 段,即可把集群统计渲染到仪表盘:
widget:
type: proxmox
url: https://proxmox.host.or.ip:8006
username: api@pam!homepage
password: api_token_secret
node: pve-1 # optional
各字段说明:
| 字段 | 必填 | 说明 |
|---|---|---|
type |
是 | 固定为 proxmox |
url |
是 | Proxmox 管理面板地址,含端口(默认 8006) |
username |
是 | 格式必须为 用户名@pam!Token ID,例如 api@pam!homepage |
password |
是 | 创建 API Token 时生成的 Secret |
node |
否 | 指定后仅统计该节点;省略时聚合整个集群 |
注意:
username不是普通登录用户名,而是 API Token 标识,其格式为用户名@pam!Token ID,与proxmox.yaml中的token字段保持一致。
认证头的底层实现
Widget 的请求经由代理转发,代理层在 credentialed 代理处理器 中为 proxmox 类型构造了标准认证头:
} else if (widget.type === "proxmox") {
headers.Authorization = `PVEAPIToken=${widget.username}=${widget.password}`;
}
也就是说,最终发往 Proxmox 的请求携带的是 PVEAPIToken=api@pam!homepage=<secret> 形式的 Authorization 头——这正是 Proxmox API Token 的规范认证方式。若认证头格式有误(例如漏掉 @pam! 段或 Token ID),API 将直接返回 401,Widget 会显示错误状态而非数据。
允许的数据字段
Widget 渲染时使用如下字段,它们也是 widget 配置文档 中声明的 allowed fields:
["vms", "lxc", "resources.cpu", "resources.mem"]
对应界面上四个统计块:VM 数量、LXC 数量、CPU 使用率、内存使用率。若你的配置需要对返回数据做进一步加工(如过滤模板),这些字段名是理解数据流的关键。
源码解析:集群统计的计算逻辑
Widget 的数据流与统计逻辑可以从三个文件完整还原:
1. API 端点定义
widget.js 声明了请求模板与端点映射:
const widget = {
api: "{url}/api2/json/{endpoint}",
proxyHandler: credentialedProxyHandler,
mappings: {
"cluster/resources": {
endpoint: "cluster/resources",
},
},
};
Widget 通过 {url}/api2/json/cluster/resources 拉取 Proxmox 集群资源视图——该接口会一次性返回所有 VM、LXC、节点、存储等资源条目,前端再按类型与状态过滤。
2. 数据过滤与计数
component.jsx 是核心渲染组件,其处理流程如下:
- 过滤 VM:筛选
type === "qemu"且template === 0的条目(template === 0用于排除模板镜像),若配置了widget.node则进一步要求item.node一致; - 过滤 LXC:筛选
type === "lxc"且template === 0的条目,同样受node参数约束; - 统计运行数:通过
calcRunning对每条记录判断status === "running"并累加; - 聚合节点资源:筛选
type === "node"且status === "online"的节点,累加得到maxMemory、usedMemory、maxCpu、usedCpu。
关键计算片段:
const maxMemory = nodes.reduce((sum, n) => n.maxmem + sum, 0);
const usedMemory = nodes.reduce((sum, n) => n.mem + sum, 0);
const maxCpu = nodes.reduce((sum, n) => n.maxcpu + sum, 0);
const usedCpu = nodes.reduce((sum, n) => n.cpu * n.maxcpu + sum, 0);
CPU 使用率 = (usedCpu / maxCpu) * 100,内存使用率 = (usedMemory / maxMemory) * 100,并调用 t("common.percent", ...) 格式化为百分比。注意 node 被显式设置时,过滤条件会让聚合只作用于该节点,这正是"单节点视图"的实现方式。
3. 测试用例验证
组件测试 用一组模拟数据验证了上述逻辑:
- 1 个 running + 1 个 stopped 的 qemu → 显示
1 / 2; - 1 个 running 的 lxc → 显示
1 / 1; - 节点
cpu: 0.25, maxcpu: 4→ CPU 百分比为 25; - 节点
mem: 50, maxmem: 100→ 内存百分比为 50。
加载期间组件渲染 4 个占位 Block(proxmox.vms、proxmox.lxc、resources.cpu、resources.mem),与最终布局一致,保证首屏无跳动。
进阶:为单个 VM/LXC 附加运行状态徽标
除了集群级 Widget,Homepage 还支持在服务条目上为单个 VM 或 LXC 显示运行状态徽标(running / stopped / paused / offline / not found)。这需要先在 Proxmox 配置文档 中按以下规则配置服务:
| 字段 | 必填 | 说明 |
|---|---|---|
proxmoxNode |
是 | 运行该 VM/LXC 的 Proxmox 节点名,必须与 proxmox.yaml 中配置的键名一致 |
proxmoxVMID |
是 | VM 或 LXC 的 ID |
proxmoxType |
否 | 虚拟机类型,默认 qemu(VM),LXC 需显式设置为 lxc |
QEMU VM 示例:
- HomeAssistant:
icon: home-assistant.png
href: http://homeassistant.local/
description: Home automation
proxmoxNode: pve
proxmoxVMID: 101
# proxmoxType: qemu # 默认值,可省略
LXC 容器示例:
- Nginx:
icon: nginx.png
href: http://nginx.local/
description: Web server
proxmoxNode: pve
proxmoxVMID: 200
proxmoxType: lxc
状态徽标由 proxmox-status 组件 渲染:它通过 /api/proxmox/stats/{proxmoxNode}/{proxmoxVMID}?type={vmType} 轮询状态(proxmoxType 缺省为 qemu),并按状态映射为不同颜色——running 绿色、stopped 橙色、paused 蓝色、not found 橙色;在 dot 样式下则以纯色圆点展示。这与集群 Widget 共同构成"全局负载 + 单机状态"的双层监控视图。
排错建议
- 401 / 认证失败:检查
username是否为用户名@pam!Token ID三段式格式,且password为创建 Token 时返回的 Secret;同时确认proxmox.yaml中token字段同样完整。 - 403 / 权限不足:确认 API Token 及其所属用户、用户组都绑定了
PVEAuditor角色且 Propagate 已勾选,否则部分资源条目会被 Proxmox 拒绝返回。 - 数据不显示 / 持续占位:确认
url使用https://且端口为8006;自签名证书场景下需确保 Homepage 侧能够信任该证书,因为代理以服务端身份直连 Proxmox API。 - 单节点统计不符预期:确认
node参数拼写与proxmox.yaml键名、Proxmox 实际节点名完全一致。
小结
通过"创建 PVEAuditor 只读 Token → 配置 proxmox.yaml 连接 → 在 services.yaml 挂载 Widget"三步,即可在 Homepage 首页实时看到 QEMU/LXC 的运行计数与集群 CPU/内存占用;配合 node 参数与单机状态徽标,还能把监控粒度精确到单个节点乃至单个 VM/LXC。深入阅读 widget.js、component.jsx 与 代理认证实现,可以帮你更从容地排查认证、过滤与聚合相关的各类问题。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00