Configure GCP Global HTTP Load Balancing Rules

The gcp:compute/globalForwardingRule:GlobalForwardingRule resource, part of the Pulumi GCP provider, defines the entry point for global load balancers: the IP address, port, and target that receives incoming traffic. This guide focuses on three capabilities: HTTP load balancing with target proxies, internal self-managed routing for service mesh, and Private Service Connect to Google APIs.

Forwarding rules sit at the front of load balancing architectures, directing traffic to target proxies, URL maps, and backend services. The examples are intentionally small. Combine them with your own backend infrastructure, health checks, and routing configuration.

Route HTTP traffic to a target proxy

Most HTTP load balancers start by creating a forwarding rule that accepts traffic on port 80 and directs it to a target proxy.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
    name: "check-backend",
    requestPath: "/",
    checkIntervalSec: 1,
    timeoutSec: 1,
});
const defaultBackendService = new gcp.compute.BackendService("default", {
    name: "backend",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    healthChecks: defaultHttpHealthCheck.id,
});
const defaultURLMap = new gcp.compute.URLMap("default", {
    name: "url-map-target-proxy",
    description: "a description",
    defaultService: defaultBackendService.id,
    hostRules: [{
        hosts: ["mysite.com"],
        pathMatcher: "allpaths",
    }],
    pathMatchers: [{
        name: "allpaths",
        defaultService: defaultBackendService.id,
        pathRules: [{
            paths: ["/*"],
            service: defaultBackendService.id,
        }],
    }],
});
const defaultTargetHttpProxy = new gcp.compute.TargetHttpProxy("default", {
    name: "target-proxy",
    description: "a description",
    urlMap: defaultURLMap.id,
});
const _default = new gcp.compute.GlobalForwardingRule("default", {
    name: "global-rule",
    target: defaultTargetHttpProxy.id,
    portRange: "80",
});
import pulumi
import pulumi_gcp as gcp

default_http_health_check = gcp.compute.HttpHealthCheck("default",
    name="check-backend",
    request_path="/",
    check_interval_sec=1,
    timeout_sec=1)
default_backend_service = gcp.compute.BackendService("default",
    name="backend",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    health_checks=default_http_health_check.id)
default_url_map = gcp.compute.URLMap("default",
    name="url-map-target-proxy",
    description="a description",
    default_service=default_backend_service.id,
    host_rules=[{
        "hosts": ["mysite.com"],
        "path_matcher": "allpaths",
    }],
    path_matchers=[{
        "name": "allpaths",
        "default_service": default_backend_service.id,
        "path_rules": [{
            "paths": ["/*"],
            "service": default_backend_service.id,
        }],
    }])
default_target_http_proxy = gcp.compute.TargetHttpProxy("default",
    name="target-proxy",
    description="a description",
    url_map=default_url_map.id)
