Bluewoo HRMS
Deployment

Load Balancer Setup

Global Load Balancer with custom domain and managed SSL

Load Balancer Setup

This guide covers setting up a Global External Load Balancer for Cloud Run services with custom domains and managed SSL certificates.

Why Load Balancer?

Cloud Run domain mapping is not available in all regions (including europe-west6). The Load Balancer approach provides:

  • ✅ Works with any Cloud Run region
  • ✅ Managed SSL certificates
  • ✅ Global anycast IP
  • ✅ CDN capabilities (optional)
  • ✅ Better for production workloads

Architecture

User Request


┌─────────────────────────────────────────────────────────────┐
│                  Global Load Balancer                        │
│                                                              │
│  Static IP: 34.8.128.20                                     │
│  Domain: docs.hrms.bluewoo.com                              │
│                                                              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐  │
│  │ SSL Cert     │  │ HTTPS Proxy  │  │ URL Map          │  │
│  │ (managed)    │→ │              │→ │                  │  │
│  └──────────────┘  └──────────────┘  └────────┬─────────┘  │
│                                                │             │
│                                    ┌───────────▼──────────┐ │
│                                    │ Backend Service      │ │
│                                    │ (hrms-docs-backend)  │ │
│                                    └───────────┬──────────┘ │
└────────────────────────────────────────────────│────────────┘

                                    ┌────────────▼───────────┐
                                    │ Serverless NEG         │
                                    │ (hrms-docs-neg)        │
                                    └────────────┬───────────┘

                                    ┌────────────▼───────────┐
                                    │ Cloud Run              │
                                    │ (hrms-docs)            │
                                    │ europe-west6           │
                                    └────────────────────────┘

Prerequisites

  • Cloud Run service deployed
  • Compute Engine API enabled
  • Domain ownership verified in Google Search Console

Step 1: Create Serverless NEG

A Network Endpoint Group connects the Load Balancer to Cloud Run.

export PROJECT_ID="bluewoo-hrms"
export REGION="europe-west6"
export SERVICE_NAME="hrms-docs"

gcloud compute network-endpoint-groups create ${SERVICE_NAME}-neg \
  --region=$REGION \
  --network-endpoint-type=serverless \
  --cloud-run-service=$SERVICE_NAME \
  --project=$PROJECT_ID

Step 2: Create Backend Service

gcloud compute backend-services create ${SERVICE_NAME}-backend \
  --load-balancing-scheme=EXTERNAL_MANAGED \
  --global \
  --project=$PROJECT_ID

Step 3: Add NEG to Backend

gcloud compute backend-services add-backend ${SERVICE_NAME}-backend \
  --global \
  --network-endpoint-group=${SERVICE_NAME}-neg \
  --network-endpoint-group-region=$REGION \
  --project=$PROJECT_ID

Step 4: Create URL Map

gcloud compute url-maps create ${SERVICE_NAME}-urlmap \
  --default-service=${SERVICE_NAME}-backend \
  --global \
  --project=$PROJECT_ID

Step 5: Create Managed SSL Certificate

export DOMAIN="docs.hrms.bluewoo.com"

gcloud compute ssl-certificates create ${SERVICE_NAME}-cert \
  --domains=$DOMAIN \
  --global \
  --project=$PROJECT_ID

Note: Certificate provisioning completes after DNS is configured (Step 8).


Step 6: Create HTTPS Proxy

gcloud compute target-https-proxies create ${SERVICE_NAME}-https-proxy \
  --ssl-certificates=${SERVICE_NAME}-cert \
  --url-map=${SERVICE_NAME}-urlmap \
  --global \
  --project=$PROJECT_ID

Step 7: Reserve Static IP and Create Forwarding Rule

# Reserve static IP
gcloud compute addresses create ${SERVICE_NAME}-ip \
  --network-tier=PREMIUM \
  --ip-version=IPV4 \
  --global \
  --project=$PROJECT_ID

# Get the IP address
IP=$(gcloud compute addresses describe ${SERVICE_NAME}-ip \
  --global \
  --project=$PROJECT_ID \
  --format="value(address)")

echo "Load Balancer IP: $IP"

# Create HTTPS forwarding rule
gcloud compute forwarding-rules create ${SERVICE_NAME}-https-rule \
  --load-balancing-scheme=EXTERNAL_MANAGED \
  --network-tier=PREMIUM \
  --address=${SERVICE_NAME}-ip \
  --target-https-proxy=${SERVICE_NAME}-https-proxy \
  --ports=443 \
  --global \
  --project=$PROJECT_ID

Step 8: Add HTTP to HTTPS Redirect

# Create redirect URL map
gcloud compute url-maps import ${SERVICE_NAME}-http-redirect \
  --global \
  --project=$PROJECT_ID \
  --source /dev/stdin <<EOF
name: ${SERVICE_NAME}-http-redirect
defaultUrlRedirect:
  redirectResponseCode: MOVED_PERMANENTLY_DEFAULT
  httpsRedirect: true
EOF

# Create HTTP proxy
gcloud compute target-http-proxies create ${SERVICE_NAME}-http-proxy \
  --url-map=${SERVICE_NAME}-http-redirect \
  --global \
  --project=$PROJECT_ID

