我有一个服务器和一个客户端应用程序,它们使用 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 但不添加其他证书?
答案1
我确实找到了一个临时的解决方法;仍在寻找更好的解决方案。
按照以下步骤将 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 reload
,Java 应用程序就能使用https://1xx.2xx.x.x:443/
URL 成功连接。
这种方法的唯一缺点是您需要 JKS 文件的原始密码,并且证书的私钥在服务器上保持未加密状态。