Skip to main content

GCP Load Balancer & SuperTokens Infrastructure Setup

This document describes the complete infrastructure setup for ChainAlign's production environment on GCP, including Cloud Load Balancing with path-based routing and SuperTokens authentication.

Overview

ChainAlign uses a multi-layer architecture:

Browser → Cloudflare (CDN/Proxy)
→ GCP External Load Balancer
→ Cloud Run Services (Frontend/Backend)
→ SuperTokens Core (Auth)
→ Supabase PostgreSQL (Data)

1. Domain & DNS Configuration

Domain: d135.chainalign.com

  • DNS Provider: Cloudflare
  • Record Type: CNAME/Proxy
  • Target: GCP Load Balancer IP (136.110.204.68)
  • Cloudflare Proxy: Enabled (orange cloud)
  • SSL: Full (strict) between Cloudflare and GCP origin

Verify DNS:

dig d135.chainalign.com +short
# Returns Cloudflare proxy IPs (104.21.x.x, 172.67.x.x)

2. GCP Load Balancer Architecture

2.1 External IP Address

gcloud compute forwarding-rules list --project=opspilot-865d9
# NAME IP_ADDRESS TARGET
# d135-frontend-https-rule 136.110.204.68 d135-frontend-https-proxy

2.2 HTTPS Proxy

gcloud compute target-https-proxies describe d135-frontend-https-proxy \
--project=opspilot-865d9

SSL Certificate: cloudflare-origin-cert

  • Type: Self-managed
  • Valid until: 2040-11-07
  • Used for Cloudflare-to-GCP communication (Full SSL)

2.3 URL Map (Path-Based Routing)

Name: d135-frontend-lb

gcloud compute url-maps describe d135-frontend-lb \
--project=opspilot-865d9 --format=yaml

Routing Rules:

Path PatternBackend ServiceTarget
/api/*chainalign-backend-bsBackend Cloud Run
/auth/*chainalign-backend-bsBackend Cloud Run (SuperTokens)
/* (default)d135-frontend-backendFrontend Cloud Run

2.4 Backend Services

Frontend Backend Service

gcloud compute backend-services describe d135-frontend-backend \
--global --project=opspilot-865d9
  • Protocol: HTTP
  • NEG: d135-frontend-neg
  • Cloud Run Service: chainalign-frontend

Backend API Service

gcloud compute backend-services describe chainalign-backend-bs \
--global --project=opspilot-865d9
  • Protocol: HTTP
  • NEG: chainalign-backend-neg
  • Cloud Run Service: chainalign-backend

2.5 Network Endpoint Groups (NEGs)

gcloud compute network-endpoint-groups list --project=opspilot-865d9
# NAME LOCATION ENDPOINT_TYPE SIZE
# d135-frontend-neg us-central1 SERVERLESS 0
# chainalign-backend-neg us-central1 SERVERLESS 0

Both are Serverless NEGs that automatically connect to Cloud Run services.


3. Cloud Run Configuration

3.1 Backend Service

Service URL: https://chainalign-backend-657144924568.us-central1.run.app

Ingress Settings:

gcloud run services describe chainalign-backend \
--region=us-central1 --project=opspilot-865d9 \
--format="value(metadata.annotations['run.googleapis.com/ingress'])"
# Output: internal-and-cloud-load-balancing

IAM Policy:

gcloud run services get-iam-policy chainalign-backend \
--region=us-central1 --project=opspilot-865d9
# Binding: allUsers → roles/run.invoker

This allows:

  • ✅ Load Balancer to invoke the service
  • ✅ Internal GCP services to invoke
  • ❌ Direct public access (blocked by ingress setting)

Environment Variables:

SUPERTOKENS_CONNECTION_URI=https://chainalign-supertokens-tvfzibzoyq-uc.a.run.app
SUPERTOKENS_API_DOMAIN=https://d135.chainalign.com
SUPERTOKENS_WEBSITE_DOMAIN=https://d135.chainalign.com

3.2 Frontend Service

Service URL: https://chainalign-frontend-tvfzibzoyq-uc.a.run.app

Ingress: internal-and-cloud-load-balancing

3.3 SuperTokens Core Service

Service URL: https://chainalign-supertokens-tvfzibzoyq-uc.a.run.app

Database Connection:

postgresql://postgres:<password>@db.vflqqrqbmjzncwkuvqvc.supabase.co:5432/postgres?currentSchema=supertokens

API Key: Stored in GCP Secret Manager as SUPERTOKENS_API_KEY


4. SuperTokens Authentication Setup

4.1 Architecture

Frontend Browser
↓ (HTTPS)
Load Balancer (/auth/*)

Backend Cloud Run (SuperTokens SDK)
↓ (HTTPS)
SuperTokens Core (Cloud Run)
↓ (PostgreSQL)
Supabase Database (supertokens schema)

4.2 Frontend Configuration

File: frontend/src/config/supertokens.js

const superTokensConfig = {
appInfo: {
appName: 'ChainAlign',
apiDomain: 'https://d135.chainalign.com', // Load Balancer URL
websiteDomain: 'https://d135.chainalign.com', // Same origin
apiBasePath: '/auth',
websiteBasePath: '/auth'
},
recipeList: [
Session.init(),
ThirdPartyEmailPassword.init(),
],
};

4.3 Backend Configuration

File: backend/src/services/ChainAlignAuth.js

supertokens.init({
framework: 'express',
supertokens: {
connectionURI: process.env.SUPERTOKENS_CONNECTION_URI,
apiKey: process.env.SUPERTOKENS_API_KEY
},
appInfo: {
appName: 'ChainAlign',
apiDomain: process.env.SUPERTOKENS_API_DOMAIN, // d135.chainalign.com
websiteDomain: process.env.SUPERTOKENS_WEBSITE_DOMAIN,
apiBasePath: '/auth',
websiteBasePath: '/auth'
},
// ... recipes
});

4.4 Database Schema (Supabase)

Schema: supertokens (33 tables)

Key Tables:

  • emailpassword_users - User credentials
  • all_auth_recipe_users - All users across recipes
  • session_info - Active sessions
  • emailpassword_user_to_tenant - Multi-tenant user mapping

Application Tables (public schema):

  • tenant_users - ChainAlign tenant-user mapping with roles
  • tenants - ChainAlign tenants

4.5 Creating a New User

Method 1: Via Frontend UI Navigate to https://d135.chainalign.com/auth/signup

Method 2: Direct Database Insert

DO $$
DECLARE
v_user_id VARCHAR(36) := gen_random_uuid()::text;
v_email VARCHAR(255) := 'user@example.com';
v_password_hash VARCHAR(255) := '$2b$10$...'; -- bcrypt hash
v_time_joined BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000;
v_tenant_uuid UUID := '11111111-1111-1111-1111-111111111111';
BEGIN
-- 1. SuperTokens app_id_to_user_id
INSERT INTO supertokens.app_id_to_user_id (app_id, user_id, recipe_id)
VALUES ('public', v_user_id, 'emailpassword');

-- 2. SuperTokens all_auth_recipe_users
INSERT INTO supertokens.all_auth_recipe_users
(app_id, tenant_id, user_id, recipe_id, time_joined)
VALUES ('public', 'public', v_user_id, 'emailpassword', v_time_joined);

-- 3. SuperTokens emailpassword_users
INSERT INTO supertokens.emailpassword_users
(app_id, user_id, email, password_hash, time_joined)
VALUES ('public', v_user_id, v_email, v_password_hash, v_time_joined);

-- 4. SuperTokens emailpassword_user_to_tenant
INSERT INTO supertokens.emailpassword_user_to_tenant
(app_id, tenant_id, user_id, email)
VALUES ('public', 'public', v_user_id, v_email);

-- 5. ChainAlign tenant_users (with roles)
INSERT INTO public.tenant_users
(supertokens_user_id, tenant_id, user_email, roles)
VALUES (v_user_id, v_tenant_uuid, v_email, ARRAY['admin']);
END $$;

Generate bcrypt hash:

node -e "console.log(require('bcrypt').hashSync('your-password', 10))"

5. Security Considerations

5.1 Network Security

ServiceIngressIAM PolicyDirect Access
Backendinternal-and-cloud-load-balancingallUsers (invoker)❌ Blocked
Frontendinternal-and-cloud-load-balancingallUsers (invoker)❌ Blocked
SuperTokensinternalNone (via service account)❌ Blocked

5.2 Authentication Flow

  1. User visits d135.chainalign.com
  2. Cloudflare terminates HTTPS, proxies to GCP LB
  3. Load Balancer routes /auth/* to backend
  4. Backend SuperTokens SDK validates credentials
  5. SuperTokens Core checks against Supabase DB
  6. Session tokens returned via HTTP-only cookies
  7. Subsequent requests include session tokens automatically

5.3 CORS Configuration

Since frontend and backend share the same origin (d135.chainalign.com), CORS is not an issue. This is a major benefit of the Load Balancer setup.


6. Maintenance & Operations

6.1 Viewing Logs

Backend:

gcloud logging read 'resource.type="cloud_run_revision" AND \
resource.labels.service_name="chainalign-backend"' \
--project=opspilot-865d9 --limit=50

SuperTokens:

gcloud logging read 'resource.type="cloud_run_revision" AND \
resource.labels.service_name="chainalign-supertokens"' \
--project=opspilot-865d9 --limit=50

6.2 Updating Services

Update backend environment variables:

gcloud run services update chainalign-backend \
--region=us-central1 \
--project=opspilot-865d9 \
--update-env-vars "KEY=value"

Update ingress (emergency public access):

gcloud run services update chainalign-backend \
--region=us-central1 \
--project=opspilot-865d9 \
--ingress=all # DANGER: Opens to public

6.3 Monitoring Backend Health

# Via Load Balancer
curl -s -o /dev/null -w "%{http_code}" https://d135.chainalign.com/api/health

# Should return 200 or 401 (auth required) - not 404/502/503

6.4 Rotating SuperTokens API Key

  1. Generate new key in SuperTokens Core
  2. Update GCP Secret Manager: SUPERTOKENS_API_KEY
  3. Redeploy backend service to pick up new secret

7. Troubleshooting

7.1 "Something went wrong" on login page

Cause: Frontend can't reach backend API

Check:

  1. Load Balancer routing: curl https://d135.chainalign.com/auth/signin
  2. Backend ingress allows LB: Should be internal-and-cloud-load-balancing
  3. Backend IAM has allUsers: gcloud run services get-iam-policy...

7.2 401 Unauthorized on API calls

Expected for: Unauthenticated requests (healthy sign!)

Check for public endpoints:

// backend/server.js
const publicAuthPaths = [
'/api/internal/v1/auth/exchange',
'/api/internal/v1/auth/signup',
'/api/internal/v1/auth/signin'
];

7.3 SuperTokens Core not responding

Check service status:

gcloud run services describe chainalign-supertokens \
--region=us-central1 --project=opspilot-865d9 \
--format="yaml(status.conditions)"

Check database connectivity:

gcloud logging read '... AND "Pool stats"' --limit=5
# Should show: total=10, active=0, idle=10

7.4 CloudBuild not updating services

Verify trigger:

gcloud builds list --project=opspilot-865d9 --region=us-central1 --limit=5

Check image digest matches:

gcloud run revisions describe <revision-name> \
--region=us-central1 --project=opspilot-865d9 \
--format="value(spec.containers[0].image)"

8. Important URLs & Credentials

Production Environment (d135)

ResourceURL/Value
Frontendhttps://d135.chainalign.com
APIhttps://d135.chainalign.com/api/*
Authhttps://d135.chainalign.com/auth/*
Load Balancer IP136.110.204.68
Supabase Hostdb.vflqqrqbmjzncwkuvqvc.supabase.co
SuperTokens Schemasupertokens
App Schemapublic

GCP Resources

ResourceNameRegion
URL Mapd135-frontend-lbglobal
HTTPS Proxyd135-frontend-https-proxyglobal
Frontend Backend Serviced135-frontend-backendglobal
Backend API Servicechainalign-backend-bsglobal
Frontend NEGd135-frontend-negus-central1
Backend NEGchainalign-backend-negus-central1
SSL Certificatecloudflare-origin-certglobal

Secret Manager Keys

  • SUPERTOKENS_API_KEY - SuperTokens Core API key
  • SUPABASE_PASSWORD - Database password
  • GEMINI_API_KEY - AI service key

9. Future Considerations

9.1 Identity-Aware Proxy (IAP)

Current setup uses SuperTokens for app-level auth. For additional security layer:

# Enable IAP on backend service
gcloud iap web enable \
--resource-type=compute \
--service=chainalign-backend-bs \
--project=opspilot-865d9

# Add authorized users
gcloud iap web add-iam-policy-binding \
--resource-type=compute \
--service=chainalign-backend-bs \
--member="user:admin@chainalign.com" \
--role="roles/iap.httpsResourceAccessor" \
--project=opspilot-865d9

9.2 Rate Limiting

Configure via Cloud Armor security policies attached to backend services.

9.3 Custom Domains

To add more domains (e.g., app.chainalign.com):

  1. Add SSL certificate
  2. Update URL map host rules
  3. Configure Cloudflare DNS

10. Change Log

DateChangeAuthor
2025-11-17Initial Load Balancer setup with backend routingClaude Code
2025-11-17SuperTokens Core configured with SupabaseClaude Code
2025-11-17Path-based routing for /api/* and /auth/*Claude Code

Document Version: 1.0 Last Updated: 2025-11-17 Environment: D135 (Pre-production)