This document provides instructions for configuring a cross-region internal proxy Network Load Balancer with Compute Engine VM instance group backends.
Before following this guide, familiarize yourself with the Internal proxy Network Load Balancer overview.
For this example, you configure the deployment shown in the following diagram.
This creates a cross-region internal proxy Network Load Balancer in a VPC network,
with one backend service and two backend managed instance groups (MIGs) in
region REGION_A and REGION_B
regions.
SNI-based routing: This page also shows you an alternative deployment architecture that you can use to configure SNI-based routing. For SNI-based routing, you use TLS routes to define how traffic is distributed. For details, see Create a load balancer with TLS routes.
Cross-region internal proxy Network Load Balancers require the following resources:
A VPC network with the following subnets:
SUBNET_A and a proxy-only subnet in REGION_A.SUBNET_B and a proxy-only subnet in REGION_B.You must create proxy-only subnets
in each region of a VPC network where you use
cross-region internal proxy Network Load Balancers. The region's
proxy-only subnet is shared among all cross-region internal proxy Network Load Balancers in
the region. Source addresses of packets sent from the load balancer
to your service's backends are allocated from the
proxy-only subnet.
In this example, the proxy-only subnet for the region
REGION_B has a primary IP address range of 10.129.0.0/23, and for
REGION_A, has a primary IP address range of 10.130.0.0/23, which is the
recommended subnet size.
High availability setup has managed instance group backends for
Compute Engine VM deployments in REGION_A
and REGION_B regions. If backends in one region
happen to be down, traffic fails over to the other region.
A global backend service that monitors the usage and health of backends.
A global target TCP proxy, which receives a request from the user and forwards it to the backend service.
Global forwarding rules, which have the regional internal IP address of your load balancer and can forward each incoming request to the target proxy.
The internal IP address associated with the forwarding rule can come from a subnet in the same network and region as the backends. Note the following conditions:
--purpose flag set to GLOBAL_MANAGED_PROXY. If you
try to use the proxy-only subnet, forwarding rule creation fails.--purpose flag to SHARED_LOADBALANCER_VIP.To follow this guide, you must be able to create instances and modify a network in a project. You must be either a project owner or editor, or you must have all of the following Compute Engine IAM roles.
| Task | Required role |
|---|---|
| Create networks, subnets, and load balancer components | Compute Network Admin |
| Add and remove firewall rules | Compute Security Admin |
| Create instances | Compute Instance Admin |
For more information, see the following guides:
Within the VPC network, configure a subnet in each region
where your backends are configured. In addition, configure a proxy-only-subnet
in each region that you want to configure the load balancer.
This example uses the following VPC network, region, and subnets:
Network. The network is a custom mode VPC
network named NETWORK.
Subnets for backends.
SUBNET_A in the
REGION_A region uses 10.1.2.0/24 for its primary
IP range.SUBNET_B in the
REGION_B region uses 10.1.3.0/24 for its primary
IP range.Subnets for proxies.
PROXY_SN_A in
the REGION_A region uses 10.129.0.0/23 for its
primary IP range.PROXY_SN_B in the
REGION_B region uses 10.130.0.0/23 for its
primary IP range.Cross-region load balancers can be accessed from any region within the VPC. So clients from any region can globally access your load balancer backends.
In the Google Cloud console, go to the VPC networks page.
Click Create VPC network.
Provide a Name for the network.
In the Subnets section, set the Subnet creation mode to Custom.
Create a subnet for the load balancer's backends. In the New subnet section, enter the following information:
10.1.2.0/24Click Done.
Click Add subnet.
Create a subnet for the load balancer's backends. In the New subnet section, enter the following information:
10.1.3.0/24Click Done.
Click Create.
Create the custom VPC network with the gcloud compute
networks create command:
gcloud compute networks create NETWORK \
--subnet-mode=custom
Create a subnet in the NETWORK network in the
REGION_A region with
the gcloud compute networks subnets create command:
gcloud compute networks subnets create SUBNET_A \
--network=NETWORK \
--range=10.1.2.0/24 \
--region=REGION_A
Create a subnet in the NETWORK network in the
REGION_B region with
the gcloud compute networks subnets create command:
gcloud compute networks subnets create SUBNET_B \
--network=NETWORK \
--range=10.1.3.0/24 \
--region=REGION_B
To create the VPC network, use the google_compute_network resource.
To create the VPC subnets in the lb-network-crs-reg network,
use the google_compute_subnetwork resource.
Make a POST request to the
networks.insert method.
Replace PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/networks
{
"routingConfig": {
"routingMode": "regional"
},
"name": "NETWORK",
"autoCreateSubnetworks": false
}
Make a POST request to the
subnetworks.insert method.
Replace PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/regions/REGION_A/subnetworks
{
"name": "SUBNET_A",
"network": "projects/PROJECT_ID/global/networks/lb-network-crs-reg",
"ipCidrRange": "10.1.2.0/24",
"region": "projects/PROJECT_ID/regions/REGION_A",
}
Make a POST request to the
subnetworks.insert method.
Replace PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/regions/REGION_B/subnetworks
{
"name": "SUBNET_B",
"network": "projects/PROJECT_ID/global/networks/NETWORK",
"ipCidrRange": "10.1.3.0/24",
"region": "projects/PROJECT_ID/regions/REGION_B",
}
A proxy-only subnet provides a set of IP addresses that Google Cloud uses to run Envoy proxies on your behalf. The proxies terminate connections from the client and create new connections to the backends.
This proxy-only subnet is used by all Envoy-based regional load balancers in the same region as the VPC network. There can only be one active proxy-only subnet for a given purpose, per region, per network.
If you're using the Google Cloud console, you can wait and create the proxy-only subnet later on the Load balancing page.
If you want to create the proxy-only subnet now, use the following steps:
In the Google Cloud console, go to the VPC networks page.
10.129.0.0/23.Create the proxy-only subnet in REGION_B
10.130.0.0/23.Create the proxy-only subnets with the
gcloud compute networks subnets create command.
gcloud compute networks subnets create PROXY_SN_A \
--purpose=GLOBAL_MANAGED_PROXY \
--role=ACTIVE \
--region=REGION_A \
--network=NETWORK \
--range=10.129.0.0/23
gcloud compute networks subnets create PROXY_SN_B \
--purpose=GLOBAL_MANAGED_PROXY \
--role=ACTIVE \
--region=REGION_B \
--network=NETWORK \
--range=10.130.0.0/23
To create the VPC proxy-only subnet in the lb-network-crs-reg
network, use the google_compute_subnetwork resource.
Create the proxy-only subnets with the
subnetworks.insert method, replacing
PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/regions/REGION_A/subnetworks
{
"name": " PROXY_SN_A",
"ipCidrRange": "10.129.0.0/23",
"network": "projects/PROJECT_ID/global/networks/NETWORK",
"region": "projects/PROJECT_ID/regions/REGION_A",
"purpose": "GLOBAL_MANAGED_PROXY",
"role": "ACTIVE"
}
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/regions/REGION_B/subnetworks
{
"name": "PROXY_SN_B",
"ipCidrRange": "10.130.0.0/23",
"network": "projects/PROJECT_ID/global/networks/NETWORK",
"region": "projects/PROJECT_ID/regions/REGION_B",
"purpose": "GLOBAL_MANAGED_PROXY",
"role": "ACTIVE"
}
This example uses the following firewall rules:
fw-ilb-to-backends. An ingress rule, applicable to the instances being load
balanced, that allows incoming SSH connectivity on TCP port 22 from any
address. You can choose a more restrictive source IP address range for this rule; for
example, you can specify just the IP address ranges of the system from which you
initiate SSH sessions. This example uses the target tag allow-ssh to
identify the VMs that the firewall rule applies to.
fw-healthcheck. An ingress rule, applicable to the instances
being load balanced, that allows all TCP traffic from the Google Cloud
health checking systems (in 130.211.0.0/22 and 35.191.0.0/16). This
example uses the target tag load-balanced-backend to identify the VMs that
the firewall rule applies to.
fw-backends. An ingress rule, applicable to the instances being
load balanced, that allows TCP traffic on ports 80, 443, and 8080 from
the internal proxy Network Load Balancer's managed proxies. This example uses the target tag
load-balanced-backend to identify the VMs that the firewall rule applies to.
Without these firewall rules, the default deny ingress rule blocks incoming traffic to the backend instances.
The target tags define the backend instances. Without the target tags, the firewall rules apply to all of your backend instances in the VPC network. When you create the backend VMs, make sure to include the specified target tags, as shown in Creating a managed instance group.
In the Google Cloud console, go to the Firewall policies page.
Click Create firewall rule to create the rule to allow incoming SSH connections:
fw-ilb-to-backendsallow-ssh0.0.0.0/022 for the port number.Click Create.
Click Create firewall rule a second time to create the rule to allow Google Cloud health checks:
fw-healthcheckload-balanced-backend130.211.0.0/22 and 35.191.0.0/16Protocols and ports:
80 for the port number.As a best practice, limit this rule to just the protocols and ports
that match those used by your health check. If you use tcp:80 for
the protocol and port, Google Cloud can use
HTTP on port 80 to contact your VMs, but it cannot use HTTPS on
port 443 to contact them.
Click Create.
Click Create firewall rule a third time to create the rule to allow the load balancer's proxy servers to connect the backends:
fw-backendsload-balanced-backend10.129.0.0/23 and 10.130.0.0/2380, 443, 8080 for the
port numbers.Click Create.
Create the fw-ilb-to-backends firewall rule to allow SSH connectivity to
VMs with the network tag allow-ssh. When you omit source-ranges,
Google Cloud interprets the rule to mean any
source.
gcloud compute firewall-rules create fw-ilb-to-backends \
--network=NETWORK \
--action=allow \
--direction=ingress \
--target-tags=allow-ssh \
--rules=tcp:22
Create the fw-healthcheck rule to allow Google Cloud
health checks. This example allows all TCP traffic from health check
probers; however, you can configure a narrower set of ports to meet your
needs.
gcloud compute firewall-rules create fw-healthcheck \
--network=NETWORK \
--action=allow \
--direction=ingress \
--source-ranges=130.211.0.0/22,35.191.0.0/16 \
--target-tags=load-balanced-backend \
--rules=tcp
Create the fw-backends rule to allow the internal proxy Network Load Balancer's
proxies to connect to your backends. Set source-ranges to the
allocated ranges of your proxy-only subnet,
for example, 10.129.0.0/23 and 10.130.0.0/23.
gcloud compute firewall-rules create fw-backends \
--network=NETWORK \
--action=allow \
--direction=ingress \
--source-ranges=SOURCE_RANGE \
--target-tags=load-balanced-backend \
--rules=tcp:80,tcp:443,tcp:8080
Create the fw-ilb-to-backends firewall rule by making a POST request to
the firewalls.insert method,
replacing PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/firewalls
{
"name": "fw-ilb-to-backends",
"network": "projects/PROJECT_ID/global/networks/NETWORK",
"sourceRanges": [
"0.0.0.0/0"
],
"targetTags": [
"allow-ssh"
],
"allowed": [
{
"IPProtocol": "tcp",
"ports": [
"22"
]
}
],
"direction": "INGRESS"
}
Create the fw-healthcheck firewall rule by making a POST request to
the firewalls.insert method,
replacing PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/firewalls
{
"name": "fw-healthcheck",
"network": "projects/PROJECT_ID/global/networks/NETWORK",
"sourceRanges": [
"130.211.0.0/22",
"35.191.0.0/16"
],
"targetTags": [
"load-balanced-backend"
],
"allowed": [
{
"IPProtocol": "tcp"
}
],
"direction": "INGRESS"
}
Create the fw-backends firewall rule to allow TCP traffic within the
proxy subnet for the
firewalls.insert method,
replacing PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/firewalls
{
"name": "fw-backends",
"network": "projects/PROJECT_ID/global/networks/NETWORK",
"sourceRanges": [
"10.129.0.0/23",
"10.130.0.0/23"
],
"targetTags": [
"load-balanced-backend"
],
"allowed": [
{
"IPProtocol": "tcp",
"ports": [
"80"
]
},
{
"IPProtocol": "tcp",
"ports": [
"443"
]
},
{
"IPProtocol": "tcp",
"ports": [
"8080"
]
}
],
"direction": "INGRESS"
}
This section shows how to create a template and a managed instance group. The managed instance group provides VM instances running the backend servers of an example cross-region internal proxy Network Load Balancer. For your instance group, you can define an HTTP service and map a port name to the relevant port. The backend service of the load balancer forwards traffic to the named ports. Traffic from clients is load balanced to backend servers. For demonstration purposes, backends serve their own hostnames.
In the Google Cloud console, go to the Instance templates page.
gil4-backendeast1-template.apt-get.allow-ssh and
load-balanced-backend.Click Management. Enter the following script into the Startup script field.
#! /bin/bash apt-get update apt-get install apache2 -y a2ensite default-ssl a2enmod ssl vm_hostname="$(curl -H "Metadata-Flavor:Google" \ http://169.254.169.254/computeMetadata/v1/instance/name)" echo "Page served from: $vm_hostname" | \ tee /var/www/html/index.html systemctl restart apache2
Click Create.
Click Create instance template.
For Name, enter gil4-backendwest1-template.
Ensure that the Boot disk is set to a Debian image, such as
Debian GNU/Linux 12 (bookworm). These instructions use commands that
are only available on Debian, such as apt-get.
Click Advanced options.
Click Networking and configure the following fields:
allow-ssh and
load-balanced-backend.Click Management. Enter the following script into the Startup script field.
#! /bin/bash apt-get update apt-get install apache2 -y a2ensite default-ssl a2enmod ssl vm_hostname="$(curl -H "Metadata-Flavor:Google" \ http://169.254.169.254/computeMetadata/v1/instance/name)" echo "Page served from: $vm_hostname" | \ tee /var/www/html/index.html systemctl restart apache2
Click Create.
In the Google Cloud console, go to the Instance groups page.
gl4-ilb-miga.gil4-backendwest1-template.Specify the number of instances that you want to create in the group.
For this example, specify the following options under Autoscaling:
Off:do not autoscale.2.Optionally, in the Autoscaling section of the UI, you can configure the instance group to automatically add or remove instances based on instance CPU use.
Click Create.
Click Create instance group.
Select New managed instance group (stateless). For more information, see Stateless or stateful MIGs.
For Name, enter gl4-ilb-migb.
For Location, select Single zone.
For Region, select REGION_B.
For Zone, select ZONE_B.
For Instance template, select gil4-backendeast1-template.
Specify the number of instances that you want to create in the group.
For this example, specify the following options under Autoscaling:
Off:do not autoscale.2.Optionally, in the Autoscaling section of the UI, you can configure the instance group to automatically add or remove instances based on instance CPU usage.
Click Create.
The gcloud CLI instructions in this guide assume that you are using Cloud Shell or another environment with bash installed.
Create a VM instance template with HTTP server with the
gcloud compute instance-templates create command.
gcloud compute instance-templates create gil4-backendwest1-template \
--region=REGION_A \
--network=NETWORK \
--subnet=SUBNET_A \
--tags=allow-ssh,load-balanced-backend \
--image-family=debian-12 \
--image-project=debian-cloud \
--metadata=startup-script='#! /bin/bash
apt-get update
apt-get install apache2 -y
a2ensite default-ssl
a2enmod ssl
vm_hostname="$(curl -H "Metadata-Flavor:Google" \
http://169.254.169.254/computeMetadata/v1/instance/name)"
echo "Page served from: $vm_hostname" | \
tee /var/www/html/index.html
systemctl restart apache2'
gcloud compute instance-templates create gil4-backendeast1-template \
--region=REGION_B \
--network=NETWORK \
--subnet=SUBNET_B \
--tags=allow-ssh,load-balanced-backend \
--image-family=debian-12 \
--image-project=debian-cloud \
--metadata=startup-script='#! /bin/bash
apt-get update
apt-get install apache2 -y
a2ensite default-ssl
a2enmod ssl
vm_hostname="$(curl -H "Metadata-Flavor:Google" \
http://169.254.169.254/computeMetadata/v1/instance/name)"
echo "Page served from: $vm_hostname" | \
tee /var/www/html/index.html
systemctl restart apache2'
Create a managed instance group in the zone with the gcloud compute
instance-groups managed create command.
gcloud compute instance-groups managed create gl4-ilb-miga \
--zone=ZONE_A \
--size=2 \
--template=gil4-backendwest1-template
gcloud compute instance-groups managed create gl4-ilb-migb \
--zone=ZONE_B \
--size=2 \
--template=gil4-backendeast1-template
Create the instance template with the
instanceTemplates.insert method,
replacing PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/instanceTemplates
{
"name":"gil4-backendwest1-template",
"properties":{
"machineType":"e2-standard-2",
"tags":{
"items":[
"allow-ssh",
"load-balanced-backend"
]
},
"metadata":{
"kind":"compute#metadata",
"items":[
{
"key":"startup-script",
"value":"#! /bin/bash\napt-get update\napt-get install
apache2 -y\na2ensite default-ssl\na2enmod ssl\n
vm_hostname=\"$(curl -H \"Metadata-Flavor:Google\"
\\\nhttp://169.254.169.254/computeMetadata/v1/instance/name)\"\n
echo \"Page served from: $vm_hostname\" | \\\ntee
/var/www/html/index.html\nsystemctl restart apache2"
}
]
},
"networkInterfaces":[
{
"network":"projects/PROJECT_ID/global/networks/NETWORK",
"subnetwork":"regions/REGION_A/subnetworks/SUBNET_A",
"accessConfigs":[
{
"type":"ONE_TO_ONE_NAT"
}
]
}
],
"disks":[
{
"index":0,
"boot":true,
"initializeParams":{
"sourceImage":"projects/debian-cloud/global/images/family/debian-12"
},
"autoDelete":true
}
]
}
}
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/instanceTemplates
{
"name":"gil4-backendeast1-template",
"properties":{
"machineType":"e2-standard-2",
"tags":{
"items":[
"allow-ssh",
"load-balanced-backend"
]
},
"metadata":{
"kind":"compute#metadata",
"items":[
{
"key":"startup-script",
"value":"#! /bin/bash\napt-get update\napt-get install
apache2 -y\na2ensite default-ssl\na2enmod ssl\n
vm_hostname=\"$(curl -H \"Metadata-Flavor:Google\"
\\\nhttp://169.254.169.254/computeMetadata/v1/instance/name)\"\n
echo \"Page served from: $vm_hostname\" | \\\ntee
/var/www/html/index.html\nsystemctl restart apache2"
}
]
},
"networkInterfaces":[
{
"network":"projects/PROJECT_ID/global/networks/NETWORK",
"subnetwork":"regions/REGION_B/subnetworks/SUBNET_B",
"accessConfigs":[
{
"type":"ONE_TO_ONE_NAT"
}
]
}
],
"disks":[
{
"index":0,
"boot":true,
"initializeParams":{
"sourceImage":"projects/debian-cloud/global/images/family/debian-12"
},
"autoDelete":true
}
]
}
}
Create a managed instance group in each zone with the
instanceGroupManagers.insert method,
replacing PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/{zone}/instanceGroupManagers
{
"name": "gl4-ilb-miga",
"zone": "projects/PROJECT_ID/zones/ZONE_A",
"instanceTemplate": "projects/PROJECT_ID/global/instanceTemplates/gil4-backendwest1-template",
"baseInstanceName": "gl4-ilb-miga",
"targetSize": 2
}
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/zones/{zone}/instanceGroupManagers
{
"name": "gl4-ilb-migb",
"zone": "projects/PROJECT_ID/zones/ZONE_A",
"instanceTemplate": "projects/PROJECT_ID/global/instanceTemplates/gil4-backendwest1-template",
"baseInstanceName": "gl4-ilb-migb",
"targetSize": 2
}
This section creates the following cross-region internal proxy Network Load Balancer resources:
SUBNET_A or
SUBNET_B IP address range. If you
try to use the proxy-only subnet,
forwarding rule creation fails.Sometimes Google Cloud regions don't have enough proxy capacity for a new load balancer. If this happens, the Google Cloud console provides a proxy availability warning message when you are creating your load balancer. To resolve this issue, you can do one of the following:
Wait for the capacity issue to be resolved.
In the Google Cloud console, go to the Load balancing page.
Basic configuration
Configure the frontend with two forwarding rules
Reserve a proxy-only subnet
10.1.2.99.Reserve a proxy-only subnet
10.1.3.99.http.global-http-health-check.HTTP.80.gl4-ilb-miga in
REGION_A.80.gl4-ilb-migb in
REGION_B.80.Review the configuration
Define the TCP health check with the gcloud compute health-checks
create tcp command.
gcloud compute health-checks create tcp global-health-check \ --use-serving-port \ --global
Define the backend service with the gcloud compute backend-services
create command.
gcloud compute backend-services create gl4-gilb-backend-service \ --load-balancing-scheme=INTERNAL_MANAGED \ --protocol=TCP \ --enable-logging \ --logging-sample-rate=1.0 \ --health-checks=global-health-check \ --global-health-checks \ --global
Add backends to the backend service with the gcloud compute backend-services
add-backend command.
gcloud compute backend-services add-backend gl4-gilb-backend-service \ --balancing-mode=CONNECTION \ --max-connections=50 \ --instance-group=gl4-ilb-miga \ --instance-group-zone=ZONE_A \ --global
gcloud compute backend-services add-backend gl4-gilb-backend-service \ --balancing-mode=CONNECTION \ --max-connections=50 \ --instance-group=gl4-ilb-migb \ --instance-group-zone=ZONE_B \ --global
Create the target proxy.
Create the target proxy with the gcloud compute target-tcp-proxies
create command.
gcloud compute target-tcp-proxies create gilb-tcp-proxy \ --backend-service=gl4-gilb-backend-service \ --global
Create two forwarding rules, one with a VIP (10.1.2.99) in
REGION_B and another one with a VIP (10.1.3.99)
in REGION_A. For more information,
see Reserve a static internal IPv4 address.
For custom networks, you must reference the subnet in the forwarding rule. Note that this is the VM subnet, not the proxy subnet.
Use the gcloud compute forwarding-rules
create command
with the correct flags.
gcloud compute forwarding-rules create gil4forwarding-rule-a \ --load-balancing-scheme=INTERNAL_MANAGED \ --network=NETWORK \ --subnet=SUBNET_A \ --subnet-region=REGION_A \ --address=10.1.2.99 \ --ports=80 \ --target-tcp-proxy=gilb-tcp-proxy \ --global
gcloud compute forwarding-rules create gil4forwarding-rule-b \ --load-balancing-scheme=INTERNAL_MANAGED \ --network=NETWORK \ --subnet=SUBNET_B \ --subnet-region=REGION_B \ --address=10.1.3.99 \ --ports=80 \ --target-tcp-proxy=gilb-tcp-proxy \ --global
Create the health check by making a POST request to the
healthChecks.insert method,
replacing PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/healthChecks
{
"name": "global-health-check",
"type": "TCP",
"httpHealthCheck": {
"portSpecification": "USE_SERVING_PORT"
}
}
Create the global backend service by making a POST request to the
backendServices.insert method,
replacing PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendServices
{
"name": "gl4-gilb-backend-service",
"backends": [
{
"group": "projects/PROJECT_ID/zones/ZONE_A/instanceGroups/gl4-ilb-miga",
"balancingMode": "CONNECTION"
},
{
"group": "projects/PROJECT_ID/zones/ZONE_B/instanceGroups/gl4-ilb-migb",
"balancingMode": "CONNECTION"
}
],
"healthChecks": [
"projects/PROJECT_ID/regions/global/healthChecks/global-health-check"
],
"loadBalancingScheme": "INTERNAL_MANAGED"
}
Create the target TCP proxy by making a POST request to the
targetTcpProxies.insert method,
replacing PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/targetTcpProxy
{
"name": "l4-ilb-proxy",
}
Create the forwarding rule by making a POST request to the
forwardingRules.insert method,
replacing PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/forwardingRules
{
"name": "gil4forwarding-rule-a",
"IPAddress": "10.1.2.99",
"IPProtocol": "TCP",
"portRange": "80-80",
"target": "projects/PROJECT_ID/global/targetTcpProxies/l4-ilb-proxy",
"loadBalancingScheme": "INTERNAL_MANAGED",
"subnetwork": "projects/PROJECT_ID/regions/REGION_A/subnetworks/SUBNET_A",
"network": "projects/PROJECT_ID/global/networks/NETWORK",
"networkTier": "PREMIUM"
}
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/forwardingRules
{
"name": "gil4forwarding-rule-b",
"IPAddress": "10.1.3.99",
"IPProtocol": "TCP",
"portRange": "80-80",
"target": "projects/PROJECT_ID/global/targetTcpProxies/l4-ilb-proxy",
"loadBalancingScheme": "INTERNAL_MANAGED",
"subnetwork": "projects/PROJECT_ID/regions/REGION_B/subnetworks/SUBNET_B",
"network": "projects/PROJECT_ID/global/networks/NETWORK",
"networkTier": "PREMIUM"
}
Create the forwarding rule by making a POST request to the
globalForwardingRules.insert method,
replacing PROJECT_ID with your project ID.
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/forwardingRules
{
"name": "gil4forwarding-rule-a",
"IPAddress": "10.1.2.99",
"IPProtocol": "TCP",
"portRange": "80-80",
"target": "projects/PROJECT_ID/global/targetTcpProxies/l4-ilb-proxy",
"loadBalancingScheme": "INTERNAL_MANAGED",
"subnetwork": "projects/PROJECT_ID/regions/REGION_A/subnetworks/SUBNET_A",
"network": "projects/PROJECT_ID/global/networks/NETWORK",
"networkTier": "PREMIUM"
}
POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/forwardingRules
{
"name": "gil4forwarding-rule-b",
"IPAddress": "10.1.3.99",
"IPProtocol": "TCP",
"portRange": "80-80",
"target": "projects/PROJECT_ID/global/targetTcpProxies/l4-ilb-proxy",
"loadBalancingScheme": "INTERNAL_MANAGED",
"subnetwork": "projects/PROJECT_ID/regions/REGION_B/subnetworks/SUBNET_B",
"network": "projects/PROJECT_ID/global/networks/NETWORK",
"networkTier": "PREMIUM"
}
Create a client VM in REGION_B and REGION_A regions:
gcloud compute instances create l4-ilb-client-a \
--image-family=debian-12 \
--image-project=debian-cloud \
--network=NETWORK \
--subnet=SUBNET_A \
--zone=ZONE_A \
--tags=allow-ssh
gcloud compute instances create l4-ilb-client-b \
--image-family=debian-12 \
--image-project=debian-cloud \
--network=NETWORK \
--subnet=SUBNET_B \
--zone=ZONE_B \
--tags=allow-ssh
Use SSH to connect to each client instance.
gcloud compute ssh l4-ilb-client-a --zone=ZONE_A
gcloud compute ssh l4-ilb-client-b --zone=ZONE_B
Verify that the IP address is serving its hostname
Verify that the client VM can reach both IP addresses. The command should succeed and return the name of the backend VM which served the request:
curl 10.1.2.99
curl 10.1.3.99
Verify failover to backends in the REGION_A region
when backends in the REGION_B are unhealthy or
unreachable. To simulate failover, remove all backends from
REGION_B:
gcloud compute backend-services remove-backend gl4-gilb-backend-service \ --instance-group=gl4-ilb-migb \ --instance-group-zone=ZONE_B \ --global
Connect using SSH to a client VM in REGION_B.
gcloud compute ssh l4-ilb-client-b \ --zone=ZONE_B
Send requests to the load balanced IP address in the REGION_B region.
The command output shows responses from backend VMs in REGION_A:
{
RESULTS=
for i in {1..100}
do
RESULTS="$RESULTS:$(curl 10.1.3.99)"
done
echo "***"
echo "*** Results of load-balancing to 10.1.3.99: "
echo "***"
echo "$RESULTS" | tr ':' '\n' | grep -Ev "^$" | sort | uniq -c
echo
}
This section expands on the configuration example to provide alternative and additional configuration options. All of the tasks are optional. You can perform them in any order.
This section shows you how to create a load balancer that can use SNI-based routing. SNI-based routing lets your proxy Network Load Balancers route traffic to specific backend services based on the Server Name Indication (SNI) hostname provided during the TLS handshake.
To create this load balancer we use the same networks, subnets, and firewall rules created previously on this page. You configure the deployment shown in the following diagram:
This section shows you how to create a managed instance group (MIG) backends for the load balancer. The MIG provides VM instances running the backend servers for this example.
The Google Cloud CLI instructions in this guide assume that you are using
Cloud Shell or another environment with bash installed.
Create an instance template with an "echo" HTTPS service that is exposed on port 443.
gcloud compute instance-templates create INSTANCE_TEMPLATE_NAME \
--region=REGION_A \
--network=NETWORK \
--subnet=SUBNET_A \
--stack-type=IPv4_ONLY \
--tags=allow-ssh,load-balanced-backend \
--image-family=debian-12 \
--image-project=debian-cloud \
--metadata=startup-script='#! /bin/bash
sudo sed -i "s/^#DNS=.*/DNS=8.8.8.8 8.8.4.4/" /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved
sudo rm -rf /var/lib/apt/lists/*
sudo apt-get -y clean
sudo apt-get -y update
sudo apt-get -y install ca-certificates curl gnupg software-properties-common
sudo curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
sudo apt-get -y update
sudo apt-get -y install docker-ce
sudo which docker
echo "{ \"registry-mirrors\": [\"https://mirror.gcr.io\"] }" | sudo tee -a /etc/docker/daemon.json
sudo service docker restart
sudo docker run -e HTTPS_PORT=9999 -p 443:9999 --rm -dt mendhak/http-https-echo:22'
Replace the following:
INSTANCE_TEMPLATE_NAME: a name for the instance
template.REGION_A: the region for the instance template.NETWORK: the name of the network.SUBNET_A: the name of the subnetwork.Create a managed instance group based on the instance template:
gcloud compute instance-groups managed create INSTANCE_GROUP_NAME \ --zone=ZONE_A \ --size=2 \ --template=INSTANCE_TEMPLATE_NAME
Replace ZONE_A with the zone for the instance group.
Set the name of the serving port for the managed instance group:
gcloud compute instance-groups managed set-named-ports INSTANCE_GROUP_NAME \ --named-ports=PORT_NAME:PORT_NUMBER \ --zone=ZONE_A
Replace the following:
PORT_NAME: a name for the serving port—for example, tcp443.PORT_NUMBER: a port number for the serving port—for example, 443.Configure a firewall rule to allow traffic from the load balancer and from the health check probes to the backend instances.
gcloud compute firewall-rules create FIREWALL_RULE_NAME \
--network=NETWORK \
--action=allow \
--direction=ingress \
--source-ranges=35.191.0.0/16,130.211.0.0/22 \
--target-tags=allow-health-check \
--rules=tcp:443
Replace FIREWALL_RULE_NAME with a name for the firewall
rule.
Create an HTTPS health check:
gcloud compute health-checks create http HTTPS_HEALTH_CHECK_NAME \
--global \
--port=HC_PORT
Replace the following:
HTTP_HEALTH_CHECK_NAME: a name for the health check.HC_PORT: the port for the health check.Create a backend service:
gcloud compute backend-services create BACKEND_SERVICE_NAME \
--load-balancing-scheme=INTERNAL_MANAGED \
--protocol=TCP \
--port-name=PORT_NAME \
--health-checks=global-health-check \
--global-health-checks \
--global
Replace the following:
BACKEND_SERVICE_NAME: a name for the backend
service.PORT_NAME: the port name for the backend service.
Use the same named port configured on the instance group—for example,
tcp443.HTTPS_HEALTH_CHECK_NAME: the name of the HTTPS
health check.Add the backend instance group to your backend service:
gcloud compute backend-services add-backend BACKEND_SERVICE_NAME \
--balancing-mode=UTILIZATION \
--max-utilization=0.8 \
--instance-group=INSTANCE_GROUP_NAME \
--instance-group-zone=ZONE_A \
--global
Replace the following:
INSTANCE_GROUP_NAME: the name of the backend instance group.ZONE_A: the zone of the instance group.Create a target TCP proxy.
gcloud beta compute target-tcp-proxies create TARGET_TCP_PROXY_NAME \
--load-balancing-scheme=INTERNAL_MANAGED \
--proxy-header=NONE \
--global
Replace TARGET_TCP_PROXY_NAME with the name of the
target TCP proxy.
Create a TLS route specification and save it to a YAML file.
cat <<EOF | tee YAML_FILE_NAME
name: TLS_ROUTE_NAME
targetProxies:
- projects/PROJECT_NUMBER/locations/global/targetTcpProxies/TARGET_TCP_PROXY
rules:
- matches:
- sniHost:
- example.com
action:
destinations:
- serviceName: projects/PROJECT_NUMBER/locations/global/backendServices/BACKEND_SERVICE
EOF
Replace the following:
YAML_FILE_NAME: a name for the YAML file—for example, tls-route.yaml.TLS_ROUTE_NAME: a name for the TLS route.PROJECT_NUMBER: the project number.Use the YAML specification file to create the TLS route resource.
gcloud network-services tls-routes import TLS_ROUTE_NAME \ --source=YAML_FILE_NAME \ --global
Create the forwarding rule.
gcloud compute forwarding-rules create FORWARDING_RULE_NAME \ --load-balancing-scheme=INTERNAL_MANAGED \ --network=NETWORK \ --subnet=SUBNET_A \ --subnet-region=REGION_A \ --address=IP_ADDRESS \ --ports=PORT \ --target-tcp-proxy=TARGET_TCP_PROXY_NAME \ --global
Replace the following:
FORWARDING_RULE_NAME: a name for the forwarding rule.NETWORK: the name of the network.SUBNET_A: the name of the subnetwork in the same
region as the load balancer.IP_ADDRESS: the IP address of the load balancer.PORT_NUMBER: the port used by the forwarding
rule—for example, 443.Now that you have configured your load balancer, you can test sending traffic to the load balancer's IP address.
Verify that you can access the HTTPS service through the load balancer.
curl https://example.com --resolve example.com:443:IP_ADDRESS -k
You will see the command returning a response from one of the VMs in the managed instance group with the following printed to the console.
"path": "/",
"headers": {
"host": "example.com",
"user-agent": "curl/7.81.0",
"accept": "*/*"
},
"method": "GET",
"body": "",
"fresh": false,
"hostname": "example.com",
"ip": "::ffff:10.142.0.2",
"ips": [],
"protocol": "https",
"query": {},
"subdomains": [],
"xhr": false,
"os": {
"hostname": "0cd3aec9b351"
},
"connection": {
"servername": "example.com"
}
You can further verify that if you provide a different SNI hostname that doesn't match a TLS route, or if you don't provide an SNI hostname at all, the request is dropped.
curl https://unknown.com --resolve unknown.com:443:IP_ADDRESS -k
curl example.com:443 --resolve example.com:443:IP_ADDRESS -k
These commands return the following error.
curl: (35) OpenSSL SSL_connect: Connection reset by peer in connection
You'll see the connection_refused error code in the proxyStatus
logs
when the load balancer refuses such invalid connections.
The internal proxy Network Load Balancer terminates TCP connections from the client and creates new connections to the VM instances. By default, the original client IP and port information is not preserved.
To preserve and send the original connection information to your instances, enable PROXY protocol (version 1). This protocol sends an additional header that contains the source IP address, destination IP address, and port numbers to the instance as a part of the request.
Make sure that the internal proxy Network Load Balancer's backend instances are running HTTP or HTTPS servers that support PROXY protocol headers. If the HTTP or HTTPS servers are not configured to support PROXY protocol headers, the backend instances return empty responses. For example, the PROXY protocol doesn't work with the Apache HTTP Server software. You can use different web server software, such as Nginx.
If you set the PROXY protocol for user traffic, you must also set it for your
health checks. If you are checking health and serving
content on the same port, set the health check's --proxy-header to match your
load balancer setting.
The PROXY protocol header is typically a single line of user-readable text in the following format:
PROXY TCP4 <client IP> <load balancing IP> <source port> <dest port>\r\n
Following is an example of the PROXY protocol:
PROXY TCP4 192.0.2.1 198.51.100.1 15221 110\r\n
In the preceding example, the client IP is 192.0.2.1, the load balancing IP is
198.51.100.1, the client port is 15221, and the destination port is 110.
In cases where the client IP is not known, the load balancer generates a PROXY protocol header in the following format:
PROXY UNKNOWN\r\n
The example load balancer setup on this page shows you how to enable the PROXY protocol header while creating the internal proxy Network Load Balancer. Use these steps to change the PROXY protocol header for an existing target TCP proxy.
In the Google Cloud console, go to the Load balancing page.
Click Edit for your load balancer.
Click Frontend configuration.
Change the value of the Proxy protocol field to On.
Click Update to save your changes.
In the following command, edit the --proxy-header field and set it to
either NONE or PROXY_V1 depending on your requirement.
gcloud compute target-ssl-proxies update int-tcp-target-proxy \
--proxy-header=[NONE | PROXY_V1]
For multiple internal forwarding rules to share the same internal IP address,
you must reserve the IP address and set its --purpose flag to
SHARED_LOADBALANCER_VIP.
gcloud compute addresses create SHARED_IP_ADDRESS_NAME \
--region=REGION \
--subnet=SUBNET_NAME \
--purpose=SHARED_LOADBALANCER_VIP
The example configuration creates a backend service without session affinity.
These procedures show you how to update a backend service for an example load balancer so that the backend service uses client IP affinity or generated cookie affinity.
When client IP affinity is enabled, the load balancer directs a particular client's requests to the same backend VM based on a hash created from the client's IP address and the load balancer's IP address (the internal IP address of an internal forwarding rule).
To enable client IP session affinity:
Use the following gcloud command to update the BACKEND_SERVICE
backend service, specifying client IP session affinity:
gcloud compute backend-services update BACKEND_SERVICE \
--global \
--session-affinity=CLIENT_IP
You can enable connection draining on backend services to ensure minimal interruption to your users when an instance that is serving traffic is terminated, removed manually, or removed by an autoscaler. To learn more about connection draining, read the Enabling connection draining documentation.
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2026-06-09 UTC.