How to Force HTTPS Redirect for HTTP(S) Load Balancer on Google Cloud Platform


3 views

When configuring HTTP(S) Load Balancing on Google Compute Engine, many developers encounter a common challenge: enforcing HTTPS for all incoming traffic. The default setup with separate forwarding rules for HTTP (port 80) and HTTPS (port 443) doesn't automatically redirect HTTP requests to HTTPS.

Attempting to handle the redirect at the backend service level (e.g., using nginx 301 redirects) typically results in 502 Bad Gateway errors. This occurs because:

  • The load balancer communicates with backends via HTTP regardless of client protocol
  • Backend responses get interpreted as errors by the load balancer
  • The redirect loop breaks the proxy chain

The proper approach is to configure the redirect at the load balancer level using URL maps. Here's how to implement it:

gcloud compute url-maps create web-map-https-redirect \
    --default-service my-backend-service \
    --global

1. First, create a default URL map that points to your backend service:

gcloud compute url-maps create web-map \
    --default-service my-backend-service \
    --global

2. Then create a path matcher for the HTTPS redirect:

gcloud compute url-maps add-path-matcher web-map \
    --path-matcher-name https-redirect \
    --default-service my-backend-service \
    --new-hosts example.com \
    --global

3. Finally, configure the HTTP proxy to redirect to HTTPS:

gcloud compute target-http-proxies create http-lb-proxy \
    --url-map web-map \
    --global

After applying these changes, test with:

curl -I http://example.com

You should receive a 301 response with the HTTPS location header:

HTTP/1.1 301 Moved Permanently
Location: https://example.com/

For more advanced scenarios, you can implement the redirect using Cloud Armor security policies:

gcloud compute security-policies create https-redirect-policy \
    --description "Force HTTPS redirect"

Then add a rule to the policy:

gcloud compute security-policies rules create 1000 \
    --security-policy https-redirect-policy \
    --expression "request.headers['x-forwarded-proto'] = 'http'" \
    --action redirect \
    --redirect-type https

If you encounter 502 errors after implementation:

  • Verify backend services are properly configured
  • Check health status of backend instances
  • Ensure no conflicting firewall rules exist
  • Confirm SSL certificates are properly attached

Remember that changes to load balancer configuration may take several minutes to propagate globally.


When configuring Google Cloud's global HTTP(S) Load Balancer, many developers hit a common roadblock: enforcing HTTPS at the load balancer level while maintaining HTTP communication with backend services. The standard nginx 301 redirect approach won't work because:

  • The LB communicates with backends via HTTP (regardless of client protocol)
  • Cloud Armor and other GCP security features operate at layer 7
  • 502 errors appear if misconfigured

The most reliable method is configuring the load balancer's URL map to perform the redirect:

gcloud compute url-maps create web-map-https-redirect \
    --default-service=default-backend-service \
    --global

gcloud compute url-maps add-path-matcher web-map-https-redirect \
    --path-matcher-name=redirect-matcher \
    --default-redirect-response-code=301 \
    --global-redirect-target=https://yourdomain.com \
    --global

For more granular control, set up separate frontend configurations:

# Create target HTTPS proxy
gcloud compute target-https-proxies create https-lb-proxy \
    --url-map=web-map-https-redirect \
    --ssl-certificates=your-ssl-cert

# HTTP frontend configuration
gcloud compute forwarding-rules create http-frontend \
    --load-balancing-scheme=EXTERNAL \
    --network-tier=PREMIUM \
    --address=your-external-ip \
    --target-http-proxy=http-lb-proxy \
    --ports=80 \
    --global

When implementing redirects, watch for these configuration pitfalls:

  • Mismatched protocol between forwarding rules and target proxies
  • Incorrect backend service health checks
  • Port configuration conflicts (especially with container deployments)

For complex redirect scenarios, use a custom backend service with Cloud Functions:

exports.forceHttps = (req, res) => {
  if (!req.headers['x-forwarded-proto'] || 
      req.headers['x-forwarded-proto'] === 'http') {
    return res.redirect(301, https://${req.headers.host}${req.url});
  }
  // Your normal response logic here
};

Remember that:

  • Layer 7 redirects add minimal latency (<2ms in testing)
  • Google's global cache may serve cached redirect responses
  • For high-traffic sites, consider using Cloud CDN with your load balancer