Azure Application Gateway: Understanding Health Probes, Host Headers and SNI

Overview

Azure Application Gateway (AppGW) is an application-layer reverse proxy. It accepts client connections and forwards requests to healthy backend targets using its listeners, routing rules, backend pools and backend settings. It also creates its own health-check requests, independently of client traffic.

That independence is the key to understanding why a custom probe sometimes needs an explicit hostname, even when normal backend requests already carry the correct Host header.

This article covers:

  • The difference between a destination IP, HTTP Host header and TLS Server Name Indication (SNI).
  • How normal requests differ from health probes.
  • Default and custom probes, including hostname inheritance.
  • Why a probe may not be eligible for association with particular backend settings.
  • Practical troubleshooting and traffic-capture examples.

Key principle

Preserving a hostname is not the same as configuring a hostname. Backend settings with no hostname override can forward the client’s Host header, but an independent health probe has no client request from which to obtain that header.

1. Example environment

Assume the following example deployment. The hostname and private IP are generic lab values:

ComponentValue
Public application URLhttps://app.example.com/
Application GatewayAzure Application Gateway v2
Backend pool member10.0.0.4
Backend protocolHTTPS
Backend port443
Backend hostname overrideDisabled
Custom health-check path/

The backend might host multiple HTTPS websites or virtual hosts on the same IP address. In such an environment, the hostname is essential for selecting the correct application and TLS certificate.

2. Three different network concepts

Do not confuse the following values:

ValuePurposeExample
Destination IP addressWhere AppGW establishes a backend TCP connection10.0.0.4
HTTP Host headerWhich HTTP virtual host/application is requestedapp.example.com
TLS SNIWhich server name the client of the backend TLS connection requests during the TLS handshakeapp.example.com

For HTTPS, SNI appears during the TLS handshake, whereas the HTTP Host header appears inside the encrypted HTTP request (unless TLS is decrypted at an observation point).

The domain name in a Host header does not automatically mean that AppGW performs DNS resolution for that domain. If the backend pool member is the literal IP 10.0.0.4, that remains the destination IP.

3. What happens to a normal client request?

A client opens:

https://app.example.com/

Conceptually, the inbound HTTP request contains:

GET / HTTP/1.1
Host: app.example.com

Application Gateway matches the listener and routing rule, chooses an eligible healthy backend, and connects to the target specified by the backend pool.

With Override with new host name = No, AppGW normally preserves the original Host header when forwarding the request:

Client
  |
  | HTTPS request
  | Host: app.example.com
  v
Application Gateway
  |
  | Backend pool target: 10.0.0.4
  | Backend settings: HTTPS / 443
  | Hostname override: No
  v
10.0.0.4:443
  |
  | HTTP request after TLS termination:
  | GET / HTTP/1.1
  | Host: app.example.com
  v
Backend virtual host: app.example.com

AppGW terminates the frontend TLS connection and, when HTTPS backend settings are used, initiates a separate TLS connection to the backend. On AppGW v2, the backend SNI selection depends on the backend TLS validation configuration; under complete validation, a configured backend hostname takes precedence and otherwise the incoming client’s hostname may be used.

Important distinction: The backend setting isn’t storing app.example.com. It is applying a rule: keep whichever hostname the client supplied.

4. Why health probes are different

A health probe is not a forwarded user request. AppGW generates and sends it independently, on its own schedule, to determine whether the backend is healthy.

                 Client traffic
Client ------------------------------> Application Gateway
                                           |
                                           | Forwarded request
                                           | (client Host preserved)
                                           v
                                         Backend
                                           ^
                                           |
                                           | Independent health-check GET
                                           |
                                    Application Gateway
                                    (probe generator)

For a probe, there is no incoming client request and therefore no incoming client Host header to preserve.

That resolves an otherwise confusing question:

If backend settings say “preserve the original Host header,” why can’t the health probe simply pick that hostname from backend settings?

Because “preserve the original Host header” is a runtime forwarding behaviour, not a stored hostname value. The probe must obtain its hostname from somewhere explicit, such as its own custom-probe configuration or a hostname configured in backend settings.

A probe does not borrow the hostname from the most recent client request. Nor is a probe intrinsically tied to one particular client hostname merely because a routing rule accepts that hostname.

5. Default health probes

If no custom probe is associated with backend settings, AppGW automatically generates a default probe for active backend/backend-setting combinations.

For the example configuration, where no hostname is explicitly configured in backend settings:

TCP destination: 10.0.0.4:443
Protocol:        HTTPS
Request path:    /
HTTP Host:       127.0.0.1

The HTTP request is conceptually:

GET / HTTP/1.1
Host: 127.0.0.1

This does not mean the network connection goes to loopback. The TCP destination is still 10.0.0.4:443. The 127.0.0.1 value is the probe’s logical hostname/Host header when no hostname is specified in backend settings.

Default settings include:

PropertyDefault
Path/
Interval30 seconds
Timeout30 seconds
Unhealthy threshold3 consecutive failures
Healthy HTTP response codes200–399
Protocol and portInherited from the relevant backend settings
Hostname127.0.0.1 unless a hostname is specified in backend settings

For HTTPS, an IP-literal hostname such as 127.0.0.1 is not sent as a TLS SNI server_name. A backend that depends on SNI may therefore present a default/fallback certificate or reject the connection. This is one reason default probes can fail even when an application is accessible by its normal FQDN.

Backend state

AppGW begins probing when the listener, rule, backend pool and backend settings are associated. It forwards normal client traffic only to backend targets considered healthy. A failed probe can lead to HTTP 502 errors for requests that otherwise would have reached the application.

6. Custom health probes

A custom probe lets you set the hostname, path, interval, timeout, response matching and other parameters.

Scenario A: Hostname set explicitly on the probe

Backend pool:

10.0.0.4

Backend settings:

Protocol: HTTPS
Port: 443
Override with new host name: No

Custom probe:

Protocol: HTTPS
Pick host name from backend settings: No
Host: app.example.com
Pick port from backend settings: Yes
Path: /

Result:

TCP destination: 10.0.0.4:443
HTTP Host:       app.example.com
TLS SNI:         app.example.com (normal v2 complete-validation behaviour)

The HTTP request looks approximately like:

GET / HTTP/1.1
Host: app.example.com

This is useful when normal traffic must preserve each client’s original Host header, while the health probe needs one stable, explicitly selected virtual host.

Scenario B: Hostname inherited from backend settings

Backend settings:

Protocol: HTTPS
Port: 443
Override with new host name: Yes
Override with specific domain name: app.example.com

Custom probe:

Protocol: HTTPS
Pick host name from backend settings: Yes
Pick port from backend settings: Yes
Path: /

Result:

TCP destination: 10.0.0.4:443
HTTP Host:       app.example.com

The custom probe can inherit the concrete hostname because that hostname is stored in the backend setting.

However, the hostname override also changes the Host header forwarded for normal client requests. That may matter for applications depending on original hostnames, redirects, cookies, or multi-tenant routing.

Scenario C: No hostname override, but “pick hostname from backend settings” selected

Backend settings:

Override with new host name: No

Custom probe:

Pick host name from backend settings: Yes

This is the confusing case. Backend settings do not have a concrete hostname for the probe to inherit; they only preserve the live client’s Host header. But the probe has no live client request.

As a result, this is not the appropriate inheritance configuration. In the Azure portal, the available backend settings are filtered based on compatibility with the probe’s Pick host name from backend settings option.

The general principle is that a hostname must be explicitly known to the independently generated probe.

7. Why can’t some backend settings be selected for a custom probe?

In the Azure portal, backend settings shown for custom-probe association are filtered. Microsoft documents these conditions:

  1. Protocol compatibility: The probe and backend settings must use the same protocol.
  2. Hostname-mode compatibility: The probe’s “Pick host name from backend settings” setting must be compatible with the backend setting’s hostname mode.
  3. Existing association: A given backend setting can have only one associated custom probe.

Also, creating a probe alone does not activate it. The probe must be associated with backend settings used by a routing rule and backend pool.

Association is not selection of a destination by DNS

The backend pool supplies the actual backend target. The backend setting supplies how AppGW connects to that target. The custom probe supplies (or inherits) the HTTP probe hostname and path. These are separate responsibilities.

8. HTTPS: Host header, SNI and certificates

With an HTTPS backend, AppGW establishes a TLS session before sending its HTTP GET request.

A simplified sequence is:

Application Gateway                   Backend 10.0.0.4:443
       |                                         |
       |--- TCP connection -------------------->|
       |--- TLS ClientHello (SNI if set) ------>|
       |<-- TLS server certificate -------------|
       |<-- TLS handshake --------------------->|
       |--- Encrypted HTTP GET ---------------->|
       |    Host: app.example.com              |
       |<-- Encrypted HTTP response ------------|
       |                                         |

Three separate things can go wrong:

  • Network connectivity: TCP/443 cannot be established.
  • TLS: The backend presents an unsuitable certificate, lacks a suitable certificate for SNI, or TLS negotiation/validation fails.
  • HTTP: The TLS session works, but the requested virtual host or path returns an unhealthy status (for example, 404, 403, or 500).

For Application Gateway v2, Microsoft documents that a custom probe hostname can influence both the HTTP Host header and TLS SNI. Configurable TLS validation can specify an SNI name or skip certificate subject-name validation. Skipping validation does not by itself establish that the SNI extension is absent; check the active configuration and handshake rather than assuming Host and SNI are identical.

The portal’s one-off probe test does not apply all backend TLS validation settings, so its result can differ from periodic health probes. See backend HTTPS validation settings.

In particular, Host: 127.0.0.1 does not imply SNI: 127.0.0.1. IP literals are not valid TLS server_name values.

9. Request comparison

For the running example:

RequestDestinationHTTP Host headerHow the hostname is chosen
Normal client request, no override10.0.0.4:443app.example.comPreserved from the client request
Default probe, no explicit backend hostname10.0.0.4:443127.0.0.1Default probe behaviour
Custom probe, explicit hostname10.0.0.4:443app.example.comCustom probe’s Host field
Custom probe, inherited hostname10.0.0.4:443app.example.comExplicit hostname configured in backend settings

All four requests can target the same IP address while carrying different HTTP Host headers.

10. Reproduce a probe with curl

To test the backend directly, without allowing DNS to send your request somewhere else:

curl -vk --http1.1 \
  --resolve app.example.com:443:10.0.0.4 \
  https://app.example.com/

This instructs curl to:

  • Open the TCP connection to 10.0.0.4:443.
  • Use app.example.com as the URL hostname.
  • Send Host: app.example.com.
  • Supply the hostname in TLS SNI (when appropriate).

To test the default probe’s HTTP Host behaviour instead, one possible approximation is:

curl -vk --http1.1 \
  https://10.0.0.4/ \
  -H 'Host: 127.0.0.1'

This uses the backend IP as the URL host and sets the HTTP Host header to 127.0.0.1; it normally does not send DNS-name SNI. It is an approximation of the HTTP/TLS request, not a perfect reproduction of AppGW certificate-validation behaviour.

The -k flag disables curl’s certificate verification for diagnosis. It does not mean Application Gateway ignores certificate errors. Remove -k when testing certificate trust, and use a suitable --cacert if a private CA is involved.

11. Capture and inspect probe traffic

For a private backend, probe traffic generally originates from an AppGW instance IP within the Application Gateway subnet. Its destination is the configured backend IP and port.

Linux backend: tcpdump

For HTTP probes on port 80:

sudo tcpdump -i any -nn -s 0 -A \
  'src net <APPGW_SUBNET_CIDR> and dst host 10.0.0.4 and dst port 80'

For HTTPS probes on port 443:

sudo tcpdump -i any -nn -s 0 -w appgw-health-probes.pcap \
  'src net <APPGW_SUBNET_CIDR> and dst host 10.0.0.4 and dst port 443'

HTTPS packet captures show IP/TCP and TLS handshake information, including SNI when sent and visible, but not the encrypted HTTP GET/Host header unless the TLS payload is decrypted.

Wireshark display filters

ip.dst == 10.0.0.4 && tcp.dstport == 443

For plain HTTP:

http.request.method == "GET"

For TLS ClientHello SNI (when present):

tls.handshake.extensions_server_name == "app.example.com"

Other observation points

  • Azure Network Watcher packet capture on a supported Azure VM backend.
  • Backend web-server access logs, e.g. Nginx, Apache or IIS, to see decrypted request paths and Host headers (subject to log format).
  • Firewall/NVA packet capture if probe traffic crosses one, to inspect connectivity and TLS handshakes.
  • Application Gateway → Backend health, to see the gateway’s determination and reported errors.

Application Gateway access logs are intended primarily for client requests; they are not a substitute for capturing each internally generated health-probe request.

12. CLI: inspect configured custom probes

az network application-gateway probe list \
  --gateway-name <APPGW_NAME> \
  --resource-group <RESOURCE_GROUP> \
  --output json

Also inspect the related backend settings, since the settings determine the connection port, hostname handling, TLS validation and probe association:

az network application-gateway http-settings list \
  --gateway-name <APPGW_NAME> \
  --resource-group <RESOURCE_GROUP> \
  --output json

Depending on the AppGW configuration/API version, backend HTTP settings are shown under the corresponding HTTP settings resource. Verify routing-rule associations as well; a probe on an unused backend setting will not actively monitor a backend.

13. Common misconceptions

MisconceptionCorrect interpretation
The Host header determines the destination IPBackend pool targets determine the network destination; the Host header identifies the HTTP virtual host
If hostname override is disabled, backend settings “know” the client’s hostnameThey preserve the incoming hostname on normal requests; they do not store a fixed hostname
Probes use the last client request’s Host headerProbes are independently generated, outside the context of client requests
A default probe with 127.0.0.1 connects to the backend’s loopbackIt connects to the backend pool member IP; 127.0.0.1 is the HTTP Host value
HTTPS probe captures should show the GET request in tcpdumpThe GET/Host fields are encrypted inside TLS
HTTP Host and TLS SNI are always the sameThey are different protocol fields, and backend TLS validation settings can influence SNI independently
Creating a custom probe immediately makes it activeIt must be attached to backend settings that are actually used by a routing rule

Conclusion

The most useful mental model for Azure Application Gateway is:

  1. Backend pool: Where to connect.
  2. Backend settings: How to connect, including protocol, port, hostname handling and TLS validation.
  3. Normal client request: Can preserve the Host header received from the client.
  4. Health probe: An independent request that needs its own determinable hostname.

Therefore, when a backend setting preserves the original client Host header without defining a hostname, a probe cannot dynamically inherit the client’s hostname. You either specify the hostname directly on the custom probe or configure a hostname in backend settings that the probe can inherit. The latter can also change normal request forwarding behaviour.

References