Create custom headers in backend services

This page describes how to configure custom headers in backend services used bythe classic Application Load Balancer.

Custom request and response headers let you specify additional headers thatthe load balancer can add to HTTP(S) requests and responses. Depending on theinformation detected by the load balancer, these headers can include thefollowing information:

  • Latency to the client
  • Geographic location of the client's IP address
  • Parameters of the TLS connection

Customrequest headers are supported for backend services, while customresponse headers are supported for backend services and backend buckets.

The load balancer adds certain headers by default toall HTTP(S) requests and responses that it proxies between backends and clients.For more information, seeTargetproxies.

Before you begin

How custom headers work

Custom headers work as follows:

To enable custom headers, you specify a list of headers in a property of thebackend service or backend bucket.

You specify each header as aheader-name:header-value string. The header mustcontain a colon separating the header name and header value.

Header names must fulfill the following requirements:

  • The header name must be a valid HTTP header-field name definition(perRFC 7230).
  • The header name must not beX-User-IP orCDN-Loop.
  • The following hop-by-hop headers must not be used:Keep-Alive,Transfer-Encoding,TE,Connection,Trailer, andUpgrade. In accordance withRFC 2616,these headers are not stored by caches or propagated by the target proxies.
  • The header name must not begin withX-Google,X-Goog-,X-GFEorX-Amz-.
  • A header name must not appear more than once in the list of added headers.

Header values must fulfill the following requirements:

  • The header value must be a valid HTTP header field definitionperRFC 7230,with obsolete forms disallowed).
  • The header value can be blank.
  • The header value can include one or more variables, enclosed by curly braces,that expand to values that the load balancer provides. A list of variablesallowed in the header value is in the next section.

