Four answers to four questions that always come up once the basic flow clicks. Keep this lesson bookmarked — you'll come back to it.
Three rules, in order of importance:
1. Never commit secrets to the repo. Put every API key, token, password in a .env file at the project root. Add .env to your .gitignore on day one. Your code reads from process.env.OPENAI_KEY instead of having the key hardcoded.
2. Tell your deploy platform the secrets, not your repo. Both Cloudflare Pages and Coolify have a UI section called Environment Variables. You paste the key value in there once. The platform makes it available to your code at runtime as process.env.OPENAI_KEY — same as on your Mac.
3. If you ever accidentally commit a secret, rotate it immediately. Don't just delete the commit — by the time you notice, scrapers may have grabbed it. Generate a new key in the service's dashboard, update your .env + the platform's env var, invalidate the old one. The leaked one in git history is dead anyway.
On a private repo, a leaked secret is a smaller blast radius — only collaborators saw it. On a public repo, bots scan GitHub for new commits with sk-... patterns within seconds. If you go public, double-check every commit. git diff --staged before git commit is your friend.
Yes — and you already know how, because you do this for Coolify, Portainer, and NocoDB already. The same pattern works for Cloudflare Pages.
The setup: in your Cloudflare dashboard → Zero Trust → Access → Applications → add a new self-hosted application targeting your Pages URL (e.g. card-tracker.lovebuiltautomations.com). Add a policy like "only allow emails ending in @drawingboardbooksllc.com" or "only this list of GitHub users" or "only valid service tokens." Save.
Visitors hitting the URL now get the Cloudflare Access login screen first. After they auth, they get to your site. Site owners (you) don't change anything in the deployed code — Access sits in front transparently.
Personal dashboards (only you log in). Family-shared tools (you + Josh + a small allowlist). Pre-launch staging sites (auth-gate the dev URL, public-launch the prod URL). All free under your existing Cloudflare plan.
You want lovebuiltautomations.com/games/duck-hunt rather than duck-hunt.lovebuiltautomations.com. Both work; path-based is the cleaner mental model for a portal-style site. Three ways to do it:
Option A — All in one repo, one Pages project. Easiest. The repo contains /games/duck-hunt/index.html, /games/pepper-popper/index.html, etc. Pages serves the whole directory tree. Routes Just Work because they match the folder structure.
Option B — Cloudflare Pages _redirects file. Use this when each game lives in its own repo + Pages project. Put a _redirects file at the root of your "portal" Pages project mapping paths to the standalone Pages URLs:
The 200 at the end is "rewrite, not redirect" — visitor URL stays as lovebuiltautomations.com/games/duck-hunt, but the content comes from the sub-Pages.
Option C — Coolify reverse proxy. When the portal is a Coolify-hosted app (because it has a Node server), you can configure the proxy to route specific paths to upstream services. More flexible than _redirects, more setup. Worth it when you mix static + dynamic + multiple servers.
Start with Option A (monorepo). It matches how playground already lives, and you don't need a redirect layer at all — the folder structure IS the URL structure. Reach for B or C only when you have a real need to split.
Both run on Cloudflare's edge network. The shorthand:
Pages = static site hosting + lightweight functions. You point Pages at a GitHub repo with HTML / CSS / JS / image files. It serves them globally. If you need a tiny bit of dynamic behavior (a contact form handler, an auth callback, a webhook receiver), you drop a JS file in a /functions/ folder. Each function runs server-side at the edge when its URL is hit. Maximum 10ms CPU per request on the free tier.
Workers = pure edge compute, no static files. A Worker is a JS file that responds to every HTTP request. No HTML/CSS in the source — the Worker generates the entire response programmatically. Used for: API proxies, custom auth layers, edge-rendered apps, image transformations, geo-aware routing.
If you're publishing files visitors load in a browser → Pages. If you're writing code that responds to HTTP requests programmatically → Workers. If you need both (a static site WITH some dynamic endpoints), you stay in Pages and use Pages Functions — same Worker runtime under the hood, but co-located with your static files.
For your playground today: Pages-or-Coolify is the right framing. You don't need raw Workers yet. When you do (e.g., "I want a custom edge function that aggregates data from three APIs and serves the result"), Pages Functions are your gateway drug — same skill, lower stakes.
Seven lessons. Git, deploy targets, architecture, environments, versioning, the actual hands-on flow, and the four follow-up questions. You can now have any deployment conversation with anyone and follow it — and ship your first thing when you're ready.