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 for Google APIs.

Forwarding rules reference target proxies, URL maps, backend services, and for Private Service Connect, reserved GlobalAddress resources and VPC networks. The examples are intentionally small. Combine them with your own backend infrastructure 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

The forwarding rule accepts traffic on the specified portRange and forwards it to the target, which must be a TargetHttpProxy or TargetHttpsProxy. The target proxy then consults the URLMap to route requests to backend services. When loadBalancingScheme is omitted, it defaults to EXTERNAL, and GCP assigns an ephemeral IP address.

Configure internal self-managed load balancing

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

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

Setting loadBalancingScheme to INTERNAL_SELF_MANAGED creates a forwarding rule for xDS-based service mesh integration. The ipAddress of 0.0.0.0 is a special value for internal self-managed rules. The metadataFilters property restricts which xDS clients receive routing configuration based on node metadata they present.

Use external managed load balancing with premium tier

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

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 integration with Cloud Armor, Cloud CDN, and other advanced ALB features. The networkTier property controls routing quality; PREMIUM uses Google’s global network for optimal performance.

Connect privately to Google APIs via PSC

Organizations accessing Google APIs from private networks use Private Service Connect forwarding rules with reserved internal IPs.

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” provides access to all supported Google APIs, while “vpc-sc” limits access to APIs that support VPC Service Controls. The ipAddress must reference a GlobalAddress with purpose PRIVATE_SERVICE_CONNECT. The serviceDirectoryRegistrations property enables service discovery integration.

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 for Google APIs. They’re intentionally minimal rather than full load balancing deployments.

The examples reference pre-existing infrastructure such as VPC networks and subnets, backend services, URL maps, and target proxies, and GlobalAddress resources for PSC. 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:

  • IPv6 configuration (ipVersion)
  • Source IP range filtering (sourceIpRanges)
  • Backend bucket migration (externalManagedBackendBucketMigrationState)
  • Cross-region PSC access (allowPscGlobalAccess)

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

Load Balancing Configuration
What load balancing schemes are available?
Four schemes are available: EXTERNAL (default), EXTERNAL_MANAGED, INTERNAL_MANAGED, and INTERNAL_SELF_MANAGED. The scheme determines the forwarding rule type and load balancer behavior.
What's the difference between EXTERNAL and EXTERNAL_MANAGED?
EXTERNAL is the classic load balancing scheme, while EXTERNAL_MANAGED is for newer external Application Load Balancers with advanced features. Use EXTERNAL_MANAGED with networkTier set to PREMIUM for modern deployments.
When should I use INTERNAL_SELF_MANAGED load balancing?
Use INTERNAL_SELF_MANAGED for service mesh deployments with xDS-compliant clients. Set ipAddress to 0.0.0.0 and optionally configure metadataFilters for routing control.
What can I use as a target for my forwarding rule?
For load balancers, use the URL of a target proxy resource (like TargetHttpProxy). For Private Service Connect to Google APIs, use all-apis or vpc-sc. For PSC to managed services, use a service attachment URL.
IP Address & Networking
When do I need to specify an IP address?
You must specify ipAddress when: (1) target is targetGrpcProxy with validateForProxyless set to true (use 0.0.0.0), or (2) target is a Private Service Connect Google APIs bundle. Otherwise, it’s optional and Google Cloud assigns an ephemeral IP.
What IP address formats are supported?
You can specify: IP address number (100.1.2.3), IPv6 range (2600:1234::/96), full resource URL, partial URL (projects/project_id/regions/region/addresses/address-name), or just the address name. The API always returns the IP address number.
What's the difference between PREMIUM and STANDARD network tiers?
PREMIUM (default) uses Google’s global network for optimal performance. STANDARD uses regular ISP networks and costs less. For global forwarding rules, only PREMIUM is valid. If you specify ipAddress, its networkTier must match.
Immutability & Updates
What properties can't be changed after creation?
These properties are immutable and force replacement: ipAddress, ipProtocol, name, network, networkTier, project, serviceDirectoryRegistrations, subnetwork, allowPscGlobalAccess, description, ipVersion, metadataFilters, noAutomateDnsZone, portRange, and sourceIpRanges.
Can I update the target of my forwarding rule?
Yes, target is one of the few properties that can be updated without replacing the resource. You can change which load balancer or service the forwarding rule points to.
Private Service Connect
How do I connect to Google APIs using Private Service Connect?
Set target to all-apis (all Google APIs) or vpc-sc (VPC Service Controls-supported APIs), specify an ipAddress, provide a network, and set loadBalancingScheme to an empty string.
What are the naming requirements for PSC forwarding rules?
For Private Service Connect to Google APIs, names must be 1-20 characters with lowercase letters and numbers, starting with a letter. General forwarding rules can use 1-63 characters following RFC1035 (lowercase letters, numbers, dashes).
Protocols & Ports
What protocols and ports can I use?
Supported protocols: TCP, UDP, ESP, AH, SCTP, ICMP. The portRange property requires TCP, UDP, or SCTP, and is only applicable to specific load balancer products (external/internal passthrough and proxy Network Load Balancers, Application Load Balancers, protocol forwarding, Classic VPN). Some products have additional port restrictions.
When can I use metadataFilters?
metadataFilters only works when loadBalancingScheme is set to INTERNAL_SELF_MANAGED. It restricts routing configuration to xDS-compliant clients based on node metadata matching.

Using a different cloud?

Explore networking guides for other cloud providers: