From 44c3727ad3e099817c8f903577dfcabc584a243f Mon Sep 17 00:00:00 2001 From: bluebluesoda <300733005+bluebluesoda@users.noreply.github.com> Date: Fri, 11 Sep 2026 06:41:06 +0000 Subject: [PATCH] docs: document multi-container user groups - add a "User groups" section: name-derived grouping, name validation, the shared panel password and accent color, and the container switcher - describe the switcher labels and the per-container sticky-notes tag - note the accent color is group-wide in the color section - list multi-container users in both READMEs Co-authored-by: CommandCodeBot --- README.en.md | 3 +- README.md | 3 +- docs/README.md | 2 +- docs/architecture.md | 75 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 74 insertions(+), 9 deletions(-) diff --git a/README.en.md b/README.en.md index f1b9926..71154fd 100644 --- a/README.en.md +++ b/README.en.md @@ -10,7 +10,8 @@ A lightweight Incus container hosting panel for small VPS instances and low-memo - Admin panel: users, quotas, domains, IPv6 pool, SSH public keys, and audit logs; supports logging in as a user - User panel: power control, self-service Debian 13/AlmaLinux 9/openSUSE Leap 16/Arch Linux reinstall, domain and SSH key management, encrypted sticky notes (exportable), and a time machine (checkpoint snapshots; rolling back discards the later checkpoints) -- The admin can assign each user a dedicated accent color (click the username in the user list): that user's "log in" button and user-panel background use it, so impersonating operators can tell users apart at a glance +- Multi-container users: group accounts as `name` + `name-1`, `name-2`, … to share one login and password across several containers, with a switcher and per-group accent color +- The admin can assign each user a dedicated accent color (click the username in the user list): that user's "log in" button and user-panel background use it, so impersonating operators can tell users apart at a glance. A user group shares one color - CPU, memory, and disk oversubscription; quota changes apply live without a container restart - Strict container network isolation; prefix mode assigns each container a dedicated `/112` IPv6 block that it can subdivide - Traffic is counted in both directions; over-quota containers are rate-limited to 1 Mbps both ways diff --git a/README.md b/README.md index 3536164..4b02e8a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,8 @@ - 管理员面板:用户、配额、域名、IPv6 地址池、SSH 公钥与审计日志;支持"以用户身份登录"接入用户面板 - 用户面板:电源控制、自助重装 Debian 13/AlmaLinux 9/openSUSE Leap 16/Arch Linux、域名与 SSH 密钥管理、加密便签(可导出)、时光机(检查点快照,回滚即丢弃此后的检查点) -- 管理员可为每个用户分配专属颜色(在用户列表中点击用户名):该用户的「登录面板」按钮采用此颜色,管理员代客登录时其用户面板也以此颜色渲染,方便区分不同用户;用户自行登录始终显示默认主题 +- 多容器用户组:相邻账号按 `用户名` + `用户名-1`、`用户名-2`… 归为一组,共用同一登录与密码管理多个容器,支持容器切换与组内统一配色 +- 管理员可为每个用户分配专属颜色(在用户列表中点击用户名):该用户的「登录面板」按钮采用此颜色,管理员代客登录时其用户面板也以此颜色渲染,方便区分不同用户;用户自行登录始终显示默认主题;同一用户组共用一个颜色 - CPU、内存、磁盘支持超售;配额修改实时生效,无需重启容器 - 容器网络严格隔离;IPv6 前缀模式下每个容器获得独立 `/112`,可继续划分子网 - 流量按上下行合计,超额后双向限速至 1 Mbps diff --git a/docs/README.md b/docs/README.md index 529e01c..64bd323 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,7 @@ Technical documentation for vpsmgr. All docs are in English. | Doc | What it covers | |---|---| -| [architecture.md](architecture.md) | System design: components, storage, network, security, traffic, image, install/uninstall lifecycle | +| [architecture.md](architecture.md) | System design: components, storage, network, security, traffic, users and user groups, image, install/uninstall lifecycle | | [configuration.md](configuration.md) | Full reference for `/etc/vpsmgr/config.yaml` | | [ipv6.md](ipv6.md) | IPv6 pass-through design: deterministic addresses, prefix support, routing, installer flow | | [ipv6-ndp-responder.md](ipv6-ndp-responder.md) | Why prefix mode replaced ndppd with an in-tree NDP responder, design hardening, and what to test at scale | diff --git a/docs/architecture.md b/docs/architecture.md index 4a2f2bc..e22a843 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,9 +1,9 @@ # Architecture -vpsmgr is a lightweight LXC hosting panel: one Debian 13 container per user, -managed from a web panel and a CLI. Everything ships as a single Go binary -(`vps` = CLI + embedded web panel); Incus, nftables and Traefik provide the -plumbing. +vpsmgr is a lightweight LXC hosting panel: one Debian 13 container per user +account, managed from a web panel and a CLI. Everything ships as a single Go +binary (`vps` = CLI + embedded web panel); Incus, nftables and Traefik provide +the plumbing. ## Design goals @@ -193,7 +193,7 @@ The panel daemon runs as the dedicated unprivileged `vps` system user `/var/log/vpsmgr-init.log` there. Shebangs are honored; a hanging script cannot block the reinstall because it is backgrounded. Delivery failure only warns — the reinstall still succeeds. -- **Per-user accent color**: each user can carry an accent color +- **Accent color (group-wide)**: each user can carry an accent color (`users.color`, a hex string from the admin panel's **fixed 10-color palette** in `admin` — black/white/gray are excluded; the palette is the allowlist, so a free-form hex can never be stored). The entry point is deliberately low-key: @@ -208,7 +208,9 @@ The panel daemon runs as the dedicated unprivileged `vps` system user user-panel tint renders **only for operator impersonation sessions**, so a user logging in with their own password always sees the default theme. Only the admin can set it; users cannot. Setting/clearing is audited as - `color.update` under `000+`. + `color.update` under `000+`. The color is **shared across a user group** + (see “User groups” below): writing it updates every member, and a new member + inherits the group's existing color. - **Snapshots ("时光机" / time machine)**: each user can keep up to `snapshots.limit` disk-only checkpoints (named `snap-...`) of their container and create / delete / restore them from the panel. The panel calls @@ -237,6 +239,67 @@ The panel daemon runs as the dedicated unprivileged `vps` system user container deletes every checkpoint, which the reinstall dialog warns about with the exact count. +### User groups (multi-container users) + +One login can manage several containers by grouping panel accounts under a +naming convention. There is **no group table** — the group is derived from the +account name at read time, so adding or removing a member needs no migration: + +- An account `parent` and every account named `parent-` are one + **user group**. `alice` is the parent (labelled machine **A**); `alice-1`, + `alice-09` are its children (labelled by their digit suffix, leading zeros + preserved). +- The parent part must start and end with a letter. Nesting is rejected: + `alice-1-2` is not a child, and a `-` suffix whose prefix is not a + valid parent (`alice1-2`, `a-1`) makes the name invalid. Names stay ≤ 31 + characters. `mgr.ParseUserGroup` / `UserGroupName` are the single definitions, + covered by `group_test.go`. +- **Only the admin panel can create a child** (`ValidateAddName(..., true)`). + The CLI / `vps add` path passes `AllowChild=false` and rejects child names. + The admin create form mirrors the rule client-side and previews the group and + its size before submitting. + +State that is **shared across a group**: + +- **Panel password.** A brand-new group gets a fresh 20-char password; adding a + member to an existing group reuses the group's bcrypt hash, and the one-time + credential block prints “same as the existing user-group password” instead of + a password. This holds on the CLI too: `vps add` of a parent name whose group + already has members inherits the group hash, and its output says the password + was inherited rather than printing one. Changing it (`ChangePanelPassword`, + the path behind both the panel's own change flow and the admin reset) hashes + once and rewrites **every** member in a single transaction, dropping each + member's other sessions — the change flow keeps the caller's current token, an + admin reset passes an empty token and drops all + (`db.UpdateUsersPasswordAndDeleteSessions`). The **container root password is + not shared**: every container gets its own, and for an inherited group member + that value is generated but deliberately not displayed, so the root password + must be reset from the panel. +- **Accent color.** `SetGroupColor` writes one color to all members + (`db.UpdateUsersColor`, one transaction), and `inheritGroupColorLocked` gives a + newly added member the first color found in its group. +- **A container switcher.** With more than one member the user panel shows a + `