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_IDStep 2: Create Backend Service
gcloud compute backend-services create ${SERVICE_NAME}-backend \
--load-balancing-scheme=EXTERNAL_MANAGED \
--global \
--project=$PROJECT_IDStep 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_IDStep 4: Create URL Map
gcloud compute url-maps create ${SERVICE_NAME}-urlmap \
--default-service=${SERVICE_NAME}-backend \
--global \
--project=$PROJECT_IDStep 5: Create Managed SSL Certificate
export DOMAIN="docs.hrms.bluewoo.com"
gcloud compute ssl-certificates create ${SERVICE_NAME}-cert \
--domains=$DOMAIN \
--global \
--project=$PROJECT_IDNote: 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_IDStep 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_IDStep 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_IDStep 9: Configure DNS
Add an A record in your DNS provider (GoDaddy, Namecheap, etc.):
| Type | Name | Value | TTL |
|---|---|---|---|
| A | docs.hrms | 34.8.128.20 | 1 Hour |
# Verify DNS propagation
dig docs.hrms.bluewoo.com
# Should return:
# docs.hrms.bluewoo.com. 3600 IN A 34.8.128.20Step 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_IDVerification
# 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
| Component | Monthly Cost |
|---|---|
| Load Balancer (forwarding rules) | ~$18 |
| Static IP | ~$3 (if unused) |
| SSL Certificate | Free (managed) |
| Total | ~$18-21/month |
Troubleshooting
SSL Certificate Stuck in PROVISIONING
- Verify DNS A record points to Load Balancer IP
- Wait up to 24 hours for propagation
- Check certificate status:
gcloud compute ssl-certificates describe hrms-docs-cert --global
403 Forbidden
-
Ensure Cloud Run allows public access:
gcloud run services add-iam-policy-binding hrms-docs \ --region=europe-west6 \ --member="allUsers" \ --role="roles/run.invoker" -
If org policy blocks allUsers, reset it:
gcloud org-policies reset iam.allowedPolicyMemberDomains \ --project=bluewoo-hrms
502 Bad Gateway
- Check Cloud Run service is healthy
- Verify NEG is correctly linked
- Check backend service health
Status: Verified and deployed to production