X-Forwarded-Proto: the scheme the client actually used
X-Forwarded-Proto records the scheme the client used to reach the proxy, so an application receiving plain HTTP internally can tell the original request was HTTPS.
At a glance
- Direction
- Request, added by a proxy that terminates TLS.
- Defined in
- No RFC. A de facto convention, standardised as the proto parameter of Forwarded.
- When absent
- The application sees only its own connection, which behind a TLS terminating proxy is plain HTTP.
- Values
- https or http
- Set by
- The proxy or load balancer that terminated TLS
- Standard equivalent
- The proto parameter inside a Forwarded header
- Classic symptom
- An infinite redirect loop between the proxy and the application
In detail
When a load balancer terminates TLS, the connection it opens to your application is usually plain HTTP. From inside the application every request therefore looks insecure, which is fine until some part of your code makes a decision based on that: building an absolute URL, setting a Secure cookie, or deciding whether to redirect to HTTPS.
The redirect loop is the famous consequence. The application sees http, redirects to https, the browser asks the proxy again over HTTPS, the proxy forwards it as plain HTTP once more, and the application redirects again. The browser gives up after a handful of rounds, and the error mentions nothing about proxies at all.
The fix is to trust this header only from your own edge and use it as the scheme for everything derived from the request. Frameworks generally have a proxy trust setting for exactly this; enabling it globally without restricting which upstream addresses are trusted swaps a redirect loop for a header that any client can set.
It matters for cookies too. A Secure cookie is only sent over HTTPS, and code that decides whether to mark a cookie Secure by looking at the connection scheme will leave that attribute off behind a terminating proxy, which is a genuine downgrade rather than an inconvenience.
Examples
GET /account HTTP/1.1
Host: example.com
X-Forwarded-Proto: https
X-Forwarded-For: 203.0.113.7The connection is plain HTTP, but the visitor reached the edge over HTTPS.
Forwarded: for=203.0.113.7; proto=https; host=example.comThings that catch people out
- Trusting the header from any source lets a client claim https on a plain HTTP request, which can bypass a redirect that exists for a reason.
- Enabling HTTPS redirection in an application behind a terminating proxy without reading this header produces an immediate redirect loop.
- Some proxies send X-Forwarded-Protocol or X-Forwarded-Scheme instead, so code that checks only one name misses the value entirely.
Try it: HTTP Headers Checker
Check a live URL or paste headers you already have. It grades six security headers from A+ to F and lists every other header the response returned.
HTTP Headers Checker
LOCAL · Browser-OnlyView HTTP response headers for any URL
Enter any website URL to fetch and analyze its HTTP response headers. We'll automatically add https:// if needed.
Why Check Security Headers?
Security headers protect your website against common attacks like XSS, clickjacking, and MIME sniffing. They're set by your web server and cost nothing to implement. Missing security headers are one of the most common findings in security audits.
Related HTTP headers
All http headers →X-Forwarded-For: the client address behind a proxy
How the X-Forwarded-For list is built, why the leftmost address is not trustworthy, how to count trusted hops, and what breaks rate limiting behind a proxy.
Forwarded: the standardised proxy header
The syntax of the standard Forwarded header, how it replaces the X-Forwarded set, how to quote IPv6 addresses and ports, and how far to trust it.
Strict-Transport-Security: the HSTS response header
What Strict-Transport-Security does, what max-age and includeSubDomains change, why preload is close to permanent, and how to withdraw the policy safely.
Location: where the client should go next
How Location works on each 3xx status, why it also appears on a 201 Created, whether relative URLs are allowed, and how to avoid an open redirect.
Connection: keep-alive, close and hop by hop headers
What the Connection header controls, how it lists hop by hop headers, why HTTP/1.1 keeps connections open by default, and why HTTP/2 forbids it.
Upgrade: switching protocols on an open connection
How the Upgrade header negotiates a protocol switch, what a 101 response means, why proxies break WebSocket handshakes, and what HTTP/2 does instead.
Tools for this
- HTTP Headers Checker Free online HTTP headers checker - view HTTP response headers for any URL
- Redirect Chain Checker Free online redirect chain checker - trace HTTP redirect chains and hops