Bryan Hamilton / writing

bryanhamilton.info / writing / article

The Deploy Pattern That Keeps My 1,000-Page Site Alive Without Shell Access

No shell, no SSH, no pipeline - just a browser file manager and a prayer. How a token-gated, self-verifying, self-deleting PHP worker makes pasted-change deploys on shared cPanel hosting survivable, and the failure modes that shaped the 18-rule checklist.

  • November 7, 2026
  • 6 min read
  • performance · webdev · php · corewebvitals
  • More writing

I run The DJ Calendar - about 1,000 pages of PHP/MySQL on shared cPanel hosting. No shell. No SSH. No deploy pipeline. LiteSpeed caches HTML for 5 minutes, and opcache serves stale output for a minute after every write.

Pasting a code change into a production file through a browser file manager is how sites die. So over months of live deploys, I built a worker pattern that makes that kind of deploy survivable, and I open-sourced it: guarded-deploy-workers.

How a deploy works

A "worker" is a single PHP file I upload to the web root. I hit its URL once with a secret token. It:

  • 404s unless the token matches - and renders the site's real 404 page, so the worker's existence never leaks
  • Checks an idempotency marker - an already-patched file aborts, so double-patching is impossible
  • Counts every needle string - if an anchor does not appear exactly the expected number of times, nothing is written
  • Backs up before writing, and restores automatically if post-write verification fails
  • Verifies the patch, not the intent - the replacements must land byte-exact or it rolls back
  • Deletes itself after reporting

The pattern wraps what would otherwise be open-heart surgery in a browser tab.

The bugs that taught me the most

The class is ~100 lines. The real value is the checklist of failure modes, all earned live:

  • A verifier that checked for an unchanged file length when the patch legitimately removed 2 bytes. It restored a correct patch. My own safety check fired on a good deploy.
  • A needle string that appeared twice in the file. The patch landed in both places. Now every needle is counted, not assumed.
  • opcache serving the old file long after the disk was correct - the default explanation for "the patch did not work" on shared hosting, and the reason live verification always cache-busts.
  • Uppercase characters in a preg lowercase filter - the string shredder that ate a slug. Always lowercase before the character-class filter.
  • A sitemap whose disk bytes did not match the served bytes - byte-exact needles false-failed until the insert walked back to the nearest <url> tag instead of trusting whitespace.

The full list is an 18-rule pre-flight checklist in the repo.

When not to use this

If you have a real deployment pipeline, use it. This pattern is for the world a lot of us actually live in: a cPanel box, FTP credentials, a production site that pays the bills, and no infrastructure team coming to save you.

The repo is MIT licensed: github.com/bryanhamiltondev/guarded-deploy-workers. What is your survivability trick on locked-down hosting?

More from the workshop

All writingEvery article, on this domain. Open source11 production-extracted projects.