簡體   English   中英

Apache 代理后面帶有嵌入式 Tomcat 的 Spring Boot

[英]Spring Boot with embedded Tomcat behind Apache proxy

我們有一個 Spring Boot (Spring MVC) 應用程序,在 Apache SSL 代理后面的專用應用程序服務器上嵌入了 Tomcat。

代理服務器上的 SSL 端口是 4433,轉發到應用服務器上的端口 8080。

因此,代理服務器的 URL 轉發如下:

https://proxyserver:4433/appname   >>forward>>   http://appserver:8080/

在沒有代理的情況下運行時,發生的第一件事是
Spring Security 重定向請求,例如:

http://appserver:8080/   >>redirect>>   http://appserver:8080/login

通過擴展WebSecurityConfigurerAdapter來顯示登錄表單

  ...
  httpSecurity.formLogin().loginPage("/login") ...
  ...

它在沒有代理的情況下工作正常,但是使用代理重定向需要更改,
所以 Spring 應該重定向到相應的代理 URL,例如:

http://appserver:8080/   >>redirect>>   https://proxyserver:4433/appname/login

但還沒有成功。

我正在嘗試應用此解決方案: 59.8 Use Tomcat behind a front-end proxy server

我們已經在 Apache 中配置了mod_proxy ,並驗證它發送了預期的標頭:

X-Forwarded-For: xxx.xxx.xxx.xxx
X-Forwarded-Host: proxyserver
X-Forwarded-Port: 4433
X-Forwarded-Proto: https

應用程序以參數啟動:

export ARG1='-Dserver.tomcat.protocol-header=x-forwarded-proto' 
export ARG2='-Dserver.tomcat.remote-ip-header=x-forwarded-for'
java $ARG1 $ARG2 -jar webapp.jar

仍然重定向不起作用。

它將繼續在本地重定向到客戶端無法使用的http://appserver:8080/login

我們還需要做些什么來使這個場景起作用?


更新

另外,我擔心代理 URL 中的“/appname”部分。 在應用程序服務器上,應用程序以“/”為根。 當通過代理時,應該如何指示 Spring 將“/appname”包含在發送回客戶端的所有 URL 中?

前幾天我遇到了同樣的問題。 在對 Spring Boot 1.3 進行一些調試后,我找到了以下解決方案。

1.您必須在 Apache 代理上設置標頭:

<VirtualHost *:443>
    ServerName www.myapp.org
    ProxyPass / http://127.0.0.1:8080/
    RequestHeader set X-Forwarded-Proto https
    RequestHeader set X-Forwarded-Port 443
    ProxyPreserveHost On
    ... (SSL directives omitted for readability)
</VirtualHost>

2.您必須告訴您的 Spring Boot 應用程序使用這些標頭。 所以把下面這行放在你的 application.properties (或任何其他 Spring Boots 理解屬性的地方):

server.use-forward-headers=true

如果你正確地做這兩件事,你的應用程序發送的每個重定向都不會轉到http://127.0.0.1:8080/[path]而是自動轉到https://www.myapp.com/[path]

更新 1.關於這個主題的文檔在這里 您至少應該閱讀它以了解屬性server.tomcat.internal-proxies ,它定義了可以信任的代理服務器的 IP 地址范圍。

更新 2021文檔移至此處 Spring Boot 配置現在有點不同。

您的代理看起來不錯,后端應用程序也是如此,在某種程度上,但它似乎沒有看到RemoteIpValve修改后的請求。 RemoteIpValve的默認行為包括代理 IP 地址的模式匹配(作為安全檢查),它只修改它認為來自有效代理的請求。 Spring Boot 中的模式默認為一組眾所周知的內部 IP 地址,如10.*.*.*192.168.*.* ,因此如果您的代理不在其中之一,則您需要明確配置它,例如

server.tomcat.internal-proxies=172\\.17\\.\\d{1,3}\\.\\d{1,3}|127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}

(使用屬性文件格式,這意味着您必須對反斜杠進行雙重轉義)。

如果您設置,您可以看到RemoteIpValve發生的事情

logging.level.org.apache.catalina.valves.RemoteIpValve=DEBUG

或在其中設置斷點。

這個問題的典型解決方案是讓代理處理任何需要的重寫。 例如,在 Apache 中,您可以使用rewrite_module和/或headers_module來更正標頭。 再舉一個例子,Nginx 會在配置上游服務器后自動為你處理這種情況和其他類似的情況。

回應評論:

remote_ip_header 和 protocol_header spring boot 配置值是什么?

讓我們暫時忘記 Spring Boot。 Tomcat 是嵌入式 servlet 容器,具有稱為 RemoteIpValve 的閥門。 這個閥是 Apache remotip_module 的一個端口。 此閥的主要目的是將“發起請求的用戶代理視為原始用戶代理”以實現“授權和記錄的目的”。 為了使用該閥,需要對其進行配置。

在此處找到有關此閥門的更多信息。

Spring Boot 通過 server.tomcat.remote_ip_header 和 server.tomcat.protocol_header 屬性通過 application.properties 方便地支持配置此閥。

我有完全相同的情況,使用 haproxy 作為具有以下配置的負載均衡器,這對我來說很合適。 唯一的問題是客戶端 IP 在request.getRemoteAddr()而不是在"X-Forwarded-For"標頭中

frontend www
  bind *:80
  bind *:443 ssl crt crt_path
  redirect scheme https if !{ ssl_fc }
  mode http
  default_backend servers

backend servers
  mode http
  balance roundrobin
  option forwardfor
  server S1 host1:port1 check
  server S2 host2:port2 check
  http-request set-header X-Forwarded-Port %[dst_port]
  http-request add-header X-Forwarded-Proto https if { ssl_fc }

在 application.properties 中:

 server.use-forward-headers=true

您可以配置幾個與此相關的屬性。 application.yaml示例:

server:
  forward-headers-strategy: native
  tomcat:
    use-relative-redirects: true
    protocol-header: x-forwarded-proto
    remote-ip-header: x-forwarded-for

設置server.forward-headers-strategy: native是對已棄用的server.use-forward-headers:true的替換

你有沒有試過設置

  server.context-path=/appname

在 Spring Boot 中?

嘗試設置重寫規則,如: https://proxyserver:4433/appname >>forward>> http://appserver:8080/appname

然后將您的應用程序上下文設置為“appname” server.context-path=/appname

因此,您可以在本地通過http://appserver:8080/appname 運行並通過反向代理通過https://proxyserver:4433/appname 訪問

由於我使用的是 JBOSS,因此在 jboss 的 standalone.xm 中發生了變化:

<http-listener name="default" socket-binding="http" redirect-socket="https" proxy-address-forwarding="true" enable-http2="true"/>

Tomcat 會有類似的配置,通知 Tomcat (proxy-address-forwarding="true") 尊重代理轉發地址。

server.use-forward-headers=true對我不起作用,遇到了一個奇怪的問題,即X-Forwarded-For標頭未一致地填充到HttpServletRequest

最終使用ForwardedHeaderFilterhttps : //stackoverflow.com/a/51500554/986942

最重要的是,確保負載均衡器(代理)正確提供以下標頭:

proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM