Skip to content

dotcomrow/cf-suncoast-graphql-proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cf-suncoast-graphql-proxy

Cloudflare Worker that acts as a strict pull-through proxy to an upstream GraphQL endpoint in your k8s cluster.

Behavior

  • Accepts GraphQL requests on /graphql (GET and POST).
  • Accepts Directus asset passthrough requests on /directus/assets/* (GET and HEAD).
  • Proxies requests to UPSTREAM_GRAPHQL_URL without 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 like https://*.suncoast.systems or *.suncoast.systems); additionally allows localhost loopback origins only when the request hostname has a dev subdomain label.
  • Uses bearer-token passthrough only:
    • HTTP GraphQL requests (GET/POST) require Authorization: Bearer ...; missing/invalid bearer headers return 401 Not authorized.
    • WebSocket upgrade handshakes are allowed without Authorization so browser clients can connect; upstream GraphQL must enforce token auth during connection_init.
    • Valid Authorization: Bearer ... headers are forwarded to upstream unchanged.
  • Forwards client IP metadata to upstream using Cloudflare-trusted source only:
    • Reads only CF-Connecting-IP from the Cloudflare edge request.
    • Ignores inbound X-Forwarded-For, Forwarded, X-Real-IP, and True-Client-IP values from clients.
    • Sends normalized IP via X-Client-IP, X-Real-IP, CF-Connecting-IP, True-Client-IP, X-Forwarded-For, and Forwarded.
  • Provides edge caching for unauthenticated query operations.

Cache Rules

  • Cache is enabled by default and controlled via env vars.
  • Only query operations are cache candidates.
  • Requests with Authorization or Cookie are 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, or Cache-Control: no-store are not cached.
  • By default, GraphQL responses containing errors are not cached (CACHE_INCLUDE_GRAPHQL_ERRORS=false).
  • WebSocket upgrade requests are always bypassed from cache and returned as raw upgraded responses.

Worker Env Bindings

  • UPSTREAM_GRAPHQL_URL: full upstream GraphQL URL.
    • By default this is generated by Terraform from a managed proxied upstream DNS record.
    • If MANAGE_UPSTREAM_DNS_RECORD=false, supply UPSTREAM_GRAPHQL_URL directly.
  • UPSTREAM_TIMEOUT_MS (optional, default 60000): timeout for upstream GraphQL request before returning 504 (also used for WebSocket handshake timeout).
  • UPSTREAM_DIRECTUS_ASSET_BASE_URL (optional): base URL used for /directus/assets/* passthrough. If omitted and MANAGE_UPSTREAM_DNS_RECORD=true, defaults to https://<UPSTREAM_DNS_NAME>.<domain>.
  • UPSTREAM_DIRECTUS_ASSET_PATH (default /assets): upstream path prefix appended to UPSTREAM_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 like https://*.suncoast.systems or *.suncoast.systems.
    • Terraform sets this from ALLOWED_HOSTS and automatically appends *.${domain}.
  • CACHE_ENABLED (default true).
  • CACHE_TTL_SECONDS (default 60).
  • CACHE_STALE_WHILE_REVALIDATE_SECONDS (default 30).
  • CACHE_INCLUDE_GRAPHQL_ERRORS (default false).

Terraform Upstream DNS

  • MANAGE_UPSTREAM_DNS_RECORD (default true): create and manage a proxied Cloudflare DNS record for upstream GraphQL.
  • UPSTREAM_SHARED_OWNER_ENVIRONMENT (default dev): only this environment manages shared upstream DNS+tunnel resources to avoid duplicate create errors across dev/prod.
  • UPSTREAM_DNS_NAME (default graphql-origin): relative DNS label in your zone.
  • UPSTREAM_TUNNEL_ID (default 69517d80-2079-43f1-97f7-cfd716298c50): when set, managed DNS is a proxied CNAME to <UPSTREAM_TUNNEL_ID>.cfargotunnel.com.
  • UPSTREAM_ORIGIN_IP (default 64.251.17.245): fallback origin IPv4 when UPSTREAM_TUNNEL_ID is empty (managed DNS is proxied A).
  • UPSTREAM_GRAPHQL_PATH (default /v1/graphql): path appended to managed hostname.
  • UPSTREAM_GRAPHQL_URL: only used when MANAGE_UPSTREAM_DNS_RECORD=false.

Terraform Tunnel Config (Optional)

  • MANAGE_UPSTREAM_TUNNEL_CONFIG (default true): manage tunnel ingress config for UPSTREAM_DNS_NAME.
  • UPSTREAM_TUNNEL_SERVICE (default http://hasura.graphql.svc.cluster.local:8080): origin service URL tunnel should route to (for example http://apisix.gateway.svc.cluster.local:80).
  • Uses cloudflare_zero_trust_tunnel_cloudflared_config and defines:
    • ingress rule for ${UPSTREAM_DNS_NAME}.${domain} -> UPSTREAM_TUNNEL_SERVICE
    • catch-all http_status:404 rule
  • Important: this resource manages the tunnel's ingress config for that tunnel id. Use a dedicated tunnel if other hostname rules are managed elsewhere.
  • Shared ownership: only the workspace where environment == UPSTREAM_SHARED_OWNER_ENVIRONMENT creates/updates this shared tunnel config.

Health Check

  • GET /healthz returns proxy health and version.
  • GET /upstream-probe performs a direct probe to UPSTREAM_GRAPHQL_URL and returns reachability/latency/status diagnostics.

About

Suncoast systems Cloudflare GraphQL proxy

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors