cf-gate
Headlessly create/remove Cloudflare Access (Zero Trust) gates that require
an email login before a site renders. Wraps the Cloudflare API in
scripts/cf-gate.sh; credentials come from a .env next to it.
Setup (once)
- Copy
.env.example→.envin this skill's base directory,chmod 600 .env, and fillCF_API_TOKEN+CF_ACCOUNT_ID. The.env.examplelists the exact token scopes. Minting that token in the dashboard is the only GUI step. - Verify: run the
whoamicommand below. It must printcredentials valid.
.env is gitignored — never commit it.
Usage
Resolve the script from the injected "Base directory for this skill" value:
SKILL="<base directory for this skill>"
bash "$SKILL/scripts/cf-gate.sh" <command> [args]
| Command | Effect |
|---|---|
whoami |
Verify the token works against the account. |
gate <host> [email|@domain ...] |
Create/update an allow-email gate on <host>. Idempotent. Emails default to CF_GATE_EMAILS. |
ungate <host> |
Remove the gate on <host>. |
list |
List every Access app (id, domain, name). |
status <host> |
Show the gate's policies (decision + allowed emails). |
pages-domain <project> <host> |
Attach a custom domain to a Pages project (so the gated host resolves). |
@example.com allows any address on that domain; a bare address allows just
that person. Re-running gate on an existing host updates it in place (no
duplicate apps).
Typical end-to-end flow (e.g. gating a Pages site on a custom domain)
SKILL="<base directory for this skill>"
G() { bash "$SKILL/scripts/cf-gate.sh" "$@"; }
G whoami # sanity check
G pages-domain polish-prompt-reports reports.hsiehting.com # custom domain → Pages
G gate reports.hsiehting.com # gate it to CF_GATE_EMAILS
G status reports.hsiehting.com # confirm the policy
After gating, visiting the host shows a Cloudflare login; an allowed email receives a one-time PIN (or uses the configured IdP), then reaches the site.
Notes & gotchas
- The host must be a Cloudflare-proxied zone or a
*.pages.devdomain. For a custom domain likereports.hsiehting.com,pages-domainboth registers it with the Pages project and creates the proxied CNAME →<project>.pages.dev. The CNAME step needs the token to have Zone → DNS → Edit on that zone; if it doesn't, the command degrades gracefully and tells you to add the scope. - One Access app per hostname. For a catch-all, gate
*.hsiehting.comas its own host string (the wildcard hostname must be routable). - Removing the gate ≠ taking the site down.
ungateonly drops the Access policy; the site itself stays served by Pages/Workers/DNS. - Errors print the Cloudflare error
[code] message; an auth error usually means the token is missing theAccess: Apps and Policies: Editscope.