Spring boot具有一些配置Web端口和SSL设置的属性,但是一旦设置了SSL证书,http端口就变成了https端口。
那么,如何在其上运行两个端口,例如:80和443同时运行?
如您所见,只有一个端口的属性,在这种情况下启用了“server.ssl”,这使得http端口自动被禁用。
##############
### Server ###
##############
server.port=9043
server.session-timeout=1800
server.ssl.key-store=file:///C:/Temp/config/localhost.jks
server.ssl.key-store-password=localhost
server.ssl.key-password=localhost
server.ssl.trust-store=file:///C:/Temp/config/localhost.jks
server.ssl.trust-store-password=localhost
我正在尝试使用Tomcat或Undertow。我很感激任何帮助!
答案 0 :(得分:37)
使用属性的Spring Boot配置,只允许配置一个连接器。你需要的是多个连接器,为此你必须编写一个Configuration类。按照
中的说明操作您可以找到一个通过属性配置https的工作示例,然后通过下面的http://wwwServletContainerCustomizer来查找http
server:
port:
8080
ssl:
enabled:
true
keyStoreType:
PKCS12
key-store:
/path/to/keystore.p12
key-store-password:
password
http:
port:
8079
@Configuration
public class TomcatConfig {
@Value("${server.http.port}")
private int httpPort;
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
TomcatEmbeddedServletContainerFactory containerFactory =
(TomcatEmbeddedServletContainerFactory) container;
Connector connector = new Connector(TomcatEmbeddedServletContainerFactory.DEFAULT_PROTOCOL);
connector.setPort(httpPort);
containerFactory.addAdditionalTomcatConnectors(connector);
}
}
};
}
}
答案 1 :(得分:17)
当前接受的答案可以很好地工作,但是如果您希望它与Spring Boot 2.0.0及更高版本一起使用,则需要进行一些调整:
@Component
public class HttpServer {
@Bean
public ServletWebServerFactory servletContainer(@Value("${server.http.port}") int httpPort) {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setPort(httpPort);
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addAdditionalTomcatConnectors(connector);
return tomcat;
}
}
或kotlin版本:
@Component
class HttpServer {
@Bean
fun servletContainer(@Value("\${server.http.port}") httpPort: Int): ServletWebServerFactory {
val connector = Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL)
connector.setPort(httpPort)
val tomcat = TomcatServletWebServerFactory()
tomcat.addAdditionalTomcatConnectors(connector)
return tomcat
}
}
答案 2 :(得分:4)
Spring Boot只允许按配置打开一个端口。必须以编程方式打开第二个端口。
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
@Configuration
public class UndertowConfig {
@Value("${server.http.port}")
private int httpPort;
@Value("${server.http.interface}")
private String httpInterface;
@Bean
public WebServerFactoryCustomizer<UndertowServletWebServerFactory> containerCustomizer() {
return (WebServerFactoryCustomizer) factory -> {
UndertowServletWebServerFactory undertowFactory = (UndertowServletWebServerFactory) factory;
undertowFactory.getBuilderCustomizers().add(builder -> {
builder.addHttpListener(httpPort, httpInterface);
});
};
}
}
Spring可以从可用属性源打开HTTP或HTTPS端口读取属性。如果您添加适当的配置,如下所示,将HTTPs端口打开就足够了。
#default secured port (Spring will open it automatically)
server.port=8443
#additional HTTP port (will open it in UndertowConfig)
server.http.port=8080
#Open to the world
server.http.interface=0.0.0.0
#These settings tell Spring to open SSL port
server.ssl.keystore=file:${APP_BASE}/conf/server/ssl_selfsigned/server.keystore
server.ssl.key-store-password=xyz
server.ssl.key-password=xyz
通过手动设置如果您愿意,可以像打开HTTP端口一样打开另一个SSL端口
.addHttpsListener(ssl_port, httpInterface, getSSLContext());
这是您创建SSL上下文的方法
import javax.net.ssl.*;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyStore;
public SSLContext getSSLContext() throws Exception
{
return createSSLContext(loadKeyStore(serverKeystore,keyStorePassword),
loadKeyStore(serverTruststore,trustStorePassword));
}
private SSLContext createSSLContext(final KeyStore keyStore,
final KeyStore trustStore) throws Exception {
KeyManager[] keyManagers;
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
keyManagers = keyManagerFactory.getKeyManagers();
TrustManager[] trustManagers;
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext;
sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
return sslContext;
}
private static KeyStore loadKeyStore(final String storeLoc, final String storePw) throws Exception {
InputStream stream = Files.newInputStream(Paths.get(storeLoc));
if(stream == null) {
throw new IllegalArgumentException("Could not load keystore");
}
try(InputStream is = stream) {
KeyStore loadedKeystore = KeyStore.getInstance("JKS");
loadedKeystore.load(is, storePw.toCharArray());
return loadedKeystore;
}
}
答案 3 :(得分:2)
另一个Spring boot 2.x解决方案:
private static final int HTTP_PORT = 80;
private static final int HTTPS_PORT = 443;
private static final String HTTP = "http";
private static final String USER_CONSTRAINT = "CONFIDENTIAL";
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint(USER_CONSTRAINT);
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(redirectConnector());
return tomcat;
}
private Connector redirectConnector() {
Connector connector = new Connector(
TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setScheme(HTTP);
connector.setPort(HTTP_PORT);
connector.setSecure(false);
connector.setRedirectPort(HTTPS_PORT);
return connector;
}
并在您的属性中设置 server.port = 443
答案 4 :(得分:1)
看看:https://github.com/creactiviti/spring-boot-starter-acme。它使得自动生成基于LetsEncrypt的SSL证书非常容易。
来自自述文件:
将模块作为依赖项添加到pom.xml文件中。
构建您的项目。
将其部署到目标计算机并将您的域名指向该计算机的IP地址。 LetsEncrypt通过回调此模块公开的http://your-domain/.well-known/acme-challenge/ {token}端点来验证您对域的所有权。
确保您的服务器的$ PATH上有openssl。
要激活spring-boot-starter-acme并生成证书执行:
sudo java -Dserver.port=80 -Dacme.enabled=true -Dacme.domain-name=<YOUR_DOMAIN_NAME> -Dacme.accept-terms-of-service=true -jar mysecureapp-0.0.1-SNAPSHOT.jar
检查控制台是否已成功生成证书。
停止您的应用程序并将其配置为使用生成的证书:
server.port=443
server.ssl.key-store=keystore.p12
server.ssl.key-store-password=password
server.ssl.keyStoreType=PKCS12
答案 5 :(得分:0)
最重要的答案都是很好的,而且可能有用,但是我一直在将Undertow与JHipster结合使用,因此它们对我不起作用(这是主要的search结果)。 this issue中具体提到了Undertow的正确代码:
@Bean
public UndertowServletWebServerFactory embeddedServletContainerFactory() {
UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
@Override
public void customize(Undertow.Builder builder) {
builder.addHttpListener(8080, "0.0.0.0");
}
});
return factory;
}