docs(admin): rewrite + extend WHP super-admin section from real UI
Build and deploy / deploy (push) Successful in 24s

Verified every page against the live admin panel on whp01 (read-only).
Five existing articles rewritten; one new article added; customer-facing
backups article updated to match server reality.

Article changes
- overview: super admin = the root user only (no UI to add another);
  WHMCS portal route doesn't apply for admin; accurate sidebar map of
  every admin-only section; customer backups don't cover server config
  (multiple locations, not just /etc — full-server backup is the right
  safety net).
- server-settings: walked all six tabs (System / Services / Mail / DNS
  / Network & SSL / Security); clarified that host Apache + PHP-FPM
  serve the WHP control panel, not customer sites; that MySQL runs as
  a container so host MySQL config is client-facing; that custom
  container needs are met by publishing a custom Docker image (linked
  to repo.anhonesthost.net/cloud-hosting-platform/ for examples).
- coraza-waf: real Firing rules / CRS catalog / Activity tabs; global
  WAF mode pill (off/detect/enforce); per-rule + per-host overrides;
  Ask AI link; security.db source-of-truth + SIGHUP reload note.
- site-monitoring: split into the three actual admin pages — AI Monitor
  dashboard, Issues, Ignore Rules — with stat tiles + health-check
  timeline + ignore-rule AND-semantics.
- user-management: account types corrected to full / domain_dns /
  mail_dns (verified in web-files/pages/user-management.php:26);
  system users are protected against deletion (verified is_protected_user
  in web-files/libs/usermgmt.php:697); delegated users are admin-editable
  (not read-only); suspension page is served by haproxy's 503 errorfile
  (verified in haproxy-manager-base/haproxy_tarpit_config.txt:31) so
  troubleshooting points at haproxy reload / container logs.
- new admin/backups: customer-data backups vs full-server backups;
  auto-backups only run with a default target; how to add global vs
  per-customer targets; how to fire on-demand backups for any user;
  troubleshooting around missing targets / failed test / disk pressure.
