The WHP panel sends Strict-Transport-Security max-age=31536000
includeSubDomains on every response (correct for prod). When a server
is rebuilt, the regenerated self-signed cert no longer matches what
the admin's browser cached as HSTS-valid, and there is no clickable
'proceed unsafely' escape — the admin is locked out of their own
panel by hostname.
Add a Caution Aside under Network & SSL describing the symptom, the
two-browser HSTS confirmation pattern, and the three recovery paths
(IP-direct + LE issuance, browser HSTS clear, real cert preserved
across rebuilds). Frames LE issuance as a first-day operation, not an
incident response.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Covers the opt-in LUKS2 encryption of /docker available on new server
installs. Reboot UX (web unlock at :8444, SSH fallback), threat model
in plain English, what LUKS does and doesn't protect against, header
backup handling, passphrase rotation outline, and the "do not enable
this if you need unattended reboots" caveat.
Sidebar order 7 (after Backups in the admin section).
Linked from the admin overview "What's in this section" list and from
the VDS comparison section of "What is containerized hosting?".
No cost / pricing language by design — operational positioning is
still being decided.
Adds /whp/local-dev/ with three articles documenting the public cloud
container images on repo.anhonesthost.net/cloud-hosting-platform/:
- overview: dev/prod parity pitch, prerequisites, table of images,
link to the Gitea org, and a note that this is for customers
comfortable with Docker (the hosted side needs none of this).
- php-apache: cloud-apache-container (cac). PHP 7.4 through 8.5 side
by side, default 8.3, AlmaLinux 9 + Apache mod_ssl. Documents
image tags, local-dev.sh flags, manual docker command, bind-mount
layout, WordPress install, helper scripts (instance_start /
instance_stop / instance_logs / instance_db_info), and cleanup.
- node: cloud-node-container (cnoc). Node 18/20/22, default 20,
AlmaLinux 9 + Nginx (SSL + HTTP→HTTPS redirect) + PM2 +
Memcached. Same shape: tags, flags, manual docker, where code
goes (user/app/), logs layout, helpers, cleanup.
Sidebar gains a 'Local development' group between Site Builder and
Reference. Section redirect /whp/local-dev/ -> overview added to
the section-landing redirect set.
- astro.config.mjs: section-only URLs now redirect to the first article in
that section. /whp/admin/ used to render Apache's directory listing
because no index.html existed; now it serves a meta-refresh to
/whp/admin/overview/. Same for /whp/, /whp/getting-started/,
/whp/how-to/, /whp/site-builder/, /whp/reference/, /whp/add-ons/.
- public/.htaccess: ships in dist, disables Options Indexes + MultiViews
(defense in depth so any future section without a redirect doesn't
leak a listing), and routes 404/403 to /404.html.
- src/content/docs/404.md: replaces the bare 'check the URL' tagline
with two explicit actions — 'Go to the knowledge base home' and
'WHP getting started'.
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).
Caught by Lighthouse on prod:
1. CRITICAL: support-link.mdx and signing-in.mdx used the MDX expression
`{URLS.x}` inside Markdown-link parens, which MDX doesn't evaluate —
the resulting href was URL-encoded '%7BURLS.whmcsTicket%7D' on every
page with a Support partial. Replaced with HTML anchors so the
expression evaluates.
2. Light-mode --sl-color-text-accent was the brand teal (#00d4aa) on a
cream background = 1.73:1 contrast. Introduced --anhh-accent-on-light
(#047857) at ~6:1 for inline accent text/links. Brand graphics keep
the original teal.
3. Bumped light-mode --anhh-text-secondary and --anhh-text-muted to
#334155 / #475569 so muted UI text clears AA.
4. Hub brand link aria-label now includes 'Knowledge Base' so the
accessible name covers the visible text.
Adds /whp/site-builder/ with overview, getting-started, blocks-and-pages,
styling, and publishing. Wired as a 'Site Builder' sidebar group with a
Beta badge.
- Captured real screenshots via the demo account through a redaction
step (server names, domain, demo-user all swapped for placeholders)
- New beta-callout partial shared across all 5 articles
- capture-site-builder.ts is local-only (uses tools/screenshots/.env
for demo creds, never runs in CI)
Triggers on push to main and manual workflow_dispatch. Builds with
Node 20, runs astro check, builds the static site, then mirrors
./dist via SFTP using the SFTP_* secrets configured on the repo.
Password-based SFTP for now (matches the credentials we have). Swap to
key-based by adding SFTP_KEY as a secret and tweaking the lftp call
when the production site user is created.
Adds /whp/admin/ with: overview, server-settings, coraza-waf,
site-monitoring, user-management. Articles are product-neutral
(no VDS in titles or required framing) since super admin may be
offered as a separate service later. They're marked Draft via:
- 'Draft' sidebar badge on the group + each article
- A draft callout partial at the top of every page noting WIP
The super-admin-callout partial (renamed from vds-only-callout)
mentions VDS as today's most common way to get super admin without
locking the docs to that single product.
The apartment-vs-townhome framing maps more cleanly onto containers:
- An apartment shares walls, plumbing, air — neighbour noise/smells leak in.
That's the experience on shared hosting.
- A townhome in a gated community keeps the shared upside (security, gates,
community centre = the server/host) but isolates each unit. That's the
containerized story.
Adds external links to anhonesthost.com (Hosting) and
secure.anhonesthost.com (Client Portal) in both the Starlight header
(via the SiteTitle override) and the custom hub page header. Hidden
on narrow viewports so the search box, hamburger, and theme toggle
keep room.
Discovery against the demo account on whp01 surfaced several inaccuracies:
- Cache is Valkey (Redis wire-compatible), not Redis or Memcached.
No Memcached is offered as a separate service.
- Site Monitoring is the sidebar label (not 'AI Monitor').
- 'Add a domain' has no Primary/Add-on distinction.
- Sites form: 'Container Type' (not 'Site type'), Number of Containers
(1-10 for horizontal scaling), CPU per Container (default 0.25),
Memory per Container (default 256MB), SSL inline on the same form.
- Backups: default retention 5 days / 10 backups; on-demand + scheduled;
S3 backup targets are visible and configurable.
- Email: per-domain settings live behind 'Setup Instructions' on the
Email page; mail server hostname is on the Dashboard (per-server,
e.g. mail01.cloud-hosting.io), not per-domain.
Also reworked the screenshot pipeline:
- New shots.config.ts targets the real index.php?page=... URLs
- Added redactSensitive() step that runs before each screenshot to swap
server names, IPs, mail hostnames, and demo-user-isms with neutral
placeholders. This keeps docs portable across the fleet.
- Hides .brand-full and .navbar-text (top-bar server identifier and
Welcome greeting).
- Captured 9 real WHP screenshots; removed stale placeholders.
- Remove smtp.anhonesthost.com row from service-hostnames partial — we
don't operate a single shared SMTP gateway; mail server hostnames are
per-domain and listed on the WHP Dashboard
- Drop SSH tunneling section from service-hostnames reference (not a
supported access path)
- Point email-client setup at the Dashboard for the per-domain host
rather than assuming a 'mail.<yourdomain>' pattern
- Pulled the real inline SVG from anhonesthost.com (chevrons + wordmark
with 'Host' in teal #00d4aa)
- Override Starlight's SiteTitle component so the SVG is inlined rather
than loaded as <img>, letting currentColor follow the active theme
- Hub page header uses the same wordmark
- 'Knowledge Base' label sits to the right of the brand mark, hidden on
narrow viewports
Starlight's default uses --sl-color-text-accent (our teal #00d4aa) as
the active-item background, which gives ~3:1 contrast vs the dark
inverted text — under WCAG AA (4.5:1). Override with primary blue
+ white text for ~9:1.
Note: customCss loads before Starlight's component CSS, so the rule
needs (0,2,1) specificity to win against Starlight's scoped (0,2,0).
Placeholders are 1440x900 'Screenshot pending' PNGs that will be
overwritten by real captures via 'npm run screenshots' once a demo
user is provisioned.