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 <noreply@commandcode.ai>
This commit is contained in:
1 parent
770b763d2a
commit
44c3727ad3
4 files changed
+74
-9
No files matched your search
+2
-1
@@ -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
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
|
||||
- 管理员面板:用户、配额、域名、IPv6 地址池、SSH 公钥与审计日志;支持"以用户身份登录"接入用户面板
|
||||
- 用户面板:电源控制、自助重装 Debian 13/AlmaLinux 9/openSUSE Leap 16/Arch Linux、域名与 SSH 密钥管理、加密便签(可导出)、时光机(检查点快照,回滚即丢弃此后的检查点)
|
||||
- 管理员可为每个用户分配专属颜色(在用户列表中点击用户名):该用户的「登录面板」按钮采用此颜色,管理员代客登录时其用户面板也以此颜色渲染,方便区分不同用户;用户自行登录始终显示默认主题
|
||||
- 多容器用户组:相邻账号按 `用户名` + `用户名-1`、`用户名-2`… 归为一组,共用同一登录与密码管理多个容器,支持容器切换与组内统一配色
|
||||
- 管理员可为每个用户分配专属颜色(在用户列表中点击用户名):该用户的「登录面板」按钮采用此颜色,管理员代客登录时其用户面板也以此颜色渲染,方便区分不同用户;用户自行登录始终显示默认主题;同一用户组共用一个颜色
|
||||
- CPU、内存、磁盘支持超售;配额修改实时生效,无需重启容器
|
||||
- 容器网络严格隔离;IPv6 前缀模式下每个容器获得独立 `/112`,可继续划分子网
|
||||
- 流量按上下行合计,超额后双向限速至 1 Mbps
|
||||
|
||||
+1
-1
@@ -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 |
|
||||
|
||||
+69
-6
@@ -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+<user>`.
|
||||
`color.update` under `000+<user>`. 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-<UTC>...`) 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-<digits>` 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 `-<digits>` 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
|
||||
`<select>` in the header. Each option is labelled
|
||||
`<label>-<cpu>c<mem>g<disk>g` — the machine label (`A` for the base account,
|
||||
else the numeric suffix) plus the three quota values, e.g. `2-4c8g40g`;
|
||||
the group-name prefix is dropped because every option shares it. The list is
|
||||
ordered base-first then by numeric suffix (so `A, 1, 2, … 10`, not lexical).
|
||||
`POST /switch-user` accepts only a name in the caller's own group, mints a
|
||||
session for the target, drops the old one and audits `session.switch.<target>`.
|
||||
A warning banner (repeated inside the reinstall and snapshot dialogs) names the
|
||||
current machine label so a destructive action is not aimed at the wrong
|
||||
sibling, and the sticky-notes card title carries the same label (`Machine 2`)
|
||||
when the group has more than one container — notes themselves stay
|
||||
per-container, so each machine keeps its own encrypted set.
|
||||
|
||||
All of it is process-safe: the add path and the password/color changes hold the
|
||||
manager's operation mutex, and the multi-row writes are single transactions.
|
||||
Deleting one member never touches its siblings, and because the group is name-
|
||||
derived it survives the parent's deletion: a leftover child keeps the group
|
||||
name (and its shared credentials) with no `A` machine, and re-adding the parent
|
||||
name later simply rejoins the same group and inherits its password — the
|
||||
convention working as designed, not a fresh tenant.
|
||||
|
||||
## Storage
|
||||
|
||||
Three backends, all selected by setting `VPSMGR_STORAGE` when running
|
||||
|
||||
Reference in new issue
Block a user