- how-to/backups (customer): aside about default-target requirement;
  new section explaining what full-server backups cover vs customer
  backups (managed plans + VDS covered by AnHonestHost; elsewhere is
  the server operator's responsibility).

New components / tooling
- admin-signin partial: 'sign in directly at :8443 as root'.
- Head.astro override + medium-zoom: click-to-zoom lightbox on every
  article image; auto-reattaches after Starlight client navigation.
- capture-admin.ts: read-only Playwright capture for admin docs with
  multi-pass redaction (server hostnames, mail server, customer
  domains, customer usernames in table cells, IPs except RFC1918 and
  public resolvers, password/key/token/secret/api input values, plus
  LiteLLM URLs, model names, JWT/sk-prefix API keys, root → admin).
This commit is contained in:
2026-05-18 10:49:43 -07:00
parent 8c965f76d2
commit 119d376029
21 changed files with 760 additions and 203 deletions
+99 -50
View File
@@ -1,95 +1,144 @@
---
title: Users & delegated access
description: Create sub-users, delegate panel access, and manage SFTP/SSH users at the server level.
description: Create WHP users, set account types, change passwords, plus delegated user access and account suspensions.
sidebar:
order: 5
badge:
text: Draft
variant: caution
---
import { Aside } from '@astrojs/starlight/components';
import SuperAdmin from '~/content/partials/super-admin-callout.mdx';
import Draft from '~/content/partials/draft-callout.mdx';
import SignIn from '~/content/partials/signing-in.mdx';
import AdminSignIn from '~/content/partials/admin-signin.mdx';
import Support from '~/content/partials/support-link.mdx';
<SuperAdmin />
<Draft />
Four admin pages collectively control who can sign in and what they can do on the server:
WHP super admin lets you give other people scoped access to the server — your dev team, a contractor, or a junior admin — without sharing your own credentials.
- **User Management** — create / change-password / delete WHP users.
- **User Resources** — set CPU / RAM / disk allowances per user.
- **Delegated Users** — list of contractor / sub-account grants on customer sites.
- **Account Suspensions** — suspended accounts.
## Three kinds of access
## Sign in as super admin
| Type | What they can do | Where they sign in |
| ------------------- | -------------------------------------------------------------------------------- | --------------------------------------- |
| **WHP sub-user** | Sign in to WHP with their own credentials. You control which sections they see. | Same `:8443` URL as you. |
| **Delegated panel access** | A read-only or scoped-write view onto a specific site, for a contractor. | Same WHP, but scoped to that one site. |
| **SFTP / SSH user** | File access (and optionally SSH) without WHP at all. | SFTP client / SSH terminal. |
<AdminSignIn />
## Sign in to WHP
## User Management
<SignIn />
Sidebar → **User Management**.
## Create a WHP sub-user
![WHP User Management page](~/assets/screenshots/whp/admin-user-mgmt.png)
### Create New User
Every user created here is a **customer account**, not a super admin. (Super admin is the `root` user on the server, and there's no UI to add another.)
Fields:
- **Username** — UNIX-safe username; also becomes the SFTP user and home-directory name (`/docker/users/<username>`).
- **Password** — strong password. The user can change it later from the panel.
- **Account Type** — pick the scope of features this customer should see:
- **Full Hosting** — sites, databases, domains, DNS, email. The default for normal customers.
- **Domain/DNS Only** — domains and DNS records only (no sites, databases, or email).
- **Mail/DNS Only** — email plus domains/DNS (no sites or databases).
Click **Create User** to provision the account. The user's home directory and SFTP credentials are set up immediately.
<Aside type="tip">
WHP sub-users are the right model when someone needs to manage parts of the server alongside you. Use **delegated access** instead if they only need one site, or **SFTP/SSH** if they only need files.
Pick the smallest account type that does the job. You can change it later from the **Actions** column in the user list.
</Aside>
1. Open **Users → WHP Users → Add User** in the admin sidebar.
2. Set a username, a strong password, and an email (used for password reset and 2FA).
3. Choose a **role**: pick from the predefined roles (Admin, Site Manager, Read-only, etc.) or build a custom role with specific pages enabled.
4. (Optional) Enable **Require 2FA** so they have to set up an authenticator app on first login.
5. Save. Share the credentials with them out-of-band; don't email passwords.
### Change User Password
## Delegated access for a single site
Pick the user from the dropdown, enter a new password, click **Change Password**. The user is forced to sign in again on next visit; any in-flight panel sessions are still live until you also revoke them via **Active Sessions**.
Use the customer-facing **Delegated Users** page (sidebar → **Delegated Users**, available on every account) when a contractor only needs to work on one site:
### User Accounts table
1. Open **Delegated Users → Add**.
2. Pick the site they should have access to.
3. Set their permission scope: view-only, manage-files, manage-DNS, etc.
4. Send them the panel URL. They sign in with their own credentials and see only that site.
Columns: **Username**, **UID** (UNIX uid), **Account Type**, **Home Directory**, **Actions** (Account-Type dropdown + Delete).
This is the right path for, say, a freelance designer who needs to upload assets but shouldn't see your other sites or your DNS.
To change a user's account type, change the dropdown in the row and the change applies immediately. The **System** badge on a row marks an internal/system user (such as `root`, `whp`, `daemon`, `www-data`, `nobody`, the various `systemd-*` users, etc.).
## SFTP / SSH users
Pure file access without WHP. Created from the admin **Users → SFTP/SSH** page:
1. Open **Users → SFTP/SSH → Add**.
2. Set the username, password (or paste their public SSH key), and which directories they have access to.
3. Pick whether to grant interactive SSH or restrict to SFTP only.
4. Save. They can now connect with their preferred SFTP/SSH client.
**System users are protected.** The panel refuses to delete any user on the protected list — `delete_user` in `web-files/libs/usermgmt.php` checks `is_protected_user($username)` first and returns *"Cannot delete protected system user"* without touching the OS user. Password changes are blocked the same way, with one exception: `root`'s password can be changed (the rest of the protected list cannot).
<Aside type="caution">
Interactive SSH is powerful — anyone with it can run arbitrary commands inside the container or VM. Restrict to SFTP-only unless they specifically need a shell.
Deleting a non-system user removes their home directory and every site, database, and mailbox associated with them. There is no undo. Use **Account Suspensions** instead for temporary disablement.
</Aside>
## Managing existing users
## User Resources
The user list shows last sign-in, role, and 2FA status. Common actions from each user's row:
Sidebar → **User Resources**. Configure CPU and memory allowances per user.
- **Disable** — keeps the user but blocks sign-in.
- **Delete** — removes the user.
- **Force password reset** — invalidates their current password; they receive an email link.
- **Revoke sessions** — kicks them out of any active panel sessions immediately.
![User Resources admin page](~/assets/screenshots/whp/admin-user-resources.png)
When someone leaves your team, **revoke sessions first** (so they're out *now*), then disable or delete the user.
Each row shows current allocation vs. usage:
- **Max CPU** / **CPU Used** — in 0.25-core increments.
- **Max Mem** / **Mem Used** — in 256 MB increments.
- **Disk** / **Used** — total disk allocation and current consumption (with %).
- **Email** — mailbox slot count.
- **Mail MB** — total mail storage cap.
- **Arch.** — archival email slots used / total.
- **Cont.** — currently-running container count.
Use the **Actions** column to edit a user's caps. Changes apply on the next container restart for that user's sites.
<Aside type="note">
Memory-usage tracking isn't available in some Docker environments. The **Active sites** count reflects running containers.
</Aside>
## Delegated Users
Sidebar → **Delegated Users**. Customers can use the Delegated Users page on their own account to grant a contractor scoped access to one of their sites. The admin view shows every active delegation across the server.
From the admin view you can:
- **Audit** — see who has cross-account access at a glance.
- **Edit** — modify scope, permissions, or expiry on any delegation for an independent customer. Useful when a customer asks support to fix a grant they set up incorrectly.
- **Revoke** — remove a delegation outright.
If a customer reports a delegation issue, this page is where you confirm the grant exists, inspect its scope, and adjust it on their behalf.
## Account Suspensions
Sidebar → **Account Suspensions**. The list of suspended customer accounts.
A suspension takes a customer's sites offline without deleting any data — the customer can be reinstated by removing the suspension. Useful for non-payment, terms-of-service issues, or maintenance hold.
The page lists who's suspended, when, by whom, and why. Reinstate from the action button on each row.
### How the suspension page is served
The "site suspended" page is served by **HAProxy** itself, not by a separate backend. When you suspend an account, WHP rewrites the HAProxy config to point that account's frontends at a 503 errorfile (`/usr/local/etc/haproxy/errors/503.http`) and reloads HAProxy.
**If a suspended site is still serving the real content** (or is throwing a network error instead of the suspended page), it almost always means HAProxy didn't pick up the config reload. Check, in order:
1. **HAProxy container is running.** **Server Settings → Services → Docker Container Management** → confirm `Haproxy manager` shows **Running**.
2. **HAProxy reload succeeded.** Either re-trigger from **Server Settings → Network & SSL → Reload Configuration**, or check the HAProxy container logs (`docker logs haproxy-manager`) for a reload error — usually a syntax error in the generated config from the suspension action.
3. **Errorfile is in place.** The 503 page lives at `/usr/local/etc/haproxy/errors/503.http` inside the container.
## Active Sessions
Sidebar → **Active Sessions**. Every active panel session across the server, with last activity time, IP, and a **Terminate** button. Use this when offboarding someone — kick them out of any active sessions *first*, then change their password or delete the user.
## When someone leaves your team
1. **Revoke active sessions** for that user via **Active Sessions**.
2. **Change their password** in **User Management** (locks them out even if they save their cookies).
3. **Downgrade or delete** the user in **User Management**.
4. Audit **Delegated Users** for any cross-account delegations that should also be revoked.
## Troubleshooting
**Sub-user can sign in but the page they expect is missing.** Their role doesn't include that section. Edit the role and tick the right page.
**"Cannot delete protected system user".** Expected — system users (root, daemon, www-data, mail, the `systemd-*` users, etc.) are blocked at the panel level to prevent breaking the host. If you really need to remove a user, confirm it's a customer account first.
**SFTP user can connect but uploads land in the wrong directory.** Check their **Home directory** in the SFTP/SSH user page — it determines what they see as `/`.
**Created user can't sign in.** Confirm the password meets the strength rules. If the user is signing in for the first time, they may be hitting the password-change-on-first-login flow.
**A delegated user can't see DNS records.** Delegated access defaults to file-only. Edit their permissions to include DNS Management.
**Suspended customer's sites are still serving real traffic.** The suspension page is served by HAProxy — see "How the suspension page is served" above. Most often it's an HAProxy reload that didn't happen; check the container logs.
## Related
- [Server settings & services](/whp/admin/server-settings/)
- [Server settings & services](/whp/admin/server-settings/) — including the suspension backend service.
- [AI Monitor, Issues & Ignore Rules](/whp/admin/site-monitoring/)
## Still stuck?