ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스프링 부트 6일차 - 스프링 부트 내장 웹 서버, SSL/HTTP2 적용
    Portfolio/Spring Boot 2019. 4. 6. 00:56
    728x90

    1. 스프링 부트는 내장 톰캣을 포함하고 있음.

      * 스프링 부트는 서버가 아님


    2. ServletWebServerFactoryAutoConfiguration은 서블릿 웹 서버를 위한 내장 설정 파일


    3. TomcatServletWebserverFactoryCustomizer은 톰캣 서버 커스터마이징


    4. spring-boot-starter-web은 기본적으로 톰캣을 서블릿 컨테이너로 사용함.

       만약 톰캣 말고 다른 서블릿 컨테이너를 사용하고 싶다면 pom.xml을 다음과 같이 작성하면됨.

    <properties>
    	<servlet-api.version>3.1.0</servlet-api.version>
    </properties>
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-web</artifactId>
    	<exclusions>
    		<!-- Exclude the Tomcat dependency -->
    		<exclusion>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-tomcat</artifactId>
    		</exclusion>
    	</exclusions>
    </dependency>
    <!-- Use Jetty instead -->
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-jetty</artifactId>
    </dependency>


    이렇게하면 톰캣인 exclusion되고, jetty가 서블릿 컨테이너로 사용됨.

    참고 : https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-web-servers.html


    5. spring.main.web-application-type=none 로 application.properties을 주면 웹 서버를 띄우지 않음.

       server.port=xxxx 를 주면 port 번호를 주면 해당 포트를 웹 서버 포트로 사용.

       server.port=0을 하면 사용중이지 않은 포트를 골라서 포트로 지정( 아마 49152 ~ 65535까지의 동적 포트 중에 할당해주는 것 같음.)


    6. 5에서 같이 랜덤하게 포트를 지정했을 때 그 포트를 해당 애플리케이션에서 가져오기 위해선 다음과 같은 방법을 사용하면 됨.

       ApplicationListener<ServletWebServerInitializedEvent> 를 구현해주는 클래스를 만들고 필요한 메소드 구현

    package me.whiteship;

    import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
    import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.stereotype.Component;

    @Component
    public class PortListener implements ApplicationListener<ServletWebServerInitializedEvent> {
    @Override
    public void onApplicationEvent(ServletWebServerInitializedEvent servletWebServerInitializedEvent) {
    ServletWebServerApplicationContext applicationContext = servletWebServerInitializedEvent.getApplicationContext();
    System.out.println(applicationContext.getWebServer().getPort());
    }
    }


    참고 : https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-web-servers.html#howto-discover-the-http-port-at-runtime


    7. HTTPS를 적용하기 위해서는 https://gist.github.com/keesun/f93f0b83d7232137283450e08a53c4fd 를 참고하여

      먼저 keytool을 이용하여 key pair를 만들어준다.


    keytool -genkey
    -alias tomcat
    -storetype PKCS12
    -keyalg RSA
    -keysize 2048
    -keystore keystore.p12
    -validity 4000

     * keytool은 JDK 설치 경로의 bin 폴더에 있음. Windows에서 내가 들어간 경로는 C:\Program Files\Java\jdk1.8.0_201\bin임. 경로는 당연히 버전마다도 다르니까 잘 찾아가시기 바랍니다. 특히 여기서 keytool로 만들려고 할 때 권한 문제로 keystore 안생기니까 콘솔을 관리자 권한으로 실행시켜줘야함. 다음과 같이 에러가 뜨면서 안될 것임.

     keytool 오류: java.io.FileNotFoundException: keystore.p12 (액세스가 거부되었습니다)

      원인 : 해당 경로는 관리자 권한이 있어야 파일 수정 가능

      해결 : 관리자 권한으로 콘솔 실행


    생성된 keystore은 프로젝트의 root 경로에 두면 됨.


      비밀번호를 설정하는 등 입력을 해주고 나서

      application.properties에 다음과 같이 설정을 추가

    server.ssl.key-store=keystore.p12
    server.ssl.key-store-password=123456
    server.ssl.keyStoreType=PKCS12
    server.ssl.keyAlias=tomcat


    실행하면 https로 접속 가능


    8. 7을 진행하면 https는 접속가능하지만 http로 접속이 안된다. http로 접속할 경우 다음과 같이 Bad Request라고 나옴

    Bad Request
    This combination of host and port requires TLS.
    


    이유는 HTTP 커넥터가 하나뿐임. 근데 이걸 HTTPS를 위해 사용하니까 HTTP가 사용할 커넥터가 없는 것.

    해결 방법은 HTTP를 위한 커넥터를 하나 추가해주면 된다.

    다음과 같이 코드가 구성


    Application.java

    package me.junhyung.webservershowcase;

    import org.apache.catalina.connector.Connector;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
    import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.bind.annotation.RestController;

    @SpringBootApplication
    @RestController
    public class Application {
    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }

    @Bean
    public ServletWebServerFactory serverFactory() {
    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
    tomcat.addAdditionalTomcatConnectors(createStandardConnector());
    return tomcat;
    }

    private Connector createStandardConnector() {
    Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
    connector.setPort(80);
    return connector;
    }
    }


    application.properties

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


    9. HTTP2 적용하기

      톰캣으로 사용하려면 좀 복합함. libtcnative 라이브러리를 설치해줘야하는데, 이렇게 안하고 싶다면 톰캣 버전을 9, JDK 버전도 9버전 이상을 사용하면 단순히 application.properties에 다음과 같은 옵션을 주는 것만으로 가능

    server.http2.enabled=true


    근데 undertow를 사용하면 추가적인 라이브러리 상관없이 사용가능


    잘 적용되었는지 확인하려면 curl을 사용해야되는데, (혹은 http2 요청을 날려주는 브라우저)

    리눅스는 기본적으로 깔려있고 윈도우에서는 사용하기 제일 쉬운 방법이 git을 설치하면 같이 딸려있는 git bash를 이용하는 것이다.

    git bash를 실행시키고 다음과 같이 명령어를 보내보면 된다.

    curl -I -k https://localhost/hello

     * 테스트해볼 hello 경로에 다음과 같이 경로 매핑을 해줘야함.

    @SpringBootApplication
    @RestController
    public class Application {
    @GetMapping
    public String hello() {
    return "Hello Spring";
    }

    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }




Designed by Tistory.