Skip to content

Hostinger Deployment Guide

🏗️ How Deployment Actually Works

Deployment is fully automated CI/CD — there is no manual VPS/PM2/nginx setup. The two services live in different places:

  • Frontend + docs → built by GitHub Actions and served by Hostinger (static site) at https://pcbgenerator.com (docs at /docs/).
  • FastAPI backend → runs on Render (https://ai-assisted-pcb-stackup-generator.onrender.com); the frontend is built to call it via VITE_API_URL.

There is no Node.js backend, no Ollama, no PM2, and no nginx in the current architecture. AI chat is served by the FastAPI backend over SSE.

The pipeline is defined in .github/workflows/deploy-hostinger.yml.

🚀 The Deploy Flow

push to main (backend/**, frontend/**, docs/**, mkdocs.yml, deps, or the workflow)
┌──────────────────────┐   pytest backend/tests/ must pass
│ Job 1: test-backend  │   (installs CPU-only PyTorch + backend deps)
└──────────┬───────────┘
           │ success or skipped
┌──────────────────────────────────────────────────────────┐
│ Job 2: build-and-deploy                                   │
│  • npm ci + `npx vitest run` (full suite gates the deploy)│
│  • npm run build  (VITE_API_URL → Render backend)         │
│  • mkdocs build   (docs site)                             │
│  • assemble deploy_out/  (frontend at /, docs at /docs)   │
│  • write deploy-info.json                                 │
│  • force-push orphan commit → `hostinger-deploy` branch   │
│  • curl RENDER_DEPLOY_HOOK_URL  (triggers backend deploy) │
└──────────┬───────────────────────────────────────────────┘
   Hostinger pulls `hostinger-deploy` → public_html   (its Git auto-deploy)
   Render rebuilds the FastAPI backend                (deploy hook)

Why the branch hand-off? GitHub-hosted runners are blocked from Hostinger's FTP (21) and SSH/SFTP (65002) ports, so the runner never connects to Hostinger directly — it publishes the built tree to the hostinger-deploy branch and Hostinger's Git integration pulls it into public_html.

✅ Triggering a Deploy

  • Automatic: push to main touching backend/**, frontend/**, docs/**, mkdocs.yml, backend/requirements*.txt, frontend/package*.json, or the workflow file itself.
  • Manual: run the Deploy Frontend to Hostinger workflow via workflow_dispatch (Actions tab → Run workflow).

A push that only changes unrelated files (e.g. .claude/, root scripts) does not trigger a deploy.

🔑 Required GitHub Secrets

Set these in the repo's Settings → Secrets and variables → Actions:

Secret Used for
VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY Frontend auth/DB at build time
VITE_POSTHOG_KEY, VITE_POSTHOG_HOST, VITE_SENTRY_DSN Observability (dormant no-ops when unset)
RENDER_DEPLOY_HOOK_URL Triggers the Render backend deploy
GITHUB_TOKEN Force-push the built site to hostinger-deploy (auto-provided)

Feature flags are baked into the build by the workflow (AI-native shell, standalone impedance/link-budget/antenna, planar filter, thermal management, chat prompts/auto-open all =true). Change them in the Build frontend step of the workflow, not in a server .env.

🔍 Verifying What's Live

The build writes a web-servable marker at the site root:

curl https://pcbgenerator.com/deploy-info.json
# -> {"commit":"<sha>","ref":"main","built":"<UTC>","run_id":"<id>"}

Compare commit against the main HEAD you expect. Then spot-check:

🔐 Hostinger Git Integration (one-time)

Hostinger pulls the hostinger-deploy branch via its Git auto-deploy feature. The SSH key/connection setup for that integration is covered separately:

Mailbox/alias setup for the support@pcbgenerator.com address is in HOSTINGER_EMAIL_SETUP.md.

📥 Feedback Storage

User feedback (thumbs up/down, comments) is written by the FastAPI backend as JSONL, one file per UTC day: backend/data/feedback/feedback_YYYY-MM-DD.jsonl (each line is one submission: source, trigger, rating, comment, context, ts, ip). Because the backend runs on Render, this lives on the Render service's filesystem — attach a Render persistent disk (or export periodically) if you need it to survive redeploys, since a service's ephemeral disk is reset on each deploy. The write path is POST /api/feedback; point it at a DB/Supabase later if durable storage is needed.

🛠️ Troubleshooting

  • Deploy didn't run — the push didn't touch a watched path, or it landed on a branch other than main. Use the manual workflow_dispatch trigger.
  • Deploy ran but site unchanged — check deploy-info.json's commit; if it matches, Hostinger may not have pulled yet (its Git integration polls) — give it a minute or trigger a pull from hPanel.
  • Backend errors after deploy — the frontend deployed but the Render deploy hook failed or Render is cold-starting; check the Render dashboard and /health. See ../TROUBLESHOOTING.md.
  • Tests blocked the deploytest-backend (pytest) or the frontend vitest run gate failed; the deploy correctly does not publish. Fix the failing test and re-push.