Spring-boot: Improve "Running Behind a Front-end Proxy Server" documentation

Created on 31 Oct 2018  路  9Comments  路  Source: spring-projects/spring-boot

Spring Boot Version 2.1.0 (and earlier down to 1.x)

Hello,

the documentation regarding Front-end Proxy Server states:

If the proxy adds conventional X-Forwarded-For and X-Forwarded-Proto headers (most proxy servers do so), the absolute links should be rendered correctly ...

This is not fully true, at least not for Tomcat:
The only thing that Tomcat RemoteIpValve (which is activated by server.use-forward-headers) does with X-Forwarded-For header is to determine the 'correct' remote ip address of the client.
(And BTW, this is also the only thing that is currently tested regarding use-forward-headers in Spring Boot: here)

So, the only useful thing that Tomcat RemoteIpValve does regarding absolute links is to set the scheme and the port of the servlet request according to the X-Forwarded headers.

The Tomcat RemoteIpValve does nothing regarding the serverName of the request. But it is essential for rendering correct absolute links that the serverName is set to the host name of the proxy server.

There is an open ticket for Tomcat to do this in RemoteIpValve by using X-Forwarded-Host header. But as long as this is not resolved, the only way to get correct redirect URIs is to make sure that the proxy server leaves the Host header unchanged.

At least this should be clarified in the documentation.

However, there are scenarios, where the Proxy Server changes the host header. Even Spring Cloud Zuul does this (or at least did this) by default (and sets X-Forwarded-Host to preserve proxy host somewhere).

So, it is probably not a good suggestion just to say "use server.use-forward-headers, and everything will be alright behind a proxy."

Spring's ForwardedHeaderFilter (which supports X-Forwarded-Host and X-Forwarded-Prefix) should at least be mentioned as an alternative, even if Spring Boot does not want to make it the default (see here). Especially now with Spring 5.1, where ForwardedHeaderFilter has become the "standard way" to cope with Forwarded-Headers in Spring (see also here).

Additionally there are existing discussions regarding ForwardedHeaderFilter or not, so the difficulties with the use-forward-headers approach are not new. However, someone who just starts by reading the documentation will not know anything about those details and will raise issues or SO questions regarding "it does not work behind proxy".

Best Regards,
Stefan.

documentation

Most helpful comment

It took us 4+ hours of debugging and searching for documentation to get past this hurdle after moving our app behind a gateway (in our case the issue was redirects created by Spring Security were to the wrong url).

I know other solutions are in the works as far as replacing server.use-forward-headers with a strategy enum, but in the meantime the docs really need a note that server.use-forward-headers doesn't work with Tomcat and you need to use the ForwardedHeaderFilter.

It's incredibly frustrating to waste so much time because the docs are just wrong, and have been for 6+ months.

All 9 comments

It seems that 'server.use-forward-headers' does not work in all cases. E.g. I just used Spring Security SAML extension and there OpenSAML "request.getRequestURL()" does not return the scheme set by 'X-Forwarded-Proto'. However writing a simple Spring Boot test (no SAML), the test succeeds. It seems that setting 'server.use-forwared-headers=true' is not a solution in all cases.

Another case that stopped working "out-of-the-box" with Spring Boot 2.1 / Spring Framework 5.1:
Running a Spring Data REST API behind a proxy will not understand "X-Forworded-Prefix" for creating entity links unless you use a ForwardedHeaderFilter now, because ServletUriComponentsBuilder stopped handling that.

@darioseidl , I guess that is kind of documented in the Spring 5.1 Release Notes:
https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-5.x#forwarded-headers

At least, if you dig deeper into the JIRA issue that is mentioned there...

Thanks, yes, that's where I eventually found it. It would be good though to have it mentioned also in the Spring Boot documentation, like you said in this issue.

It took us 4+ hours of debugging and searching for documentation to get past this hurdle after moving our app behind a gateway (in our case the issue was redirects created by Spring Security were to the wrong url).

I know other solutions are in the works as far as replacing server.use-forward-headers with a strategy enum, but in the meantime the docs really need a note that server.use-forward-headers doesn't work with Tomcat and you need to use the ForwardedHeaderFilter.

It's incredibly frustrating to waste so much time because the docs are just wrong, and have been for 6+ months.

See gh-5677.

Have a look also for spring hateoas documentation. I have also my small fight with this issue (hateoas issue 862 for forwarding).
Sidenote, it pops out again, when I have incorporated spring web and spring security. Namely HttpSecurity.formLogin does redirect to local IP.

Meanwhile, Tomcat seems to support X-Forwarded-Host, which makes server.use-forward-headers
(or in 2.2.x and above: ForwardHeadersStrategy.NATIVE) more of an option again.

But:

  • X-Forwarded-Prefix is still not supported
  • For X-Forwarded-Host, only one value seems to be supported. For scenarios with reverse proxy AND an API Gateway (like Zuul or Spring Cloud Gateway), support for multiple values is usually necessary (or at least you have to take some care that the API gateway preserves the original X-Forwarded-Host. See also here for more details). In opposite, ForwardedHeaderFilter allows multiple comma-separated values.

As a note, here the related issues for "RFC7239 Forwarded" support in servers:

Was this page helpful?
0 / 5 - 0 ratings