diff --git a/astro.config.mjs b/astro.config.mjs
index 9942161..fe7fbde 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -53,6 +53,11 @@ export default defineConfig({
label: 'Add-ons',
items: [{ autogenerate: { directory: 'whp/add-ons' } }],
},
+ {
+ label: 'Admin',
+ badge: { text: 'Draft', variant: 'caution' },
+ items: [{ autogenerate: { directory: 'whp/admin' } }],
+ },
],
},
// Future products only appear once they have content.
diff --git a/src/content/docs/whp/admin/coraza-waf.mdx b/src/content/docs/whp/admin/coraza-waf.mdx
new file mode 100644
index 0000000..85a0016
--- /dev/null
+++ b/src/content/docs/whp/admin/coraza-waf.mdx
@@ -0,0 +1,96 @@
+---
+title: Coraza WAF rules
+description: Tune the Coraza web-application firewall rules running in front of your sites — toggle modes, mute false positives, audit blocks.
+sidebar:
+ order: 3
+ 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 Support from '~/content/partials/support-link.mdx';
+
+
+
+
+
+[Coraza](https://coraza.io/) is an open-source web-application firewall (WAF). It runs as a sidecar in front of your sites and inspects incoming requests against rule families like OWASP Core Rule Set v4 (CRS). The admin WHP gives you a UI to manage the rules and audit what's been blocked.
+
+## Three operating modes
+
+The WAF runs in one of three modes, set per-site or server-wide:
+
+- **Off.** No inspection. Requests pass through untouched.
+- **Detect-only.** Inspect every request and log matches, but pass them through. Use this when rolling out the WAF for the first time or when validating a rule change.
+- **Enforce.** Inspect every request and **block** any that match an enforcing rule. This is the production setting once you've validated detect-only.
+
+The WAF is fail-open: if the Coraza sidecar itself is unhealthy, traffic still flows.
+
+## Sign in to WHP
+
+
+
+## Where it lives
+
+Sidebar → **Security → Coraza Rules**. The page lists rule families (CRS 901, 911, 913, 920–922, 930–934, 941–944, 949, 950–956, 959, 980) and per-rule controls.
+
+## Common tasks
+
+### Roll a new site onto the WAF
+
+
+
+1. Open **Security → Coraza Rules**.
+2. Find the site and set mode to **Detect-only**.
+3. Drive normal traffic for at least 24 hours.
+4. Open the **Audit log** and filter to that site. Confirm no legitimate request is matching an enforcing rule.
+5. Switch the site to **Enforce**.
+
+### Mute a noisy rule
+
+When a rule is firing on legitimate traffic for one site:
+
+1. Click the audit-log row to see the rule_id and the matched request.
+2. From the **Coraza Rules** page, find the rule by ID.
+3. Pick **Ignore for this site** (per-site mute) or **Ignore globally** (server-wide mute).
+4. Save. The rule stops firing on the next request.
+
+Per-site is almost always the right scope. Use global mute sparingly — it weakens the WAF for every site.
+
+### Audit a block
+
+Customer reports a request was wrongly blocked? The branded 403 page that visitors see includes an **X-Request-Reference** UUID. Cross-reference it:
+
+1. In the **Audit log**, search for the UUID.
+2. The audit row shows the matched rule_id, the source IP, the URL, and the offending parameter.
+3. Decide whether to mute the rule (see above) or leave it — many "false positives" turn out to be real attempts.
+
+## Things to know
+
+- **Rule changes apply on the next request.** No service restart needed for tuning.
+- **Adding or removing rules requires a full reload** of `coraza-spoa`, not just a SIGHUP. The panel handles this for you; if you edit rule files by hand, `docker restart coraza-spoa`.
+- **Real source IPs are in the audit log.** Even though haproxy fronts the WAF, we propagate the real client IP through the SPOE messages.
+- **`SecRuleRemoveById` plus a new rule needs a full restart**, not just a config reload. Again, the panel handles this when you change rules through the UI.
+
+## Troubleshooting
+
+**A rule shows enabled but doesn't fire.** Check that the site is in **Detect-only** or **Enforce** mode. A site in **Off** mode bypasses every rule, including enabled ones.
+
+**The audit log is empty.** Confirm `coraza-spoa` is healthy on the **Services** page. If it's restarting in a loop, check the container logs — most often a malformed rule file or a missing include.
+
+**Edits revert on restart.** Make sure you're editing through the panel; manual edits to files outside the panel-managed path are overwritten by config regeneration.
+
+## Related
+
+- [Server settings & services](/whp/admin/server-settings/)
+- [Site Monitoring rules](/whp/admin/site-monitoring/)
+
+## Still stuck?
+
+
diff --git a/src/content/docs/whp/admin/overview.mdx b/src/content/docs/whp/admin/overview.mdx
new file mode 100644
index 0000000..652f847
--- /dev/null
+++ b/src/content/docs/whp/admin/overview.mdx
@@ -0,0 +1,44 @@
+---
+title: Admin overview
+description: What WHP super admin unlocks — server-wide controls for services, security rules, monitoring, and users.
+sidebar:
+ order: 1
+ badge:
+ text: Draft
+ variant: caution
+---
+
+import SuperAdmin from '~/content/partials/super-admin-callout.mdx';
+import Draft from '~/content/partials/draft-callout.mdx';
+import Support from '~/content/partials/support-link.mdx';
+
+
+
+
+
+## What super admin unlocks
+
+The same WHP panel you'd use on a customer account scales up: customers with **super admin** access also see server-wide pages for managing services, firewall rules, monitoring policy, and users. The customer-facing sections (Sites, Domains, Email, etc.) work the same way; the admin sections sit alongside them, gated to admins.
+
+Today, super admin is most commonly handed to customers running a [Virtual Dedicated Server](https://anhonesthost.com/vds) — they get full server control as part of the plan.
+
+## What's in this section
+
+- **[Server settings & services](/whp/admin/server-settings/)** — restart services, manage modules and runtimes, edit server-wide configuration.
+- **[Coraza WAF rules](/whp/admin/coraza-waf/)** — view, tune, and tune out web-application-firewall rules across all your sites.
+- **[Site Monitoring rules](/whp/admin/site-monitoring/)** — manage the rules that drive Site Monitoring alerts.
+- **[Users & delegated access](/whp/admin/user-management/)** — create sub-users, delegate panel access, manage SFTP/SSH users.
+
+## Things to know before you change server-wide settings
+
+- **One change can affect every site on the server.** Where customer-side pages scope changes to one site, admin pages typically scope to the whole server.
+- **Service restarts are visible to live traffic.** Restart Apache or PHP-FPM during a quiet window when possible.
+- **Backups still apply.** Server-level changes don't bypass the [backups](/whp/how-to/backups/) you have configured; you can roll back the data side, but service-config changes you made by hand aren't snapshotted unless you back up `/etc` somewhere on your own.
+
+## Related
+
+- [What is containerized hosting?](/whp/getting-started/what-is-containerized-hosting/) — the differences between container plans and full server access.
+
+## Still stuck?
+
+
diff --git a/src/content/docs/whp/admin/server-settings.mdx b/src/content/docs/whp/admin/server-settings.mdx
new file mode 100644
index 0000000..e5df25d
--- /dev/null
+++ b/src/content/docs/whp/admin/server-settings.mdx
@@ -0,0 +1,80 @@
+---
+title: Server settings & services
+description: Restart Apache, PHP-FPM, MySQL; manage PHP modules and runtimes; edit server-wide configuration.
+sidebar:
+ order: 2
+ 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 Support from '~/content/partials/support-link.mdx';
+
+
+
+
+
+This page covers the server-wide controls available in the WHP admin sections — restarting services, managing PHP modules and versions, and adjusting server-level configuration.
+
+## Sign in to WHP
+
+
+
+## Restarting services
+
+The admin **Services** page lists the long-running services that run on the server: Apache (front-end web), PHP-FPM (one or more pools), MySQL or MariaDB, the mail stack, and any add-on services like Valkey or PostgreSQL if you've enabled them.
+
+Each service has a status indicator and **Restart**, **Stop**, and **Start** controls. Restart is the safe default for picking up new configuration.
+
+
+
+## Managing PHP modules and runtimes
+
+WHP can run multiple PHP runtimes side-by-side (PHP 8.3, 8.4, etc.). With super admin you can:
+
+- Install additional PHP runtimes via the **PHP Versions** admin page.
+- Add or remove extensions per runtime — common ones (mbstring, intl, opcache, imagick, redis, etc.) are toggles; less common ones may require a [support ticket](https://secure.anhonesthost.com/submitticket.php).
+- Edit a runtime's `php.ini` from the **PHP Configuration** sub-page, then reload PHP-FPM to pick it up.
+
+Switching a site to a different PHP version is done on the customer side — open **Sites → your site** and pick from the **Container Type / PHP Version** dropdown. The runtimes available there come from this admin list.
+
+## Server-wide configuration files
+
+For settings that aren't exposed in the panel, you can SSH to the server and edit configuration directly:
+
+- **Apache:** `/etc/httpd/conf.d/` for per-app drop-ins; per-site vhosts are generated from WHP and live in a directory the panel manages. **Don't** edit generated vhosts by hand — they'll be overwritten on the next config regeneration.
+- **PHP-FPM pools:** `/etc/php-fpm.d/` for runtime pool tweaks. Pool defaults are templated by WHP; edits to per-site pools are overwritten on regeneration.
+- **MySQL/MariaDB:** `/etc/my.cnf.d/`. The defaults are tuned for the server's resource profile; large-tweak changes are usually best left to a ticket so we can advise.
+
+After editing, reload the relevant service from the WHP **Services** page (or via systemctl on the box).
+
+## Common admin tasks
+
+**Drop a hot file cache.** From the **Services** page, click **Reload** on PHP-FPM. This is the right move after editing `php.ini` or an extension list.
+
+**Free disk space on a full server.** Check `/var/log/` first — log rotation may be lagging. WHP rotates app logs into the per-site `logs/` directory; server-level logs in `/var/log` are yours to rotate via `logrotate` config in `/etc/logrotate.d/`.
+
+**See what's eating resources.** The admin **Resource usage** page shows aggregate CPU, RAM, disk I/O, and per-process drilldowns. For deeper inspection, SSH in and use `top`, `htop`, or `iotop`.
+
+## Troubleshooting
+
+**Service won't restart.** The Services page surfaces the systemd error; if it's `failed (exit-code)`, check `journalctl -u ` on the box for the underlying message. The most common cause is a syntax error in a config file you just edited.
+
+**PHP module toggle has no effect.** PHP modules need a PHP-FPM **reload** to be picked up. The toggle should do this automatically; if it doesn't, click Reload manually.
+
+**Edits to a generated vhost keep disappearing.** That file is generated. Put your customisation in a per-app drop-in under `/etc/httpd/conf.d/` instead, or open a ticket about adding a stable include hook.
+
+## Related
+
+- [Coraza WAF rules](/whp/admin/coraza-waf/)
+- [Users & delegated access](/whp/admin/user-management/)
+
+## Still stuck?
+
+
diff --git a/src/content/docs/whp/admin/site-monitoring.mdx b/src/content/docs/whp/admin/site-monitoring.mdx
new file mode 100644
index 0000000..544db64
--- /dev/null
+++ b/src/content/docs/whp/admin/site-monitoring.mdx
@@ -0,0 +1,95 @@
+---
+title: Site Monitoring rules
+description: Configure Site Monitoring across every site on the server — global ignore lists, alert routing, and severity tuning.
+sidebar:
+ order: 4
+ 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 Support from '~/content/partials/support-link.mdx';
+
+
+
+
+
+[Site Monitoring](/whp/add-ons/monitoring/) is the customer-facing alerting product. With super admin access, you can manage the rules that drive those alerts at the server level — including a server-wide ignore list, alert routing, and severity tuning.
+
+## Sign in to WHP
+
+
+
+## Where it lives
+
+Sidebar → **Site Monitoring** (admin view). The page shows two perspectives:
+
+- **Customer feed** — what your site owners see when they sign in.
+- **Admin tools** — the rule library, global ignore list, and alert configuration.
+
+## Common tasks
+
+### Add a global ignore rule
+
+When a signature is noisy for every site (for example, a known scanner you allow on your own infrastructure):
+
+1. Open **Site Monitoring → Global Ignore Rules**.
+2. Click **Add Rule**.
+3. Define the match condition (rule_id, source IP/CIDR, URL pattern, or a combination).
+4. Add a short note so future-you remembers why this exists.
+5. Save. Matching events stop firing alerts immediately.
+
+
+
+### Tune severity for a rule
+
+If a rule is set to **critical** but you've decided it's really informational in your environment:
+
+1. Find the rule in **Site Monitoring → Rules**.
+2. Open the rule and change its severity to one of: informational / warning / critical.
+3. Save. The severity change applies to new events from that rule.
+
+Severity matters because **SMS notifications fire only on critical**. Downgrading from critical to warning silences SMS without silencing the rule.
+
+### Route alerts somewhere other than the default
+
+Default routing: alerts go to the contact email on the account. You can:
+
+- **Add additional email recipients** — useful for a shared ops alias.
+- **Enable SMS for critical alerts** — wire your phone number on the **Alert Routing** page.
+- **Forward to a webhook** — for integration with Slack, PagerDuty, or your own incident pipeline.
+
+## Brute-force detection
+
+Brute-force detection is a separate rule family and has its own per-site sensitivity. From the admin view, you can adjust:
+
+- The window in which repeated failures count.
+- The threshold at which the rule fires.
+- Whether the rule auto-blocks the source IP (recommended) or only alerts.
+
+## Things to know
+
+- **Ignore lists don't stop logging.** They only suppress alerts. The events still appear in the audit feed so you can see what's actually happening.
+- **Rules apply on the next log scan**, typically within a minute.
+- **A muted rule for one customer doesn't affect others.** Per-site ignore is scoped tightly.
+
+## Troubleshooting
+
+**No alerts arriving for a known event.** Check the **Global Ignore Rules** list and any per-site ignores. Also confirm the rule's severity isn't set to informational (no email or SMS by default).
+
+**SMS not firing on critical.** Confirm SMS is enabled in **Alert Routing** and the phone number is verified.
+
+## Related
+
+- [Site Monitoring add-on](/whp/add-ons/monitoring/) — what the customer sees.
+- [Coraza WAF rules](/whp/admin/coraza-waf/) — request-level firewall, complements monitoring.
+
+## Still stuck?
+
+
diff --git a/src/content/docs/whp/admin/user-management.mdx b/src/content/docs/whp/admin/user-management.mdx
new file mode 100644
index 0000000..acef299
--- /dev/null
+++ b/src/content/docs/whp/admin/user-management.mdx
@@ -0,0 +1,96 @@
+---
+title: Users & delegated access
+description: Create sub-users, delegate panel access, and manage SFTP/SSH users at the server level.
+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 Support from '~/content/partials/support-link.mdx';
+
+
+
+
+
+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.
+
+## Three kinds of access
+
+| 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. |
+
+## Sign in to WHP
+
+
+
+## Create a WHP sub-user
+
+
+
+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.
+
+## Delegated access for a single site
+
+Use the customer-facing **Delegated Users** page (sidebar → **Delegated Users**, available on every account) when a contractor only needs to work on one site:
+
+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.
+
+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.
+
+## 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.
+
+
+
+## Managing existing users
+
+The user list shows last sign-in, role, and 2FA status. Common actions from each user's row:
+
+- **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.
+
+When someone leaves your team, **revoke sessions first** (so they're out *now*), then disable or delete the user.
+
+## 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.
+
+**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 `/`.
+
+**A delegated user can't see DNS records.** Delegated access defaults to file-only. Edit their permissions to include DNS Management.
+
+## Related
+
+- [Server settings & services](/whp/admin/server-settings/)
+
+## Still stuck?
+
+
diff --git a/src/content/docs/whp/getting-started/what-is-containerized-hosting.mdx b/src/content/docs/whp/getting-started/what-is-containerized-hosting.mdx
index 98e4e64..ddaee48 100644
--- a/src/content/docs/whp/getting-started/what-is-containerized-hosting.mdx
+++ b/src/content/docs/whp/getting-started/what-is-containerized-hosting.mdx
@@ -22,21 +22,24 @@ Think of an **apartment** versus a **townhome in a gated community**.
- **Isolation = security.** A vulnerability in another customer's site can't reach yours. There's a hard boundary between containers.
- **Add resources without moving.** Need more RAM next month? Upgrade in place — no migration, no downtime.
-## How it compares to a VPS
+## How it compares to a Virtual Dedicated Server (VDS)
-- **No server admin required.** We patch the underlying OS, monitor the host, and back up the underlying disk. You focus on your site, not on `apt update`.
-- **Right-sized resources.** A VPS gives you a whole virtual machine whether you need it or not. A container gives your site exactly the CPU, RAM, and disk you actually use — and you can resize whenever.
-- **Cheaper to run small.** Containers share the host efficiently, so you don't pay for an idle VM sitting at 5% CPU all day.
+A [Virtual Dedicated Server](https://anhonesthost.com/vds) is our VPS-class product — you get a whole virtual machine with admin access, and the same WHP control panel layered on top with full server-wide controls. The differences from a containerized plan:
+
+- **No server admin required on a container plan.** We patch the underlying OS, monitor the host, and manage the services. On a VDS, you have admin access and can patch, configure, and manage server-wide settings yourself if you want to.
+- **Right-sized resources on a container plan.** A VDS gives you a whole virtual machine with fixed CPU/RAM/storage. A container gives your site exactly the CPU, RAM, and disk you actually use — and you can resize whenever.
+- **Cheaper to run small on a container plan.** Containers share the host efficiently, so you don't pay for an idle VM sitting at 5% CPU all day.
## What it doesn't change
- **SFTP still works** within the limits of your plan, so your usual file-upload workflow is unaffected.
- **Your databases still live next to your site**, on the same host, with low-latency connections.
- **Your domain works the same way** — DNS, SSL, redirects all behave like any other web host.
+- **The WHP panel works the same way.** Whether you're on a containerized plan or a VDS, you sign in to the same WHP — VDS just unlocks the server-wide admin sections.
-## When you might want a VPS instead
+## When you might want a VDS instead
-We'll be honest with you: if you need kernel-level tweaks, custom networking, non-standard runtimes we don't support, or root over SSH, a VPS may suit you better. Most sites don't need any of that — and the trade-off is that you're then responsible for your own OS upkeep.
+A VDS suits you when you want full admin control of the server — kernel-level tweaks, custom services, your own systemd units, or you simply prefer to manage the OS yourself. You get a real virtual machine with root access, and WHP still gives you the friendly panel on top.
## Related
diff --git a/src/content/partials/draft-callout.mdx b/src/content/partials/draft-callout.mdx
new file mode 100644
index 0000000..ce5f199
--- /dev/null
+++ b/src/content/partials/draft-callout.mdx
@@ -0,0 +1,5 @@
+import { Aside } from '@astrojs/starlight/components';
+
+
diff --git a/src/content/partials/super-admin-callout.mdx b/src/content/partials/super-admin-callout.mdx
new file mode 100644
index 0000000..6e92b3e
--- /dev/null
+++ b/src/content/partials/super-admin-callout.mdx
@@ -0,0 +1,3 @@
+
+ **Requires WHP super admin access.** These features are unlocked for customers with a WHP super admin role on the server — for example, anyone running a [Virtual Dedicated Server](https://anhonesthost.com/vds). Customers without super admin won't see these pages.
+