Cómo configurar Spring Boot para ejecutar puertos HTTPS / HTTP

8 minutos de lectura

Avatar de usuario de Carlos Alberto
carlosalberto

Spring Boot tiene algunas propiedades para configurar el puerto web y la configuración de SSL, pero una vez que se establece un certificado SSL, el puerto http se convierte en un puerto https.

Entonces, ¿cómo puedo mantener ambos puertos funcionando, por ejemplo: 80 y 443 al mismo tiempo?

Como puede ver, solo hay propiedades para un puerto, en este caso “server.ssl” está habilitado, lo que hace que el puerto http se deshabilite automáticamente.

##############
### 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

Estoy tratando de usar incluso Tomcat o Undertow. ¡Agradecería cualquier ayuda!

  • ¿Por qué quieres que ambos funcionen al mismo tiempo? O la línea es segura o insegura, pero no debería ser ambas cosas.

    – Makoto

    17 de junio de 2015 a las 15:42

  • Algunas partes de mi proyecto necesitan ser aseguradas y otras no. Como saben, el tráfico Https es más lento que Http, por lo que me gustaría intercambiar ambos protocolos al mismo tiempo que lo hacemos en cualquier servidor de aplicaciones.

    – Carlos Alberto

    17 de junio de 2015 a las 15:44


  • @Makoto – no necesariamente. un puerto puede admitir tanto HTTP como HTTPS. por ejemplo – bayou.io/release/0.9/docs/http/Server_SSL_Configuration.html

    – Zhong Yu

    17 de junio de 2015 a las 15:48

  • @ElLordCode: no estoy familiarizado con Boot; Entonces, ¿está diciendo que solo puede tener un puerto?

    – Zhong Yu

    17/06/2015 a las 15:50

  • posible duplicado de la ejecución de una aplicación Spring Boot (Tomcat integrado) con SSL y sin cifrar simultáneamente

    –Andy Wilkinson

    17 de junio de 2015 a las 20:14

Avatar de usuario de Harish Gokavarapu
Harish Gokavarapu

La configuración de Spring Boot usando propiedades, permite configurar solo un conector. Lo que necesita son múltiples conectores y para esto, debe escribir una clase de Configuración. Siga las instrucciones en

https://docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/html/howto-embedded-servlet-containers.html

Puede encontrar un ejemplo práctico de configuración de HTTPS a través de propiedades y luego HTTP a través de EmbeddedServletContainerCustomizer a continuación

http://izeye.blogspot.com/2015/01/configure-http-and-https-in-spring-boot.html?showComment=1461632100718#c4988529876932015554

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);
            }
        }
    };
}
}

  • y server.http.port ya no parece existir.

    – Stefan Falk

    28 de diciembre de 2018 a las 23:57

  • El puerto http del servidor @displayname es una configuración personalizada definida por el programador y no predefinida en Spring, en el código se puede ver: @Value(“${server.http.port}”) private int httpPort;

    – usuario666

    18 de enero de 2019 a las 12:40

  • @ user666 Solía ​​​​existir afaik.

    – Stefan Falk

    18 de enero de 2019 a las 12:41

  • @Harish Gokavarapu y Adam Millerchip, ¿cómo hacen esto en la línea de comando? Con una configuración de springboot https, probé esta: -Dserver.port=6010 -Dserver.http.port=6011, pero solo se cambió el puerto https, no el puerto http.

    – Artanis Zeratul

    16 de agosto de 2019 a las 1:59


  • Esto funcionó para mí, excepto que tuve que cambiar los valores del puerto. http.port debe ser su 8080 básico y server.port debe ser su puerto https deseado, como 8443

    – A Forsberg

    3 de enero de 2020 a las 15:15

Avatar de usuario de NickDK
NickDK

La respuesta aceptada actualmente funciona perfectamente, pero necesita alguna adaptación si desea que funcione con Spring Boot 2.0.0 y en adelante:

@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;
  }
}

o el versión 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
  }
}

  • Funcionó perfectamente en la versión más nueva de Spring Boot.

    – usuario666

    18 de enero de 2019 a las 13:28

  • Esto funcionó para mí también. Solo quería aclarar que esta clase REEMPLAZA la clase TomcatConfig en la respuesta aceptada. También se aplica mi comentario sobre la respuesta aceptada sobre ajustar las propiedades de yaml.

    – A Forsberg

    7 febrero 2020 a las 17:41

  • Funciona bien para soporte HTTP/HTTPS probado con Spring Boot 2.4.3 versión.

    – catch23

    20 de marzo de 2021 a las 19:23

  • ¿Cuál es la importación para la clase Connector?

    – Anurag Bhalekar

    11 oct 2021 a las 14:51

Avatar de usuario de Stan Sokolov
Stan Sokolov

A continuación se muestra un ejemplo simple de cómo habilitar ambos puertos HTTP/HTTPS para resaca.

Spring Boot solo permite abrir un puerto por configuración. El segundo puerto debe abrirse mediante programación.

Abra el puerto HTTP primero mediante programación.

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);
        });
    };
}

}

HTTPS por configuración

Spring puede abrir una propiedad de lectura de puerto HTTP o HTTPS desde una fuente de propiedad disponible. Si agrega la configuración adecuada como se muestra a continuación, sería lo suficientemente bueno para tener abierto el puerto HTTP.

#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

HTTPS por configuración manual

Puede abrir otro puerto SSL de la misma manera que abrió el puerto HTTP si lo desea haciendo esto

 .addHttpsListener(ssl_port, httpInterface, getSSLContext());

Así es como puedes crear un contexto 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;
    }
}

  • Esta solución funciona perfectamente con resaca, gracias.

    – norbertas.gaulia

    20 de enero de 2019 a las 20:49

  • ¿Puede agregar algunos códigos en la implementación anterior para HTTP 2.0?

    – Sam

    13 de febrero de 2019 a las 15:27

  • en mi caso el @Value la inyección no funcionó tan fácilmente porque mi configuración era más compleja. Le expliqué mi situación y lo que terminó funcionando para mí en este comentario de problema de GitHub.

    – Alejandro González

    15 de diciembre de 2021 a las 10:02


Otra solución 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;
}

Y establecer en sus propiedades servidor.puerto=443

Echa un vistazo a: https://github.com/creactiviti/spring-boot-starter-acme. Hace que sea muy fácil generar automáticamente un certificado SSL basado en LetsEncrypt.

Del LÉAME:

  1. Agregue el módulo a su archivo pom.xml como una dependencia.

  2. Construye tu proyecto.

  3. Despliéguelo en una máquina de destino y apunte su nombre de dominio a la dirección IP de esa máquina. LetsEncrypt valida su propiedad del dominio haciendo una devolución de llamada al http://tu-dominio/.bien-conocido/acme-challenge/Punto final {token} expuesto por este módulo.

  4. Asegúrese de que su servidor tenga Openssl disponible en su $PATH.

  5. Para activar spring-boot-starter-acme y generar un certificado ejecute:

    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

  6. Verifique su consola para obtener una confirmación de que el certificado se generó con éxito.

  7. Detenga su aplicación y configúrela para hacer uso del certificado generado:

    server.port=443
    server.ssl.key-store=keystore.p12
    server.ssl.key-store-password=password
    server.ssl.keyStoreType=PKCS12

Avatar de usuario de Shai Almog
Shai Almog

Las respuestas principales son excelentes y probablemente funcionen, pero he estado usando Undertow con JHipster, por lo que no me funcionaron (y esta fue la principal búsqueda resultado). El código correcto para Undertow se menciona en este problema específicamente:

@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;
}

¿Ha sido útil esta solución?