# Create HTTP forwarding rule
gcloud compute forwarding-rules create ${SERVICE_NAME}-http-rule \
  --load-balancing-scheme=EXTERNAL_MANAGED \
  --network-tier=PREMIUM \
  --address=${SERVICE_NAME}-ip \
  --target-http-proxy=${SERVICE_NAME}-http-proxy \
  --ports=80 \
  --global \
  --project=$PROJECT_ID

Step 9: Configure DNS

Add an A record in your DNS provider (GoDaddy, Namecheap, etc.):

TypeNameValueTTL
Adocs.hrms34.8.128.201 Hour
# Verify DNS propagation
dig docs.hrms.bluewoo.com

# Should return:
# docs.hrms.bluewoo.com. 3600 IN A 34.8.128.20

Step 10: Allow Public Access to Cloud Run

gcloud run services add-iam-policy-binding $SERVICE_NAME \
  --region=$REGION \
  --member="allUsers" \
  --role="roles/run.invoker" \
  --project=$PROJECT_ID

Verification

# Check SSL certificate status
gcloud compute ssl-certificates describe ${SERVICE_NAME}-cert \
  --global \
  --project=$PROJECT_ID \
  --format="table(name,managed.status,managed.domainStatus)"

# Expected output:
# NAME            STATUS  DOMAIN_STATUS
# hrms-docs-cert  ACTIVE  {'docs.hrms.bluewoo.com': 'ACTIVE'}

# Test the site
curl -sI https://docs.hrms.bluewoo.com | head -5

# Expected output:
# HTTP/2 200 
# ...

Complete Setup Script

#!/bin/bash
set -e

export PROJECT_ID="bluewoo-hrms"
export REGION="europe-west6"
export SERVICE_NAME="hrms-docs"
export DOMAIN="docs.hrms.bluewoo.com"

echo "Creating Serverless NEG..."
gcloud compute network-endpoint-groups create ${SERVICE_NAME}-neg \
  --region=$REGION \
  --network-endpoint-type=serverless \
  --cloud-run-service=$SERVICE_NAME \
  --project=$PROJECT_ID

echo "Creating Backend Service..."
gcloud compute backend-services create ${SERVICE_NAME}-backend \
  --load-balancing-scheme=EXTERNAL_MANAGED \
  --global \
  --project=$PROJECT_ID

echo "Adding NEG to Backend..."
gcloud compute backend-services add-backend ${SERVICE_NAME}-backend \
  --global \
  --network-endpoint-group=${SERVICE_NAME}-neg \
  --network-endpoint-group-region=$REGION \
  --project=$PROJECT_ID

echo "Creating URL Map..."
gcloud compute url-maps create ${SERVICE_NAME}-urlmap \
  --default-service=${SERVICE_NAME}-backend \
  --global \
  --project=$PROJECT_ID

echo "Creating SSL Certificate..."
gcloud compute ssl-certificates create ${SERVICE_NAME}-cert \
  --domains=$DOMAIN \
  --global \
  --project=$PROJECT_ID

echo "Creating HTTPS Proxy..."
gcloud compute target-https-proxies create ${SERVICE_NAME}-https-proxy \
  --ssl-certificates=${SERVICE_NAME}-cert \
  --url-map=${SERVICE_NAME}-urlmap \
  --global \
  --project=$PROJECT_ID

echo "Reserving Static IP..."
gcloud compute addresses create ${SERVICE_NAME}-ip \
  --network-tier=PREMIUM \
  --ip-version=IPV4 \
  --global \
  --project=$PROJECT_ID

IP=$(gcloud compute addresses describe ${SERVICE_NAME}-ip \
  --global --project=$PROJECT_ID --format="value(address)")

echo "Creating HTTPS Forwarding Rule..."
gcloud compute forwarding-rules create ${SERVICE_NAME}-https-rule \
  --load-balancing-scheme=EXTERNAL_MANAGED \
  --network-tier=PREMIUM \
  --address=${SERVICE_NAME}-ip \
  --target-https-proxy=${SERVICE_NAME}-https-proxy \
  --ports=443 \
  --global \
  --project=$PROJECT_ID

echo ""
echo "=========================================="
echo "Load Balancer IP: $IP"
echo ""
echo "Add this A record to your DNS:"
echo "  Type: A"
echo "  Name: docs.hrms"
echo "  Value: $IP"
echo "=========================================="

Cost Estimate

ComponentMonthly Cost
Load Balancer (forwarding rules)~$18
Static IP~$3 (if unused)
SSL CertificateFree (managed)
Total~$18-21/month

Troubleshooting

SSL Certificate Stuck in PROVISIONING

  1. Verify DNS A record points to Load Balancer IP
  2. Wait up to 24 hours for propagation
  3. Check certificate status:
    gcloud compute ssl-certificates describe hrms-docs-cert --global

403 Forbidden

  1. Ensure Cloud Run allows public access:

    gcloud run services add-iam-policy-binding hrms-docs \
      --region=europe-west6 \
      --member="allUsers" \
      --role="roles/run.invoker"
  2. If org policy blocks allUsers, reset it:

    gcloud org-policies reset iam.allowedPolicyMemberDomains \
      --project=bluewoo-hrms

502 Bad Gateway

  1. Check Cloud Run service is healthy
  2. Verify NEG is correctly linked
  3. Check backend service health

Status: Verified and deployed to production