Nginx

使用 nginx 為使用自己的證書的 java 客戶端-伺服器應用程序正確重定向流量

  • October 9, 2019

我有一個伺服器和一個客戶端應用程序,它們使用 Https 連接和他們自己的證書(.jks 文件)相互通信。伺服器偵聽埠 443,客戶端使用專用 IP 和伺服器埠連接到它。

最近,我想在同一台機器上添加一個網站/服務。我為該網站註冊了一個新的子域並獲得了 SSL 證書。我正在嘗試找到一種方法讓網站和 Java 應用程序都獲取發送到埠 443 上的伺服器的請求。該網站將獲取與分配給它的子域相關的請求,並且Java 應用程序將獲取與子域無關的請求,並且僅具有伺服器的 IP。

出於測試目的,首先我嘗試使用不同的埠來重定向與 Java 應用程序相關的流量。

server {

 listen           127.0.0.1;
 listen           25005;
 server_name      1xx.2xx.x.x;
 root             /var/www/html;

 location / {
   proxy_pass https://127.0.0.1:25566;
   proxy_set_header Host $http_host;
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header X-Forwarded-Proto $scheme;
 }

}

以上是該重定向的配置。

server {
   listen 80;
   return 301 https://$host$request_uri;
}

include /etc/nginx/websiterelated-include/upstreams;

server {
   listen 443;
   server_name subdomain.domain.com;

   ssl on;
   ssl_certificate /etc/ssl/certs/websiterelated.combined-chain.crt;
   ssl_certificate_key /etc/ssl/private/websiterelated.key;

   location /user_avatars {
       add_header X-Content-Type-Options nosniff;
       add_header Content-Security-Policy "default-src 'none' img-src 'self'";
       include /etc/nginx/websiterelated-include/uploads.types;
       alias /home/websiterelated/uploads/avatars;
   }

   location /local-static {
       alias /home/websiterelated/local-static;
   }

   include /etc/nginx/websiterelated-include/certbot;
   include /etc/nginx/websiterelated-include/app;
   include /etc/nginx/websiterelated-include/uploads.route;
}

以上是我使用的網站/服務的配置。

該網站執行正常,我可以在 subdomain.domain.com 下訪問它。使用 Java 應用程序時,我遇到了一些問題: 如果我嘗試與 Java 客戶端連接以

https://1xx.2xx.x.x:25005/

它沒有給我這個錯誤:

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
   at sun.security.ssl.InputRecord.handleUnknownRecord(InputRecord.java:710)
   at sun.security.ssl.InputRecord.read(InputRecord.java:527)
   at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
   at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
   at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
   at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
   at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
   at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
   at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1283)
   at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1258)
   at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
   at com.plugnbyte.httpclient.core.HttpClient.sendRequestSynchronous(HttpClient.kt:105)
   at com.plugnbyte.httpclient.core.HttpClient$sendRequest$requestThread$1.run(HttpClient.kt:53)
   at java.lang.Thread.run(Thread.java:745)

如果我嘗試連接https://1xx.2xx.x.x:25566/它會成功連接。

使用 Postman,如果我向它發送請求,https://1xx.2xx.x.x:25005/也無法得到回复。如果我將請求發送到https://1xx.2xx.x.x:25566/http://1xx.2xx.x.x:25005/然後我成功收到響應。

據我了解,重定向有效,但僅限於 http。是否可以將其更改為 https 但不添加其他證書?

我確實找到了一個臨時的解決方法;仍在尋找更好的解決方案。

可以按照以下命令將 JKS 文件轉換為 nginx 所需的文件

keytool -importkeystore -srckeystore {keystore.jks} -destkeystore {pkcs12.p12} -deststoretype PKCS12

openssl pkcs12 -nokeys -in {pkcs12.p12} -out {certificate-chain.pem}

openssl pkcs12 -nocerts -nodes -in {pkcs12.p12} -out {unencrypted-key.key}

之後,將 Java 應用程序的配置文件更改為以下內容:

server {

   ssl on;
   ssl_certificate /root/certs/certificate-chain.pem;
   ssl_certificate_key /root/certs/unecrypted-key.key;

 listen           127.0.0.1;
 #listen           25005;
 listen           443;
 server_name      1xx.2xx.x.x;
 root             /var/www/html;

 location / {
   proxy_pass https://127.0.0.1:25566;
   proxy_set_header Host $http_host;
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header X-Forwarded-Proto $scheme;
 }

}

重新載入設置,nginx -s reloadJava 應用程序能夠使用https://1xx.2xx.x.x:443/URL 成功連接。

這種方法的唯一缺點是您需要 JKS 文件的原始密碼,並且證書的私鑰在伺服器上保持未加密狀態。

引用自:https://serverfault.com/questions/947623