BWS Site: Git-Deploy Migration + Support Page

BWS Site - Git-Connected Deploy + Remote Support Page

How bwscomputerservice.com moved from manual single-file uploads to a Git-connected auto-deploy pipeline, and got a branded remote-support page added in the process. Done 2026-07-26. No downtime - the live homepage never dropped during the migration.

The payoff: the site now works exactly like the Hugo KB - edit in VS Code, push to GitHub, Cloudflare auto-deploys. Adding a page is now just adding a file and pushing.

The stack (what serves the site)

Piece What it is
Hosting Cloudflare Worker with static assets (bws-main), NOT Cloudflare Pages
Source repo github.com/NeuralNetworkTrader/bws-site (private)
Deploy trigger Git push to main -> Cloudflare Workers Builds -> auto-deploy
Site files live in public/ in the repo
Config wrangler.jsonc in repo root tells Cloudflare to serve public/
Remote support Zoho Assist branded portal, linked (not embedded) from /support

Repo structure

bws-site/
├── wrangler.jsonc      # tells Cloudflare: serve ./public as static assets
├── .gitignore
└── public/
    ├── index.html      # homepage
    ├── support.html    # remote-support page (served at /support)
    └── _headers        # security headers (CSP, X-Frame-Options, etc.)

wrangler.jsonc contents:

{
  "name": "bws-main",
  "compatibility_date": "2026-07-01",
  "assets": {
    "directory": "./public",
    "not_found_handling": "404-page",
    "html_handling": "auto-trailing-slash"
  }
}

The "name" MUST match the existing Worker (bws-main) exactly, or a Git deploy creates a duplicate Worker instead of updating the real one.

How to add or edit a page now

cd ~/Projects/bws-site
# edit or add a file in public/  (e.g. public/pricing.html)
git add .
git status                        # confirm the file is staged
git commit -m "Add pricing page"
git push -u origin main           # triggers Cloudflare build + deploy

Cloudflare builds and deploys automatically on push. A new file in public/ is live at its path (e.g. public/pricing.html -> /pricing) within a minute or two. Wait for the build to finish before checking (see cache gotcha below).

Security headers - IMPORTANT: they come from TWO sources

This tripped us up during the migration. The A+ header grade is produced by two separate mechanisms, and both must stay in place:

  1. The _headers file (in public/) provides:
    • Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;
    • X-Frame-Options: SAMEORIGIN
    • Referrer-Policy and Permissions-Policy
  2. The Cloudflare zone/dashboard setting provides:
    • Strict-Transport-Security (HSTS) - this is NOT in the _headers file; it’s set at the zone level (SSL/TLS -> Edge Certificates -> HSTS).

So: the _headers file is version-controlled and deploys with the site, but HSTS lives in the Cloudflare dashboard. Don’t go looking for HSTS in the repo - it’s not there, and that’s correct. If the A+ grade ever drops, check BOTH sources.

Verify headers after any deploy:

curl -I https://bwscomputerservice.com/support

Want to see: content-security-policy, permissions-policy, referrer-policy, x-frame-options, strict-transport-security, x-content-type-options. Cross-check with https://securityheaders.com (should show A+).

The support page (/support)

