Files
AnHonestHost DevandClaude Opus 5 063f992516 chore: version-control the WHMCS KB redirect rules
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>
2026-08-01 17:27:59 -07:00
..

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.