Cloudflare Worker that acts as a strict pull-through proxy to an upstream GraphQL endpoint in your k8s cluster.
- Accepts GraphQL requests on
/graphql(GETandPOST). - Accepts Directus asset passthrough requests on
/directus/assets/*(GETandHEAD). - Proxies requests to
UPSTREAM_GRAPHQL_URLwithout local schema composition/resolvers. - Supports GraphQL subscription upgrades over WebSocket by forwarding required upgrade and
Sec-WebSocket-*headers to upstream. - Preserves upstream schema exposure (including introspection behavior) because the worker does not host schema locally.
- Enforces CORS allow-list via
CORS_DOMAINS(exact origins and wildcard subdomain patterns likehttps://*.suncoast.systemsor*.suncoast.systems); additionally allows localhost loopback origins only when the request hostname has adevsubdomain label. - Uses bearer-token passthrough only:
- HTTP GraphQL requests (
GET/POST) requireAuthorization: Bearer ...; missing/invalid bearer headers return401 Not authorized. - WebSocket upgrade handshakes are allowed without
Authorizationso browser clients can connect; upstream GraphQL must enforce token auth duringconnection_init. - Valid
Authorization: Bearer ...headers are forwarded to upstream unchanged.
- HTTP GraphQL requests (
- Forwards client IP metadata to upstream using Cloudflare-trusted source only:
- Reads only
CF-Connecting-IPfrom the Cloudflare edge request. - Ignores inbound
X-Forwarded-For,Forwarded,X-Real-IP, andTrue-Client-IPvalues from clients. - Sends normalized IP via
X-Client-IP,X-Real-IP,CF-Connecting-IP,True-Client-IP,X-Forwarded-For, andForwarded.
- Reads only
- Provides edge caching for unauthenticated query operations.
- Cache is enabled by default and controlled via env vars.
- Only query operations are cache candidates.
- Requests with
AuthorizationorCookieare never cached. - Mutations/subscriptions are never cached.
- POST query responses are cached with a SHA-256 body-based key.
- Responses with
Set-Cookie,Cache-Control: private, orCache-Control: no-storeare not cached. - By default, GraphQL responses containing
errorsare not cached (CACHE_INCLUDE_GRAPHQL_ERRORS=false). - WebSocket upgrade requests are always bypassed from cache and returned as raw upgraded responses.
UPSTREAM_GRAPHQL_URL: optional full upstream GraphQL URL override.- By default this is generated by Terraform from
UPSTREAM_DNS_NAME,domain, andUPSTREAM_GRAPHQL_PATH.
- By default this is generated by Terraform from
UPSTREAM_TIMEOUT_MS(optional, default120000): timeout for upstream GraphQL request before returning504(also used for WebSocket handshake timeout).UPSTREAM_DIRECTUS_ASSET_BASE_URL(optional): base URL used for/directus/assets/*passthrough. If omitted, defaults tohttps://<UPSTREAM_DNS_NAME>.<domain>.UPSTREAM_DIRECTUS_ASSET_PATH(default/assets): upstream path prefix appended toUPSTREAM_DIRECTUS_ASSET_BASE_URL.DIRECTUS_ASSET_PROXY_PREFIX(default/directus/assets): public path prefix exposed by this worker for asset passthrough.CORS_DOMAINS(required): comma-separated allowed origins. Supports exact origins and wildcard subdomain entries likehttps://*.suncoast.systemsor*.suncoast.systems.- Terraform sets this from
ALLOWED_HOSTSand automatically appends*.${domain}.
- Terraform sets this from
CACHE_ENABLED(defaulttrue).CACHE_TTL_SECONDS(default60).CACHE_STALE_WHILE_REVALIDATE_SECONDS(default30).CACHE_INCLUDE_GRAPHQL_ERRORS(defaultfalse).
- This workspace does not create or manage upstream Cloudflare Tunnel DNS records.
UPSTREAM_DNS_NAME(defaultgraphql-origin): relative DNS label for the externally managed upstream GraphQL hostname.UPSTREAM_GRAPHQL_PATH(default/v1/graphql): path appended to the upstream hostname.global-terraform-workspaceownsgraphql-origin.suncoast.systemsthroughmodule.cloudflare_tunnel["graphql"].cloudflare_record.this.global-terraform-workspacealso owns the matching tunnel ingress config throughmodule.cloudflare_tunnel["graphql"].cloudflare_zero_trust_tunnel_cloudflared_config.this.- Deprecated compatibility variables such as
MANAGE_UPSTREAM_DNS_RECORD,MANAGE_UPSTREAM_TUNNEL_CONFIG,UPSTREAM_TUNNEL_ID,UPSTREAM_TUNNEL_SERVICE, andUPSTREAM_ORIGIN_IPare accepted by this module but have no effect.
GET /healthzreturns proxy health and version.GET /upstream-probeperforms a direct probe toUPSTREAM_GRAPHQL_URLand returns reachability/latency/status diagnostics.