A branded remote-support landing page. Design goal for a repair business: make a nervous, non-technical person feel safe letting someone control their computer (the exact scenario scam-callers exploit). So the page leads with trust: plain-language explanation, a clear 3-step flow, a “you’re in control” note, and an explicit scam warning (“we never cold-call asking for access”).

  • Links to the Zoho Assist branded portal (https://assist.zoho.com/portal/bwscomputerservice) - opens in a new tab.
  • Deliberately NOT an iframe. An embedded Zoho widget would require loosening the strict CSP (frame-src), which would drop the security posture and trip the domain monitor. A plain outbound link needs zero CSP changes. Keep it a link.
  • Canonical URL is /support (no .html) - the html_handling setting redirects /support.html -> /support with a 307. Share the clean /support form.

Remote support platform choice: Zoho Assist Standard (~$10/tech/mo billed annually, 2 concurrent, reboot-and-reconnect, branded portal domain). Chosen over TeamViewer ($24.90/mo) on cost + branded-domain feature. One-time attended fixes only - nothing persists on the client after the session. (For ongoing managed clients, the plan is a Wazuh agent instead - different tool, different job.)

Migration gotchas (the hard-won lessons)

These all bit us during the build. Documented so future-me doesn’t re-learn them.

  • Worker vs Pages - stayed on Worker. The site was already a Worker with static assets (Cloudflare’s recommended architecture for 2026). Workers now support Git integration too (Workers Builds), so there was NO need to migrate to a Pages project. Connecting the existing Worker to Git = far less risk than a platform migration. One-way door warning: once a Worker/Pages project uses Git deploy, you can’t switch back to manual Direct Upload.

  • .gitignore copied from the Hugo repo ignored /public/. In Hugo, public/ is generated build output you ignore. Here, public/ is the ACTUAL SITE SOURCE. The copied .gitignore would have pushed an empty repo and deployed a blank site. Fix: removed the /public/ and /resources/ lines. Lesson: config files copied between projects need their project-specific assumptions checked - /public/ means opposite things in Hugo vs a raw static site. Always git status before committing to confirm the real files are staged.

  • SSH push failed - this box uses gh (GitHub CLI), not an SSH key. git@github.com: Permission denied (publickey) happened because there’s no SSH key configured; auth goes through the gh CLI (OAuth token from gh auth login). Fix: use the HTTPS remote (https://github.com/.../bws-site.git) which works with the cached gh credentials, or use gh repo create ... --source=. --push. Check auth with gh auth status.

  • First Cloudflare connect needed wrangler.jsonc first. The Git connection’s deploy command is npx wrangler deploy, which needs a wrangler config in the repo to know what/how to deploy. The repo didn’t have one initially. Fix: added wrangler.jsonc (above) declaring public/ as the assets dir, committed+pushed, THEN connected. Without it, wrangler deploy has nothing to read.

  • 404 right after deploy = cache/timing, not a real error. Checked /support seconds after pushing and got a 404. The build hadn’t finished propagating and the browser/edge cached the 404. Fix: wait a minute, hard-refresh (Ctrl+Shift+R) or use incognito. It was fine once the build completed. Don’t panic-debug a 404 in the first minute after a push.

  • The reused API token is named “cyber-kb build token”. Cosmetic - the Workers Build uses a token originally made for the KB repo. Works fine, just an odd name to see attached to the website Worker. Not worth changing.

Rollback safety

Git deploys go to the SAME bws-main Worker, so its deployment history in the Cloudflare dashboard keeps every version (incl. the old manual deploy a6cd90f6). If a Git deploy ever looks wrong: Workers & Pages -> bws-main -> Deployments -> pick a known-good version -> Rollback. Instant, no data loss. This is why the migration carried zero real risk to the live site.

Verify-it-works checklist (after any deploy)

  1. https://bwscomputerservice.com - homepage loads (incognito to skip cache)
  2. https://bwscomputerservice.com/support - support page loads
  3. curl -I https://bwscomputerservice.com/support - all security headers present
  4. https://securityheaders.com scan - still A+
  5. Click “Start Remote Support” - opens the Zoho branded portal in a new tab
  6. domain-monitor.sh (existing watcher) will alert if headers ever regress

Files & locations

What Where
Local repo ~/Projects/bws-site/
GitHub repo github.com/NeuralNetworkTrader/bws-site (private)
Homepage public/index.html -> /
Support page public/support.html -> /support
Security headers file public/_headers
Wrangler config wrangler.jsonc (repo root)
Cloudflare Worker Workers & Pages -> bws-main
HSTS setting Cloudflare zone -> SSL/TLS -> Edge Certificates
Zoho support portal https://assist.zoho.com/portal/bwscomputerservice

To-do / future ideas

  • Confirm the Zoho portal slug singular/plural is consistent (bwscomputerservice, matching the singular domain).
  • Add a link to /support from the homepage nav so clients can find it.
  • Consider a robots.txt / sitemap.xml in public/ if SEO matters.
  • Ongoing managed-client monitoring = Wazuh agent (separate project, not this).