Thegcloud command-line tool has a flag for specifyingrequest headers, which is--custom-request-header. Make sure to enclose theheader name and header value in straight single quotes (') with this flag.

The general format for the flag is:

    --custom-request-header='HEADER_NAME:[HEADER_VALUE]'

The following is an example of a header value with two variables,client_region andclient_city, enclosed in curly braces.

    --custom-request-header='X-Client-Geo-Location:{client_region},{client_city}'

For clients located in Mountain View, California, the load balancer adds aheader as follows:

X-Client-Geo-Location:US,Mountain View

To create a backend service with custom headers, seeConfigure custom request headers.

Variables supported with header values

The following variables can appear in custom header values.

VariableDescription
cdn_cache_idLocation code and ID of the cache instance used to serve the request. This is the same value populated in thejsonPayload.cacheId field of the Cloud CDN request logs in Logging.
cdn_cache_statusCurrent cache status. Values can behit,miss,revalidated,stale,uncacheable, ordisabled for any object served by a Cloud CDN-enabled backend.
origin_request_headerReflects the value of theOrigin header in the request for Cross-Origin Resource Sharing (CORS) use cases.
client_rtt_msecEstimated round-trip transmission time between the load balancer and the HTTP(S) client, in milliseconds. This is the smoothed round-trip time (SRTT) parameter measured by the load balancer's TCP stack, perRFC 2988. Smoothed RTT is an algorithm that deals with variations and anomalies that may occur in RTT measurements.
client_regionThe country (or region) associated with the client's IP address. This is a Unicode CLDR region code, such asUS orFR. (For most countries, these codes correspond directly toISO-3166-2 codes.)
client_region_subdivisionSubdivision, for example, a province or state, of the country associated with the client's IP address. This is a Unicode CLDR subdivision ID, such asUSCA orCAON. (These Unicode codes are derived from the subdivisions defined by theISO-3166-2 standard.)
client_cityName of the city from which the request originated, for example,Mountain View for Mountain View, California. There is no canonical list of valid values for this variable. The city names can contain US-ASCII letters, numbers, spaces, and the following characters:!#$%&'*+-.^_`|~.
client_city_lat_longLatitude and Longitude of the city from which the request originated, for example,37.386051,-122.083851 for a request from Mountain View.
client_ip_addressThe client's IP address. This is usually the same as the client IP address that is the next-to-last address in theX-Forwarded-For header, unless the client is using a proxy or theX-Forwarded-For header has been tampered with.
client_portThe client's source port.
client_encryptedtrue if the connection between the client and the load balancer is encrypted (using HTTPS, HTTP/2 or HTTP/3); otherwise,false.
client_protocolThe HTTP protocol used for communication between the client and the load balancer. One ofHTTP/1.0,HTTP/1.1,HTTP/2, orHTTP/3.
device_request_type

The client's device, derived fromUser-Agent header values.

The following are possible values:DESKTOP,GAME_CONSOLE,GAME_CONSOLE,MOBILE,SET_TOP_BOX,SMART_SPEAKER,SMART_TV,TABLET,UNDETERMINED,WEARABLE.

server_ip_addressThe IP address of the load balancer that the client connects to. This can be useful when multiple load balancers share common backends. This is the same as the last IP address in theX-Forwarded-For header.
server_portThe destination port number that the client connects to.
tls_sni_hostnameServer name indication (as defined inRFC 6066), if provided by the client during the TLS or QUIC handshake. The hostname is converted to lowercase and with any trailing dot removed.
tls_versionTLS version negotiated between client and load balancer during the SSL handshake. Possible values include:TLSv1,TLSv1.1,TLSv1.2, andTLSv1.3. If the client connects using QUIC instead of TLS, the value isQUIC.
tls_cipher_suiteCipher suite negotiated during the TLS handshake. The value is four hex digits defined by theIANA TLS Cipher Suite Registry, for example,009C for TLS_RSA_WITH_AES_128_GCM_SHA256. This value is empty for QUIC and for unencrypted client connections.
tls_ja3_fingerprintJA3 TLS/SSL fingerprint if the client connects using HTTPS, HTTP/2, or HTTP/3.
tls_ja4_fingerprintJA4 TLS/SSL fingerprint if the client connects using HTTPS, HTTP/2, or HTTP/3.
user_agent_family

The client's browser type, derived fromUser-Agent header values.

The following are possible values:APPLE,APPLEWEBKIT,BLACKBERRY,DOCOMO,GECKO,GOOGLE,KHTML,KOREAN,MICROSOFT,MSIE,NETFRONT,NOKIA,OBIGO,OPERA,OPENWAVE,OTHER,POLARIS,SEMC,SMIT,TELECA,USER_DEFINED.

The load balancer expands variables to empty strings when it cannot determinetheir values. For example:

  • Geographic location variables when the IP address's location is unknown
  • TLS parameters when TLS is not in use
  • The{origin_request_header} when the request does not include anOrigin header
  • The{cdn_cache_status} header when included in a request header

Geographic values (regions, subdivisions, and cities) are estimates based on theclient's IP address. From time to time, Google updates the data that providesthese values in order to improve accuracy and to reflect geographic andpolitical changes. Even if the originalX-Forwarded-For header contains validlocation information, Google estimates client locations by using the source IPaddress information contained in packets received by the load balancer.

Headers added by the load balancer overwrite any existing headers thathave the same name. Header names are case insensitive. When header namesare passed to an HTTP/2 backend, the HTTP/2 protocol encodes header names aslower case.

In header values, leading whitespace and trailing whitespace are insignificant,and are not passed to the backend. To allow for curly braces in header values,the load balancer interprets two opening curly braces ({{) asa single opening brace ({), and two closing curly braces (}}) as a singleclosing brace (}).

Mutual TLS custom headers

The following additional header variables are available if mutual TLS (mTLS) isconfigured on the load balancer's TargetHttpsProxy.

VariableDescription
client_cert_presenttrue if the client has provided a certificate during the TLS handshake; otherwise,false.
client_cert_chain_verifiedtrue if the client certificate chain is verified against a configuredTrustStore; otherwise,false.
client_cert_errorPredefined strings representing the error conditions. For more information about the error strings, seemTLS client validation modes.
client_cert_sha256_fingerprintBase64-encoded SHA-256 fingerprint of the client certificate.
client_cert_serial_numberThe serial number of the client certificate. If the serial number is longer than 50 bytes, theclient_cert_error is set toclient_cert_serial_number_exceeded_size_limit, and the serial number is set to an empty string.
client_cert_spiffe_id

TheSPIFFE ID from the subject alternative name (SAN) field. If the value is not valid or exceeds 2048 bytes, the SPIFFE ID is set to an empty string.

If the SPIFFE ID is longer than 2048 bytes, theclient_cert_error is set toclient_cert_spiffe_id_exceeded_size_limit.

client_cert_uri_sans

Comma-separated Base64-encoded list of the SAN extensions of type URI. The SAN extensions are extracted from the client certificate. The SPIFFE ID is not included in theclient_cert_uri_sans field.

If theclient_cert_uri_sans is longer than 512 bytes, theclient_cert_error is set toclient_cert_uri_sans_exceeded_size_limit, and the comma-separated list is set to an empty string.

client_cert_dnsname_sans

Comma-separated Base64-encoded list of the SAN extensions of type DNSName. The SAN extensions are extracted from the client certificate.

If theclient_cert_dnsname_sans is longer than 512 bytes, theclient_cert_error is set toclient_cert_dnsname_sans_exceeded_size_limit, and the comma-separated list is set to an empty string.

client_cert_valid_not_beforeTimestamp (RFC 3339 date string format) before which the client certificate is not valid. For example,2022-07-01T18:05:09+00:00.
client_cert_valid_not_afterTimestamp (RFC 3339 date string format) after which the client certificate is not valid. For example,2022-07-01T18:05:09+00:00.
client_cert_issuer_dn

Base64-encoded DER encoding of the full Issuer field from the certificate.

If theclient_cert_issuer_dn is longer than 512 bytes, the stringclient_cert_issuer_dn_exceeded_size_limit is added toclient_cert_error, andclient_cert_issuer_dn is set to an empty string.

client_cert_subject_dn

Base64-encoded DER encoding of the full Subject field from the certificate.

If theclient_cert_subject_dn is longer than 512 bytes, the stringclient_cert_subject_dn_exceeded_size_limit is added toclient_cert_error, andclient_cert_subject_dn is set to an empty string.

client_cert_leaf

The client leaf certificate for an established mTLS connection where the certificate passed validation. Certificate encoding is compliant withRFC 9440. This means the binary DER certificate is encoded using Base64 and delimited with colons on either side.

Ifclient_cert_leaf exceeds 16 KB unencoded, the stringclient_cert_validated_leaf_exceeded_size_limit is added toclient_cert_error, andclient_cert_leaf is set to an empty string.

client_cert_chain

The comma-delimited list of certificates, in standard TLS order, of the client certificate chain for an established mTLS connection where the client certificate passed validation, not including the leaf certificate. Certificate encoding is compliant withRFC 9440.

If the combined size ofclient_cert_leaf andclient_cert_chain before Base64 encoding exceeds 16 KB, the stringclient_cert_validated_chain_exceeded_size_limit is added toclient_cert_error, andclient_cert_chain is set to an empty string.

Configure custom request headers

Console

To add custom request headers to an existing backend service:

  1. Go to the load balancing summary page.
    Go to the Load balancing page
  2. ClickBackends.
  3. Click the name of a backend service.
  4. ClickEdit.
  5. ClickAdvanced configurations (Session affinity, connection drainingtimeout, security policies).
  6. UnderCustom request headers, clickAdd header.
  7. Enter theHeader name andHeader value for the custom requestheader.
  8. Enter any additional custom request headers.
  9. ClickSave.

To remove a custom request header from a backend service:

  1. Go to the load balancing summary page.
    Go to the Load balancing page
  2. ClickBackends.
  3. Click the name of a backend service.
  4. ClickEdit.
  5. ClickAdvanced configurations (Session affinity, connection drainingtimeout, security policies).
  6. Click theX next to the name of the custom request header you wantto remove.
  7. ClickSave.

gcloud

To specify custom request headers, use thegcloud compute backend-servicescreate orgcloud compute backend-servicesupdate commandwith the--custom-request-header flag.

To create a backend service with custom request headers:

gcloud compute backend-services createBACKEND_SERVICE_NAME \    --global-health-checks \    --global \    --protocol HTTPS \    --health-checks https-basic-check \    --custom-request-header='HEADER_NAME:[HEADER_VALUE]'

To add more request headers, specify a unique header name and value byrepeating the--custom-request-header flag.

To add custom headers to an existing backend service:

gcloud compute backend-services updateBACKEND_SERVICE_NAME \    --global \    --custom-request-header='HEADER_1_NAME:[HEADER_1_VALUE]' \    --custom-request-header='HEADER_2_NAME:[HEADER_2_VALUE]'

The previous step replaces any headers already in the backendservice with the request headers that you specify in the command.

To remove all headers from a backend service:

gcloud compute backend-services updateBACKEND_SERVICE_NAME \    --global \    --no-custom-request-headers

API

Make aPATCH request to thebackendServices.patchmethod:

PATCH https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendServices/BACKEND_SERVICE_NAME"customRequestHeaders": [   "client_city:Mountain View"]

Terraform

For a Terraform script that creates a load balancer with custom headers,seeTerraform examples forglobal external Application Load Balancers.

Configure custom response headers

Console

To add custom response headers to an existing backend service:

  1. Go to the load balancing summary page.
    Go to the Load balancing page
  2. ClickBackends.
  3. Click the name of a backend service.
  4. ClickEdit.
  5. ClickAdvanced configurations (Session affinity, connection drainingtimeout, security policies).
  6. UnderCustom response headers, clickAdd header.
  7. Enter theHeader name andHeader value for the custom responseheader.
  8. Enter any additional custom response headers.
  9. ClickSave.

To remove a custom response header from a backend service:

  1. Go to the load balancing summary page.
    Go to the Load balancing page
  2. ClickBackends.
  3. Click the name of a backend service.
  4. ClickEdit.
  5. ClickAdvanced configurations (Session affinity, connection drainingtimeout, security policies).
  6. Click theX next to the name of the custom response header you wantto remove.
  7. ClickSave.

gcloud

For backend services, use thegcloud compute backend-servicescreate orgcloud compute backend-servicesupdate commandwith the--custom-response-header flag.

For backend buckets, use thegcloud compute backend-bucketscreate orgcloud compute backend-bucketsupdate commandwith the--custom-response-header flag.

gcloud compute backend-services (create | update)BACKEND_SERVICE_NAME    --custom-response-header='HEADER_NAME:[HEADER_VALUE]'
gcloud compute backend-buckets (create | update)BACKEND_BUCKET_NAME    --custom-response-header='HEADER_NAME:[HEADER_VALUE]'

Example withX-Frame-Options header:

gcloud compute backend-buckets update gaming-lab \    --custom-response-header='X-Frame-Options: DENY'

Example withStrict-Transport-Security header:

The following example shows you how to add a custom response headerto support HTTP Strict Transport Security (HSTS):

gcloud compute backend-services update customer-bs-name \    --global \    --custom-response-header='Strict-Transport-Security: max-age=63072000'

API

For backend buckets, use theMethod: backendBuckets.insert orMethod: backendBuckets.updateAPI call.

For backend services, use theMethod: backendServices.insert orMethod: backendServices.updateAPI call.

Use one of the following API calls:

POST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendBucketsPUT https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendBuckets/BACKEND_BUCKET_NAMEPOST https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendServicesPUT https://compute.googleapis.com/compute/v1/projects/PROJECT_ID/global/backendServices/BACKEND_SERVICE_NAME

Add the following snippet to the JSON request body:

"customResponseHeaders":HEADER_NAME:[HEADER_VALUE]

Terraform

For a Terraform script that creates a load balancer with custom headers,seeTerraform examples forglobal external Application Load Balancers.

Set response headers for Cloud Storage

If you need to set HTTP headers on responses fromCloud Storage—such as Cross-Origin Resource Policy,X-Frame-Options, orX-XSS-Protection headers—Google Cloud offersthe option to use custom headers for Cloud CDN withCloud Storage. You can do this by configuring custom headers at theload balancer backend bucket level, as described on this page.

Custom response headers configured at the backend bucket level are only addedto responses if the client request is sent to the load balancer IP address.Custom headers are not added to responses if the client's request was madedirectly to the Cloud Storage API.

Use custom headers with Google Cloud Armor

When you configure a Cloud Armor security policy, you can configureCloud Armor to insert a custom header and value. If yourCloud Armor security policy is configured to insert the same customheader name as your global external Application Load Balancer or classic Application Load Balancer's customheaders, then the header value specified in your Cloud Armor security policy is overwritten bythe value populated by the load balancer. If you don'twant the Cloud Armor policy to be overwritten, ensure that you don'tuse the same name.

Limitations

The following limitations apply to custom headers used with global loadbalancers:

  • The total size of all custom request headers (name and value combined,before variable expansion) for each backend service must not exceed 8 KBor 16 request headers.
  • The total size of all custom response headers (name and value combined,before variable expansion) for each backend service must not exceed 8 KBor 16 response headers.

What's next

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-15 UTC.