default = gcp.compute.GlobalForwardingRule("default",
    name="global-rule",
    target=default_target_http_proxy.id,
    port_range="80")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
			Name:             pulumi.String("check-backend"),
			RequestPath:      pulumi.String("/"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		defaultBackendService, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:         pulumi.String("backend"),
			PortName:     pulumi.String("http"),
			Protocol:     pulumi.String("HTTP"),
			TimeoutSec:   pulumi.Int(10),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		defaultURLMap, err := compute.NewURLMap(ctx, "default", &compute.URLMapArgs{
			Name:           pulumi.String("url-map-target-proxy"),
			Description:    pulumi.String("a description"),
			DefaultService: defaultBackendService.ID(),
			HostRules: compute.URLMapHostRuleArray{
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("mysite.com"),
					},
					PathMatcher: pulumi.String("allpaths"),
				},
			},
			PathMatchers: compute.URLMapPathMatcherArray{
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("allpaths"),
					DefaultService: defaultBackendService.ID(),
					PathRules: compute.URLMapPathMatcherPathRuleArray{
						&compute.URLMapPathMatcherPathRuleArgs{
							Paths: pulumi.StringArray{
								pulumi.String("/*"),
							},
							Service: defaultBackendService.ID(),
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		defaultTargetHttpProxy, err := compute.NewTargetHttpProxy(ctx, "default", &compute.TargetHttpProxyArgs{
			Name:        pulumi.String("target-proxy"),
			Description: pulumi.String("a description"),
			UrlMap:      defaultURLMap.ID(),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewGlobalForwardingRule(ctx, "default", &compute.GlobalForwardingRuleArgs{
			Name:      pulumi.String("global-rule"),
			Target:    defaultTargetHttpProxy.ID(),
			PortRange: pulumi.String("80"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
    {
        Name = "check-backend",
        RequestPath = "/",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
    });

    var defaultBackendService = new Gcp.Compute.BackendService("default", new()
    {
        Name = "backend",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var defaultURLMap = new Gcp.Compute.URLMap("default", new()
    {
        Name = "url-map-target-proxy",
        Description = "a description",
        DefaultService = defaultBackendService.Id,
        HostRules = new[]
        {
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "mysite.com",
                },
                PathMatcher = "allpaths",
            },
        },
        PathMatchers = new[]
        {
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "allpaths",
                DefaultService = defaultBackendService.Id,
                PathRules = new[]
                {
                    new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
                    {
                        Paths = new[]
                        {
                            "/*",
                        },
                        Service = defaultBackendService.Id,
                    },
                },
            },
        },
    });

    var defaultTargetHttpProxy = new Gcp.Compute.TargetHttpProxy("default", new()
    {
        Name = "target-proxy",
        Description = "a description",
        UrlMap = defaultURLMap.Id,
    });

    var @default = new Gcp.Compute.GlobalForwardingRule("default", new()
    {
        Name = "global-rule",
        Target = defaultTargetHttpProxy.Id,
        PortRange = "80",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.TargetHttpProxy;
import com.pulumi.gcp.compute.TargetHttpProxyArgs;
import com.pulumi.gcp.compute.GlobalForwardingRule;
import com.pulumi.gcp.compute.GlobalForwardingRuleArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
            .name("check-backend")
            .requestPath("/")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .build());

        var defaultBackendService = new BackendService("defaultBackendService", BackendServiceArgs.builder()
            .name("backend")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var defaultURLMap = new URLMap("defaultURLMap", URLMapArgs.builder()
            .name("url-map-target-proxy")
            .description("a description")
            .defaultService(defaultBackendService.id())
            .hostRules(URLMapHostRuleArgs.builder()
                .hosts("mysite.com")
                .pathMatcher("allpaths")
                .build())
            .pathMatchers(URLMapPathMatcherArgs.builder()
                .name("allpaths")
                .defaultService(defaultBackendService.id())
                .pathRules(URLMapPathMatcherPathRuleArgs.builder()
                    .paths("/*")
                    .service(defaultBackendService.id())
                    .build())
                .build())
            .build());

        var defaultTargetHttpProxy = new TargetHttpProxy("defaultTargetHttpProxy", TargetHttpProxyArgs.builder()
            .name("target-proxy")
            .description("a description")
            .urlMap(defaultURLMap.id())
            .build());

        var default_ = new GlobalForwardingRule("default", GlobalForwardingRuleArgs.builder()
            .name("global-rule")
            .target(defaultTargetHttpProxy.id())
            .portRange("80")
            .build());

    }
}
resources:
  default:
    type: gcp:compute:GlobalForwardingRule
    properties:
      name: global-rule
      target: ${defaultTargetHttpProxy.id}
      portRange: '80'
  defaultTargetHttpProxy:
    type: gcp:compute:TargetHttpProxy
    name: default
    properties:
      name: target-proxy
      description: a description
      urlMap: ${defaultURLMap.id}
  defaultURLMap:
    type: gcp:compute:URLMap
    name: default
    properties:
      name: url-map-target-proxy
      description: a description
      defaultService: ${defaultBackendService.id}
      hostRules:
        - hosts:
            - mysite.com
          pathMatcher: allpaths
      pathMatchers:
        - name: allpaths
          defaultService: ${defaultBackendService.id}
          pathRules:
            - paths:
                - /*
              service: ${defaultBackendService.id}
  defaultBackendService:
    type: gcp:compute:BackendService
    name: default
    properties:
      name: backend
      portName: http
      protocol: HTTP
      timeoutSec: 10
      healthChecks: ${defaultHttpHealthCheck.id}
  defaultHttpHealthCheck:
    type: gcp:compute:HttpHealthCheck
    name: default
    properties:
      name: check-backend
      requestPath: /
      checkIntervalSec: 1
      timeoutSec: 1

When a client sends traffic to the forwarding rule’s IP address, the rule directs it to the target proxy specified in the target property. The portRange property defines which port accepts traffic. The target proxy then consults the URL map to route requests to appropriate backend services based on hostname and path.

Configure internal self-managed load balancing

Service mesh deployments need internal load balancing without public IPs, using metadata filters to control routing configuration distribution.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const debianImage = gcp.compute.getImage({
    family: "debian-11",
    project: "debian-cloud",
});
const instanceTemplate = new gcp.compute.InstanceTemplate("instance_template", {
    name: "template-backend",
    machineType: "e2-medium",
    networkInterfaces: [{
        network: "default",
    }],
    disks: [{
        sourceImage: debianImage.then(debianImage => debianImage.selfLink),
        autoDelete: true,
        boot: true,
    }],
});
const igm = new gcp.compute.InstanceGroupManager("igm", {
    name: "igm-internal",
    versions: [{
        instanceTemplate: instanceTemplate.id,
        name: "primary",
    }],
    baseInstanceName: "internal-glb",
    zone: "us-central1-f",
    targetSize: 1,
});
const defaultHealthCheck = new gcp.compute.HealthCheck("default", {
    name: "check-backend",
    checkIntervalSec: 1,
    timeoutSec: 1,
    tcpHealthCheck: {
        port: 80,
    },
});
const defaultBackendService = new gcp.compute.BackendService("default", {
    name: "backend",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    loadBalancingScheme: "INTERNAL_SELF_MANAGED",
    backends: [{
        group: igm.instanceGroup,
        balancingMode: "RATE",
        capacityScaler: 0.4,
        maxRatePerInstance: 50,
    }],
    healthChecks: defaultHealthCheck.id,
});
const defaultURLMap = new gcp.compute.URLMap("default", {
    name: "url-map-target-proxy",
    description: "a description",
    defaultService: defaultBackendService.id,
    hostRules: [{
        hosts: ["mysite.com"],
        pathMatcher: "allpaths",
    }],
    pathMatchers: [{
        name: "allpaths",
        defaultService: defaultBackendService.id,
        pathRules: [{
            paths: ["/*"],
            service: defaultBackendService.id,
        }],
    }],
});
const defaultTargetHttpProxy = new gcp.compute.TargetHttpProxy("default", {
    name: "target-proxy",
    description: "a description",
    urlMap: defaultURLMap.id,
});
const _default = new gcp.compute.GlobalForwardingRule("default", {
    name: "global-rule",
    target: defaultTargetHttpProxy.id,
    portRange: "80",
    loadBalancingScheme: "INTERNAL_SELF_MANAGED",
    ipAddress: "0.0.0.0",
    metadataFilters: [{
        filterMatchCriteria: "MATCH_ANY",
        filterLabels: [{
            name: "PLANET",
            value: "MARS",
        }],
    }],
});
import pulumi
import pulumi_gcp as gcp

debian_image = gcp.compute.get_image(family="debian-11",
    project="debian-cloud")
instance_template = gcp.compute.InstanceTemplate("instance_template",
    name="template-backend",
    machine_type="e2-medium",
    network_interfaces=[{
        "network": "default",
    }],
    disks=[{
        "source_image": debian_image.self_link,
        "auto_delete": True,
        "boot": True,
    }])
igm = gcp.compute.InstanceGroupManager("igm",
    name="igm-internal",
    versions=[{
        "instance_template": instance_template.id,
        "name": "primary",
    }],
    base_instance_name="internal-glb",
    zone="us-central1-f",
    target_size=1)
default_health_check = gcp.compute.HealthCheck("default",
    name="check-backend",
    check_interval_sec=1,
    timeout_sec=1,
    tcp_health_check={
        "port": 80,
    })
default_backend_service = gcp.compute.BackendService("default",
    name="backend",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    load_balancing_scheme="INTERNAL_SELF_MANAGED",
    backends=[{
        "group": igm.instance_group,
        "balancing_mode": "RATE",
        "capacity_scaler": 0.4,
        "max_rate_per_instance": 50,
    }],
    health_checks=default_health_check.id)
default_url_map = gcp.compute.URLMap("default",
    name="url-map-target-proxy",
    description="a description",
    default_service=default_backend_service.id,
    host_rules=[{
        "hosts": ["mysite.com"],
        "path_matcher": "allpaths",
    }],
    path_matchers=[{
        "name": "allpaths",
        "default_service": default_backend_service.id,
        "path_rules": [{
            "paths": ["/*"],
            "service": default_backend_service.id,
        }],
    }])
default_target_http_proxy = gcp.compute.TargetHttpProxy("default",
    name="target-proxy",
    description="a description",
    url_map=default_url_map.id)
default = gcp.compute.GlobalForwardingRule("default",
    name="global-rule",
    target=default_target_http_proxy.id,
    port_range="80",
    load_balancing_scheme="INTERNAL_SELF_MANAGED",
    ip_address="0.0.0.0",
    metadata_filters=[{
        "filter_match_criteria": "MATCH_ANY",
        "filter_labels": [{
            "name": "PLANET",
            "value": "MARS",
        }],
    }])
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		debianImage, err := compute.LookupImage(ctx, &compute.LookupImageArgs{
			Family:  pulumi.StringRef("debian-11"),
			Project: pulumi.StringRef("debian-cloud"),
		}, nil)
		if err != nil {
			return err
		}
		instanceTemplate, err := compute.NewInstanceTemplate(ctx, "instance_template", &compute.InstanceTemplateArgs{
			Name:        pulumi.String("template-backend"),
			MachineType: pulumi.String("e2-medium"),
			NetworkInterfaces: compute.InstanceTemplateNetworkInterfaceArray{
				&compute.InstanceTemplateNetworkInterfaceArgs{
					Network: pulumi.String("default"),
				},
			},
			Disks: compute.InstanceTemplateDiskArray{
				&compute.InstanceTemplateDiskArgs{
					SourceImage: pulumi.String(debianImage.SelfLink),
					AutoDelete:  pulumi.Bool(true),
					Boot:        pulumi.Bool(true),
				},
			},
		})
		if err != nil {
			return err
		}
		igm, err := compute.NewInstanceGroupManager(ctx, "igm", &compute.InstanceGroupManagerArgs{
			Name: pulumi.String("igm-internal"),
			Versions: compute.InstanceGroupManagerVersionArray{
				&compute.InstanceGroupManagerVersionArgs{
					InstanceTemplate: instanceTemplate.ID(),
					Name:             pulumi.String("primary"),
				},
			},
			BaseInstanceName: pulumi.String("internal-glb"),
			Zone:             pulumi.String("us-central1-f"),
			TargetSize:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		defaultHealthCheck, err := compute.NewHealthCheck(ctx, "default", &compute.HealthCheckArgs{
			Name:             pulumi.String("check-backend"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
			TcpHealthCheck: &compute.HealthCheckTcpHealthCheckArgs{
				Port: pulumi.Int(80),
			},
		})
		if err != nil {
			return err
		}
		defaultBackendService, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:                pulumi.String("backend"),
			PortName:            pulumi.String("http"),
			Protocol:            pulumi.String("HTTP"),
			TimeoutSec:          pulumi.Int(10),
			LoadBalancingScheme: pulumi.String("INTERNAL_SELF_MANAGED"),
			Backends: compute.BackendServiceBackendArray{
				&compute.BackendServiceBackendArgs{
					Group:              igm.InstanceGroup,
					BalancingMode:      pulumi.String("RATE"),
					CapacityScaler:     pulumi.Float64(0.4),
					MaxRatePerInstance: pulumi.Float64(50),
				},
			},
			HealthChecks: defaultHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		defaultURLMap, err := compute.NewURLMap(ctx, "default", &compute.URLMapArgs{
			Name:           pulumi.String("url-map-target-proxy"),
			Description:    pulumi.String("a description"),
			DefaultService: defaultBackendService.ID(),
			HostRules: compute.URLMapHostRuleArray{
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("mysite.com"),
					},
					PathMatcher: pulumi.String("allpaths"),
				},
			},
			PathMatchers: compute.URLMapPathMatcherArray{
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("allpaths"),
					DefaultService: defaultBackendService.ID(),
					PathRules: compute.URLMapPathMatcherPathRuleArray{
						&compute.URLMapPathMatcherPathRuleArgs{
							Paths: pulumi.StringArray{
								pulumi.String("/*"),
							},
							Service: defaultBackendService.ID(),
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		defaultTargetHttpProxy, err := compute.NewTargetHttpProxy(ctx, "default", &compute.TargetHttpProxyArgs{
			Name:        pulumi.String("target-proxy"),
			Description: pulumi.String("a description"),
			UrlMap:      defaultURLMap.ID(),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewGlobalForwardingRule(ctx, "default", &compute.GlobalForwardingRuleArgs{
			Name:                pulumi.String("global-rule"),
			Target:              defaultTargetHttpProxy.ID(),
			PortRange:           pulumi.String("80"),
			LoadBalancingScheme: pulumi.String("INTERNAL_SELF_MANAGED"),
			IpAddress:           pulumi.String("0.0.0.0"),
			MetadataFilters: compute.GlobalForwardingRuleMetadataFilterArray{
				&compute.GlobalForwardingRuleMetadataFilterArgs{
					FilterMatchCriteria: pulumi.String("MATCH_ANY"),
					FilterLabels: compute.GlobalForwardingRuleMetadataFilterFilterLabelArray{
						&compute.GlobalForwardingRuleMetadataFilterFilterLabelArgs{
							Name:  pulumi.String("PLANET"),
							Value: pulumi.String("MARS"),
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var debianImage = Gcp.Compute.GetImage.Invoke(new()
    {
        Family = "debian-11",
        Project = "debian-cloud",
    });

    var instanceTemplate = new Gcp.Compute.InstanceTemplate("instance_template", new()
    {
        Name = "template-backend",
        MachineType = "e2-medium",
        NetworkInterfaces = new[]
        {
            new Gcp.Compute.Inputs.InstanceTemplateNetworkInterfaceArgs
            {
                Network = "default",
            },
        },
        Disks = new[]
        {
            new Gcp.Compute.Inputs.InstanceTemplateDiskArgs
            {
                SourceImage = debianImage.Apply(getImageResult => getImageResult.SelfLink),
                AutoDelete = true,
                Boot = true,
            },
        },
    });

    var igm = new Gcp.Compute.InstanceGroupManager("igm", new()
    {
        Name = "igm-internal",
        Versions = new[]
        {
            new Gcp.Compute.Inputs.InstanceGroupManagerVersionArgs
            {
                InstanceTemplate = instanceTemplate.Id,
                Name = "primary",
            },
        },
        BaseInstanceName = "internal-glb",
        Zone = "us-central1-f",
        TargetSize = 1,
    });

    var defaultHealthCheck = new Gcp.Compute.HealthCheck("default", new()
    {
        Name = "check-backend",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
        TcpHealthCheck = new Gcp.Compute.Inputs.HealthCheckTcpHealthCheckArgs
        {
            Port = 80,
        },
    });

    var defaultBackendService = new Gcp.Compute.BackendService("default", new()
    {
        Name = "backend",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        LoadBalancingScheme = "INTERNAL_SELF_MANAGED",
        Backends = new[]
        {
            new Gcp.Compute.Inputs.BackendServiceBackendArgs
            {
                Group = igm.InstanceGroup,
                BalancingMode = "RATE",
                CapacityScaler = 0.4,
                MaxRatePerInstance = 50,
            },
        },
        HealthChecks = defaultHealthCheck.Id,
    });

    var defaultURLMap = new Gcp.Compute.URLMap("default", new()
    {
        Name = "url-map-target-proxy",
        Description = "a description",
        DefaultService = defaultBackendService.Id,
        HostRules = new[]
        {
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "mysite.com",
                },
                PathMatcher = "allpaths",
            },
        },
        PathMatchers = new[]
        {
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "allpaths",
                DefaultService = defaultBackendService.Id,
                PathRules = new[]
                {
                    new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
                    {
                        Paths = new[]
                        {
                            "/*",
                        },
                        Service = defaultBackendService.Id,
                    },
                },
            },
        },
    });

    var defaultTargetHttpProxy = new Gcp.Compute.TargetHttpProxy("default", new()
    {
        Name = "target-proxy",
        Description = "a description",
        UrlMap = defaultURLMap.Id,
    });

    var @default = new Gcp.Compute.GlobalForwardingRule("default", new()
    {
        Name = "global-rule",
        Target = defaultTargetHttpProxy.Id,
        PortRange = "80",
        LoadBalancingScheme = "INTERNAL_SELF_MANAGED",
        IpAddress = "0.0.0.0",
        MetadataFilters = new[]
        {
            new Gcp.Compute.Inputs.GlobalForwardingRuleMetadataFilterArgs
            {
                FilterMatchCriteria = "MATCH_ANY",
                FilterLabels = new[]
                {
                    new Gcp.Compute.Inputs.GlobalForwardingRuleMetadataFilterFilterLabelArgs
                    {
                        Name = "PLANET",
                        Value = "MARS",
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.ComputeFunctions;
import com.pulumi.gcp.compute.inputs.GetImageArgs;
import com.pulumi.gcp.compute.InstanceTemplate;
import com.pulumi.gcp.compute.InstanceTemplateArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateNetworkInterfaceArgs;
import com.pulumi.gcp.compute.inputs.InstanceTemplateDiskArgs;
import com.pulumi.gcp.compute.InstanceGroupManager;
import com.pulumi.gcp.compute.InstanceGroupManagerArgs;
import com.pulumi.gcp.compute.inputs.InstanceGroupManagerVersionArgs;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckTcpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.inputs.BackendServiceBackendArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.TargetHttpProxy;
import com.pulumi.gcp.compute.TargetHttpProxyArgs;
import com.pulumi.gcp.compute.GlobalForwardingRule;
import com.pulumi.gcp.compute.GlobalForwardingRuleArgs;
import com.pulumi.gcp.compute.inputs.GlobalForwardingRuleMetadataFilterArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var debianImage = ComputeFunctions.getImage(GetImageArgs.builder()
            .family("debian-11")
            .project("debian-cloud")
            .build());

        var instanceTemplate = new InstanceTemplate("instanceTemplate", InstanceTemplateArgs.builder()
            .name("template-backend")
            .machineType("e2-medium")
            .networkInterfaces(InstanceTemplateNetworkInterfaceArgs.builder()
                .network("default")
                .build())
            .disks(InstanceTemplateDiskArgs.builder()
                .sourceImage(debianImage.selfLink())
                .autoDelete(true)
                .boot(true)
                .build())
            .build());

        var igm = new InstanceGroupManager("igm", InstanceGroupManagerArgs.builder()
            .name("igm-internal")
            .versions(InstanceGroupManagerVersionArgs.builder()
                .instanceTemplate(instanceTemplate.id())
                .name("primary")
                .build())
            .baseInstanceName("internal-glb")
            .zone("us-central1-f")
            .targetSize(1)
            .build());

        var defaultHealthCheck = new HealthCheck("defaultHealthCheck", HealthCheckArgs.builder()
            .name("check-backend")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .tcpHealthCheck(HealthCheckTcpHealthCheckArgs.builder()
                .port(80)
                .build())
            .build());

        var defaultBackendService = new BackendService("defaultBackendService", BackendServiceArgs.builder()
            .name("backend")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .loadBalancingScheme("INTERNAL_SELF_MANAGED")
            .backends(BackendServiceBackendArgs.builder()
                .group(igm.instanceGroup())
                .balancingMode("RATE")
                .capacityScaler(0.4)
                .maxRatePerInstance(50.0)
                .build())
            .healthChecks(defaultHealthCheck.id())
            .build());

        var defaultURLMap = new URLMap("defaultURLMap", URLMapArgs.builder()
            .name("url-map-target-proxy")
            .description("a description")
            .defaultService(defaultBackendService.id())
            .hostRules(URLMapHostRuleArgs.builder()
                .hosts("mysite.com")
                .pathMatcher("allpaths")
                .build())
            .pathMatchers(URLMapPathMatcherArgs.builder()
                .name("allpaths")
                .defaultService(defaultBackendService.id())
                .pathRules(URLMapPathMatcherPathRuleArgs.builder()
                    .paths("/*")
                    .service(defaultBackendService.id())
                    .build())
                .build())
            .build());

        var defaultTargetHttpProxy = new TargetHttpProxy("defaultTargetHttpProxy", TargetHttpProxyArgs.builder()
            .name("target-proxy")
            .description("a description")
            .urlMap(defaultURLMap.id())
            .build());

        var default_ = new GlobalForwardingRule("default", GlobalForwardingRuleArgs.builder()
            .name("global-rule")
            .target(defaultTargetHttpProxy.id())
            .portRange("80")
            .loadBalancingScheme("INTERNAL_SELF_MANAGED")
            .ipAddress("0.0.0.0")
            .metadataFilters(GlobalForwardingRuleMetadataFilterArgs.builder()
                .filterMatchCriteria("MATCH_ANY")
                .filterLabels(GlobalForwardingRuleMetadataFilterFilterLabelArgs.builder()
                    .name("PLANET")
                    .value("MARS")
                    .build())
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:compute:GlobalForwardingRule
    properties:
      name: global-rule
      target: ${defaultTargetHttpProxy.id}
      portRange: '80'
      loadBalancingScheme: INTERNAL_SELF_MANAGED
      ipAddress: 0.0.0.0
      metadataFilters:
        - filterMatchCriteria: MATCH_ANY
          filterLabels:
            - name: PLANET
              value: MARS
  defaultTargetHttpProxy:
    type: gcp:compute:TargetHttpProxy
    name: default
    properties:
      name: target-proxy
      description: a description
      urlMap: ${defaultURLMap.id}
  defaultURLMap:
    type: gcp:compute:URLMap
    name: default
    properties:
      name: url-map-target-proxy
      description: a description
      defaultService: ${defaultBackendService.id}
      hostRules:
        - hosts:
            - mysite.com
          pathMatcher: allpaths
      pathMatchers:
        - name: allpaths
          defaultService: ${defaultBackendService.id}
          pathRules:
            - paths:
                - /*
              service: ${defaultBackendService.id}
  defaultBackendService:
    type: gcp:compute:BackendService
    name: default
    properties:
      name: backend
      portName: http
      protocol: HTTP
      timeoutSec: 10
      loadBalancingScheme: INTERNAL_SELF_MANAGED
      backends:
        - group: ${igm.instanceGroup}
          balancingMode: RATE
          capacityScaler: 0.4
          maxRatePerInstance: 50
      healthChecks: ${defaultHealthCheck.id}
  igm:
    type: gcp:compute:InstanceGroupManager
    properties:
      name: igm-internal
      versions:
        - instanceTemplate: ${instanceTemplate.id}
          name: primary
      baseInstanceName: internal-glb
      zone: us-central1-f
      targetSize: 1
  instanceTemplate:
    type: gcp:compute:InstanceTemplate
    name: instance_template
    properties:
      name: template-backend
      machineType: e2-medium
      networkInterfaces:
        - network: default
      disks:
        - sourceImage: ${debianImage.selfLink}
          autoDelete: true
          boot: true
  defaultHealthCheck:
    type: gcp:compute:HealthCheck
    name: default
    properties:
      name: check-backend
      checkIntervalSec: 1
      timeoutSec: 1
      tcpHealthCheck:
        port: '80'
variables:
  debianImage:
    fn::invoke:
      function: gcp:compute:getImage
      arguments:
        family: debian-11
        project: debian-cloud

The loadBalancingScheme property set to INTERNAL_SELF_MANAGED keeps traffic within your VPC. The ipAddress of 0.0.0.0 indicates this rule doesn’t bind to a specific IP. The metadataFilters property restricts which xDS-compliant proxies receive routing configuration; only proxies presenting matching node metadata get access to the backend services.

Use external managed load balancing

Modern Application Load Balancers use EXTERNAL_MANAGED scheme for advanced traffic management.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const defaultBackendService = new gcp.compute.BackendService("default", {
    name: "backend",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    loadBalancingScheme: "EXTERNAL_MANAGED",
});
const defaultURLMap = new gcp.compute.URLMap("default", {
    name: "url-map-target-proxy",
    description: "a description",
    defaultService: defaultBackendService.id,
    hostRules: [{
        hosts: ["mysite.com"],
        pathMatcher: "allpaths",
    }],
    pathMatchers: [{
        name: "allpaths",
        defaultService: defaultBackendService.id,
        pathRules: [{
            paths: ["/*"],
            service: defaultBackendService.id,
        }],
    }],
});
const defaultTargetHttpProxy = new gcp.compute.TargetHttpProxy("default", {
    name: "target-proxy",
    description: "a description",
    urlMap: defaultURLMap.id,
});
const _default = new gcp.compute.GlobalForwardingRule("default", {
    name: "global-rule",
    target: defaultTargetHttpProxy.id,
    portRange: "80",
    loadBalancingScheme: "EXTERNAL_MANAGED",
    networkTier: "PREMIUM",
});
import pulumi
import pulumi_gcp as gcp

default_backend_service = gcp.compute.BackendService("default",
    name="backend",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    load_balancing_scheme="EXTERNAL_MANAGED")
default_url_map = gcp.compute.URLMap("default",
    name="url-map-target-proxy",
    description="a description",
    default_service=default_backend_service.id,
    host_rules=[{
        "hosts": ["mysite.com"],
        "path_matcher": "allpaths",
    }],
    path_matchers=[{
        "name": "allpaths",
        "default_service": default_backend_service.id,
        "path_rules": [{
            "paths": ["/*"],
            "service": default_backend_service.id,
        }],
    }])
default_target_http_proxy = gcp.compute.TargetHttpProxy("default",
    name="target-proxy",
    description="a description",
    url_map=default_url_map.id)
default = gcp.compute.GlobalForwardingRule("default",
    name="global-rule",
    target=default_target_http_proxy.id,
    port_range="80",
    load_balancing_scheme="EXTERNAL_MANAGED",
    network_tier="PREMIUM")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		defaultBackendService, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:                pulumi.String("backend"),
			PortName:            pulumi.String("http"),
			Protocol:            pulumi.String("HTTP"),
			TimeoutSec:          pulumi.Int(10),
			LoadBalancingScheme: pulumi.String("EXTERNAL_MANAGED"),
		})
		if err != nil {
			return err
		}
		defaultURLMap, err := compute.NewURLMap(ctx, "default", &compute.URLMapArgs{
			Name:           pulumi.String("url-map-target-proxy"),
			Description:    pulumi.String("a description"),
			DefaultService: defaultBackendService.ID(),
			HostRules: compute.URLMapHostRuleArray{
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("mysite.com"),
					},
					PathMatcher: pulumi.String("allpaths"),
				},
			},
			PathMatchers: compute.URLMapPathMatcherArray{
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("allpaths"),
					DefaultService: defaultBackendService.ID(),
					PathRules: compute.URLMapPathMatcherPathRuleArray{
						&compute.URLMapPathMatcherPathRuleArgs{
							Paths: pulumi.StringArray{
								pulumi.String("/*"),
							},
							Service: defaultBackendService.ID(),
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		defaultTargetHttpProxy, err := compute.NewTargetHttpProxy(ctx, "default", &compute.TargetHttpProxyArgs{
			Name:        pulumi.String("target-proxy"),
			Description: pulumi.String("a description"),
			UrlMap:      defaultURLMap.ID(),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewGlobalForwardingRule(ctx, "default", &compute.GlobalForwardingRuleArgs{
			Name:                pulumi.String("global-rule"),
			Target:              defaultTargetHttpProxy.ID(),
			PortRange:           pulumi.String("80"),
			LoadBalancingScheme: pulumi.String("EXTERNAL_MANAGED"),
			NetworkTier:         pulumi.String("PREMIUM"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var defaultBackendService = new Gcp.Compute.BackendService("default", new()
    {
        Name = "backend",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        LoadBalancingScheme = "EXTERNAL_MANAGED",
    });

    var defaultURLMap = new Gcp.Compute.URLMap("default", new()
    {
        Name = "url-map-target-proxy",
        Description = "a description",
        DefaultService = defaultBackendService.Id,
        HostRules = new[]
        {
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "mysite.com",
                },
                PathMatcher = "allpaths",
            },
        },
        PathMatchers = new[]
        {
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "allpaths",
                DefaultService = defaultBackendService.Id,
                PathRules = new[]
                {
                    new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
                    {
                        Paths = new[]
                        {
                            "/*",
                        },
                        Service = defaultBackendService.Id,
                    },
                },
            },
        },
    });

    var defaultTargetHttpProxy = new Gcp.Compute.TargetHttpProxy("default", new()
    {
        Name = "target-proxy",
        Description = "a description",
        UrlMap = defaultURLMap.Id,
    });

    var @default = new Gcp.Compute.GlobalForwardingRule("default", new()
    {
        Name = "global-rule",
        Target = defaultTargetHttpProxy.Id,
        PortRange = "80",
        LoadBalancingScheme = "EXTERNAL_MANAGED",
        NetworkTier = "PREMIUM",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.TargetHttpProxy;
import com.pulumi.gcp.compute.TargetHttpProxyArgs;
import com.pulumi.gcp.compute.GlobalForwardingRule;
import com.pulumi.gcp.compute.GlobalForwardingRuleArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var defaultBackendService = new BackendService("defaultBackendService", BackendServiceArgs.builder()
            .name("backend")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .loadBalancingScheme("EXTERNAL_MANAGED")
            .build());

        var defaultURLMap = new URLMap("defaultURLMap", URLMapArgs.builder()
            .name("url-map-target-proxy")
            .description("a description")
            .defaultService(defaultBackendService.id())
            .hostRules(URLMapHostRuleArgs.builder()
                .hosts("mysite.com")
                .pathMatcher("allpaths")
                .build())
            .pathMatchers(URLMapPathMatcherArgs.builder()
                .name("allpaths")
                .defaultService(defaultBackendService.id())
                .pathRules(URLMapPathMatcherPathRuleArgs.builder()
                    .paths("/*")
                    .service(defaultBackendService.id())
                    .build())
                .build())
            .build());

        var defaultTargetHttpProxy = new TargetHttpProxy("defaultTargetHttpProxy", TargetHttpProxyArgs.builder()
            .name("target-proxy")
            .description("a description")
            .urlMap(defaultURLMap.id())
            .build());

        var default_ = new GlobalForwardingRule("default", GlobalForwardingRuleArgs.builder()
            .name("global-rule")
            .target(defaultTargetHttpProxy.id())
            .portRange("80")
            .loadBalancingScheme("EXTERNAL_MANAGED")
            .networkTier("PREMIUM")
            .build());

    }
}
resources:
  default:
    type: gcp:compute:GlobalForwardingRule
    properties:
      name: global-rule
      target: ${defaultTargetHttpProxy.id}
      portRange: '80'
      loadBalancingScheme: EXTERNAL_MANAGED
      networkTier: PREMIUM
  defaultTargetHttpProxy:
    type: gcp:compute:TargetHttpProxy
    name: default
    properties:
      name: target-proxy
      description: a description
      urlMap: ${defaultURLMap.id}
  defaultURLMap:
    type: gcp:compute:URLMap
    name: default
    properties:
      name: url-map-target-proxy
      description: a description
      defaultService: ${defaultBackendService.id}
      hostRules:
        - hosts:
            - mysite.com
          pathMatcher: allpaths
      pathMatchers:
        - name: allpaths
          defaultService: ${defaultBackendService.id}
          pathRules:
            - paths:
                - /*
              service: ${defaultBackendService.id}
  defaultBackendService:
    type: gcp:compute:BackendService
    name: default
    properties:
      name: backend
      portName: http
      protocol: HTTP
      timeoutSec: 10
      loadBalancingScheme: EXTERNAL_MANAGED

The EXTERNAL_MANAGED scheme enables features like traffic splitting and global load distribution. The networkTier property set to PREMIUM provides global anycast IP addresses and optimal routing across Google’s network.

Connect privately to Google APIs

Organizations access Google APIs without internet exposure by routing API traffic through their VPC network.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const network = new gcp.compute.Network("network", {
    project: "my-project-name",
    name: "my-network",
    autoCreateSubnetworks: false,
});
const vpcSubnetwork = new gcp.compute.Subnetwork("vpc_subnetwork", {
    project: network.project,
    name: "my-subnetwork",
    ipCidrRange: "10.2.0.0/16",
    region: "us-central1",
    network: network.id,
    privateIpGoogleAccess: true,
});
const _default = new gcp.compute.GlobalAddress("default", {
    project: network.project,
    name: "global-psconnect-ip",
    addressType: "INTERNAL",
    purpose: "PRIVATE_SERVICE_CONNECT",
    network: network.id,
    address: "100.100.100.106",
});
const defaultGlobalForwardingRule = new gcp.compute.GlobalForwardingRule("default", {
    project: network.project,
    name: "globalrule",
    target: "all-apis",
    network: network.id,
    ipAddress: _default.id,
    loadBalancingScheme: "",
    serviceDirectoryRegistrations: {
        namespace: "sd-namespace",
        serviceDirectoryRegion: "europe-west3",
    },
});
import pulumi
import pulumi_gcp as gcp

network = gcp.compute.Network("network",
    project="my-project-name",
    name="my-network",
    auto_create_subnetworks=False)
vpc_subnetwork = gcp.compute.Subnetwork("vpc_subnetwork",
    project=network.project,
    name="my-subnetwork",
    ip_cidr_range="10.2.0.0/16",
    region="us-central1",
    network=network.id,
    private_ip_google_access=True)
default = gcp.compute.GlobalAddress("default",
    project=network.project,
    name="global-psconnect-ip",
    address_type="INTERNAL",
    purpose="PRIVATE_SERVICE_CONNECT",
    network=network.id,
    address="100.100.100.106")
default_global_forwarding_rule = gcp.compute.GlobalForwardingRule("default",
    project=network.project,
    name="globalrule",
    target="all-apis",
    network=network.id,
    ip_address=default.id,
    load_balancing_scheme="",
    service_directory_registrations={
        "namespace": "sd-namespace",
        "service_directory_region": "europe-west3",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		network, err := compute.NewNetwork(ctx, "network", &compute.NetworkArgs{
			Project:               pulumi.String("my-project-name"),
			Name:                  pulumi.String("my-network"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewSubnetwork(ctx, "vpc_subnetwork", &compute.SubnetworkArgs{
			Project:               network.Project,
			Name:                  pulumi.String("my-subnetwork"),
			IpCidrRange:           pulumi.String("10.2.0.0/16"),
			Region:                pulumi.String("us-central1"),
			Network:               network.ID(),
			PrivateIpGoogleAccess: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_default, err := compute.NewGlobalAddress(ctx, "default", &compute.GlobalAddressArgs{
			Project:     network.Project,
			Name:        pulumi.String("global-psconnect-ip"),
			AddressType: pulumi.String("INTERNAL"),
			Purpose:     pulumi.String("PRIVATE_SERVICE_CONNECT"),
			Network:     network.ID(),
			Address:     pulumi.String("100.100.100.106"),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewGlobalForwardingRule(ctx, "default", &compute.GlobalForwardingRuleArgs{
			Project:             network.Project,
			Name:                pulumi.String("globalrule"),
			Target:              pulumi.String("all-apis"),
			Network:             network.ID(),
			IpAddress:           _default.ID(),
			LoadBalancingScheme: pulumi.String(""),
			ServiceDirectoryRegistrations: &compute.GlobalForwardingRuleServiceDirectoryRegistrationsArgs{
				Namespace:              pulumi.String("sd-namespace"),
				ServiceDirectoryRegion: pulumi.String("europe-west3"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var network = new Gcp.Compute.Network("network", new()
    {
        Project = "my-project-name",
        Name = "my-network",
        AutoCreateSubnetworks = false,
    });

    var vpcSubnetwork = new Gcp.Compute.Subnetwork("vpc_subnetwork", new()
    {
        Project = network.Project,
        Name = "my-subnetwork",
        IpCidrRange = "10.2.0.0/16",
        Region = "us-central1",
        Network = network.Id,
        PrivateIpGoogleAccess = true,
    });

    var @default = new Gcp.Compute.GlobalAddress("default", new()
    {
        Project = network.Project,
        Name = "global-psconnect-ip",
        AddressType = "INTERNAL",
        Purpose = "PRIVATE_SERVICE_CONNECT",
        Network = network.Id,
        Address = "100.100.100.106",
    });

    var defaultGlobalForwardingRule = new Gcp.Compute.GlobalForwardingRule("default", new()
    {
        Project = network.Project,
        Name = "globalrule",
        Target = "all-apis",
        Network = network.Id,
        IpAddress = @default.Id,
        LoadBalancingScheme = "",
        ServiceDirectoryRegistrations = new Gcp.Compute.Inputs.GlobalForwardingRuleServiceDirectoryRegistrationsArgs
        {
            Namespace = "sd-namespace",
            ServiceDirectoryRegion = "europe-west3",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.Subnetwork;
import com.pulumi.gcp.compute.SubnetworkArgs;
import com.pulumi.gcp.compute.GlobalAddress;
import com.pulumi.gcp.compute.GlobalAddressArgs;
import com.pulumi.gcp.compute.GlobalForwardingRule;
import com.pulumi.gcp.compute.GlobalForwardingRuleArgs;
import com.pulumi.gcp.compute.inputs.GlobalForwardingRuleServiceDirectoryRegistrationsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var network = new Network("network", NetworkArgs.builder()
            .project("my-project-name")
            .name("my-network")
            .autoCreateSubnetworks(false)
            .build());

        var vpcSubnetwork = new Subnetwork("vpcSubnetwork", SubnetworkArgs.builder()
            .project(network.project())
            .name("my-subnetwork")
            .ipCidrRange("10.2.0.0/16")
            .region("us-central1")
            .network(network.id())
            .privateIpGoogleAccess(true)
            .build());

        var default_ = new GlobalAddress("default", GlobalAddressArgs.builder()
            .project(network.project())
            .name("global-psconnect-ip")
            .addressType("INTERNAL")
            .purpose("PRIVATE_SERVICE_CONNECT")
            .network(network.id())
            .address("100.100.100.106")
            .build());

        var defaultGlobalForwardingRule = new GlobalForwardingRule("defaultGlobalForwardingRule", GlobalForwardingRuleArgs.builder()
            .project(network.project())
            .name("globalrule")
            .target("all-apis")
            .network(network.id())
            .ipAddress(default_.id())
            .loadBalancingScheme("")
            .serviceDirectoryRegistrations(GlobalForwardingRuleServiceDirectoryRegistrationsArgs.builder()
                .namespace("sd-namespace")
                .serviceDirectoryRegion("europe-west3")
                .build())
            .build());

    }
}
resources:
  network:
    type: gcp:compute:Network
    properties:
      project: my-project-name
      name: my-network
      autoCreateSubnetworks: false
  vpcSubnetwork:
    type: gcp:compute:Subnetwork
    name: vpc_subnetwork
    properties:
      project: ${network.project}
      name: my-subnetwork
      ipCidrRange: 10.2.0.0/16
      region: us-central1
      network: ${network.id}
      privateIpGoogleAccess: true
  default:
    type: gcp:compute:GlobalAddress
    properties:
      project: ${network.project}
      name: global-psconnect-ip
      addressType: INTERNAL
      purpose: PRIVATE_SERVICE_CONNECT
      network: ${network.id}
      address: 100.100.100.106
  defaultGlobalForwardingRule:
    type: gcp:compute:GlobalForwardingRule
    name: default
    properties:
      project: ${network.project}
      name: globalrule
      target: all-apis
      network: ${network.id}
      ipAddress: ${default.id}
      loadBalancingScheme: ""
      serviceDirectoryRegistrations:
        namespace: sd-namespace
        serviceDirectoryRegion: europe-west3

The target property accepts special values for Private Service Connect: “all-apis” routes to all supported Google APIs, while “vpc-sc” limits access to APIs that support VPC Service Controls. The loadBalancingScheme is set to an empty string for PSC to Google APIs. The serviceDirectoryRegistrations property registers the endpoint in Service Directory for DNS resolution within your VPC.

Beyond these examples

These snippets focus on specific forwarding rule features: HTTP load balancing with target proxies, internal self-managed and external managed schemes, and Private Service Connect to Google APIs. They’re intentionally minimal rather than full load balancing deployments.

The examples reference pre-existing infrastructure such as VPC networks, subnets, and GlobalAddress resources, as well as backend services, health checks, instance groups, URL maps, and target proxies. They focus on configuring the forwarding rule rather than provisioning the complete load balancing stack.

To keep things focused, common forwarding rule patterns are omitted, including:

  • Source IP range filtering (sourceIpRanges)
  • IPv6 configuration (ipVersion)
  • Backend bucket migration (externalManagedBackendBucketMigrationState)
  • DNS zone automation control (noAutomateDnsZone)

These omissions are intentional: the goal is to illustrate how each forwarding rule feature is wired, not provide drop-in load balancing modules. See the GlobalForwardingRule resource reference for all available configuration options.

Let's configure GCP Global HTTP Load Balancing Rules

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Setup
When do I need to specify an IP address for my forwarding rule?
You must specify ipAddress in two cases: when target is targetGrpcProxy with validateForProxyless set to true (use 0.0.0.0), or when target is a Private Service Connect Google APIs bundle. Otherwise, ipAddress is optional and Google Cloud assigns an ephemeral IP if omitted.
What are the naming requirements for global forwarding rules?
General forwarding rules require names 1-63 characters long matching [a-z][-a-z0-9]*[a-z0-9]. Private Service Connect forwarding rules to Google APIs have stricter requirements: 1-20 characters, lowercase letters and numbers only, must start with a letter.
What types of targets can I use with global forwarding rules?
You have three options: load balancing resources (see Port specifications documentation), Google API bundles for Private Service Connect (vpc-sc for VPC Service Controls APIs or all-apis for all supported APIs), or service attachments for PSC to managed services.
Load Balancing Schemes
What's the difference between EXTERNAL and EXTERNAL_MANAGED load balancing?
EXTERNAL is the default classic load balancing scheme. EXTERNAL_MANAGED is the newer Application Load Balancer. You can migrate between them using externalManagedBackendBucketMigrationState, but the migration requires specific state transitions.
When should I use INTERNAL_SELF_MANAGED load balancing?
Use INTERNAL_SELF_MANAGED when you need xDS-based routing with metadata filters. This scheme enables metadataFilters for restricting routing configuration to specific xDS-compliant clients based on node metadata.
What load balancing scheme should I use for Private Service Connect to Google APIs?
Set loadBalancingScheme to an empty string when connecting to Google APIs via Private Service Connect. Also set target to all-apis or vpc-sc and specify an ipAddress.
Immutability & Updates
What can I change after creating a global forwarding rule?
You can only modify target, labels, and migration-related fields (externalManagedBackendBucketMigrationState, externalManagedBackendBucketMigrationTestingPercentage). All other properties including ipAddress, name, network, portRange, and metadataFilters are immutable and require resource recreation to change.
How do I migrate from EXTERNAL to EXTERNAL_MANAGED load balancing?
Set externalManagedBackendBucketMigrationState to PREPARE, then TEST_ALL_TRAFFIC, then change loadBalancingScheme to EXTERNAL_MANAGED. Optionally, use TEST_BY_PERCENTAGE with externalManagedBackendBucketMigrationTestingPercentage to gradually migrate traffic. Rollback requires reversing these states.
Private Service Connect
How do I connect to Google APIs using Private Service Connect?
Set target to all-apis or vpc-sc, specify an ipAddress (using a global address with PRIVATE_SERVICE_CONNECT purpose), provide a network, and set loadBalancingScheme to an empty string. Optionally configure serviceDirectoryRegistrations for service discovery.
What does noAutomateDnsZone control in PSC forwarding rules?
noAutomateDnsZone controls whether Private Service Connect forwarding rules automatically generate a DNS zone. This field only applies to PSC forwarding rules; non-PSC forwarding rules ignore it.
Advanced Features
How do I use metadata filters for xDS-based routing?
Set loadBalancingScheme to INTERNAL_SELF_MANAGED and configure metadataFilters with filterMatchCriteria (either MATCH_ANY or MATCH_ALL) and filterLabels. Metadata filters only work with INTERNAL_SELF_MANAGED and are ignored for other schemes.
Why aren't my labels showing up in the Pulumi state?
The labels field is non-authoritative and only manages labels present in your configuration. To see all labels on the resource (including those set by other clients or services), use the effectiveLabels output property instead.
What are the port range restrictions for global forwarding rules?
portRange requires ipProtocol to be TCP, UDP, or SCTP. It only applies to specific products (external/internal Network Load Balancers, Application Load Balancers, protocol forwarding, Classic VPN). Some products have additional port restrictions; see the port specifications documentation for details.

Using a different cloud?

Explore networking guides for other cloud providers: