These 301s live in .htaccess on secure.anhonesthost.com and existed only on that server. WHMCS rewrites .htaccess during some updates, which would silently drop them — every retired KB URL would start 404ing with nothing in version control to restore from. deploy/README.md documents where it installs, how to reinstall, and the two traps: article/category IDs collide (only the trailing .html tells them apart, so rule order is load-bearing) and the slug is ignored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Deploy artefacts
Config that lives on other servers but belongs under version control here, because it exists to serve this KB.
whmcs-kb-redirects.conf
301 redirects that send the retired WHMCS knowledgebase
(secure.anhonesthost.com/knowledgebase/*) to its replacement pages on
kb.anhonesthost.com. Installed 2026-08-01.
Where it lives in production: /home/whmcs/public_html/.htaccess on
secure.anhonesthost.com, prepended before the
### BEGIN - WHMCS managed rules ### marker. It has to come first — WHMCS's
own block ends with a catch-all that routes everything to index.php, so
rules placed after it never run.
The canonical copy on that server is /root/kb-redirects.conf, and the
pre-migration .htaccess is backed up at
/root/htaccess-backup-20260801.bak.
Reinstalling
WHMCS rewrites .htaccess during some updates, which will silently drop
these rules. To restore:
cd /home/whmcs/public_html
cp -a .htaccess /root/htaccess-backup-$(date +%Y%m%d).bak # keep whatever WHMCS wrote
cat /root/kb-redirects.conf /root/htaccess-backup-$(date +%Y%m%d).bak > /tmp/htaccess.new
install -o whmcs -g whmcs -m 644 /tmp/htaccess.new .htaccess
apachectl -t
Then spot-check a redirect:
curl -sI https://secure.anhonesthost.com/knowledgebase/13/x.html | grep -i location
# expect: https://kb.anhonesthost.com/support/remote-support/
Two things that will bite you when editing it
Article and category IDs collide. Both use the shape
/knowledgebase/<id>/<slug>, and the same number means different things —
article 5 is "What are my Name Servers?", category 5 is "WordPress Specific".
The only discriminator is the trailing .html on articles. That's why every
article rule appears before every category rule and terminates with [L]: by
the time the broad category patterns run, anything ending .html is already
gone. Reordering the file breaks this silently, and the wrong page still
returns 200.
The slug is ignored. WHMCS reads only the id, so any slug with the right
id resolves. The rules match [^/]* for the slug for the same reason.
Legacy pre-SEO URLs (knowledgebase.php?action=displayarticle&id=N and
?action=displaycat&catid=N) are mapped explicitly. (^|&)id= cannot match
catid= — the preceding character is t, not & or start-of-string — so the
two sets can't cross-fire.