์ธํ…”๋ฆฌ์ œ์ด ๋˜๋Š” ์Šคํ”„๋ง ์ด๋‹ˆ์…œ๋ผ์ด์ €๋ฅผ ํ†ตํ•ด ์Šคํ”„๋ง ๋ถ€ํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์Šคํ”„๋ง ์ด๋‹ˆ์…œ๋ผ์ด์ €๋ฅผ ํ†ตํ•ด ๋งŒ๋“ค๊ณ ์ž ํ•˜๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ํ•„์š”ํ•œ ๋ชจ๋“ˆ์„ ์‰ฝ๊ฒŒ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ง€์›ํ•˜์ง€๋งŒ ์„ธ๋ถ€์ ์ธ ๋ชจ๋“ˆ์˜ ์„ ํƒ์€ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋งŒ๋“ค์–ด์ง„ ํ”„๋กœ์ ํŠธ๋ฅผ ์ˆ˜์ •ํ•ด์•ผํ•  ํ•„์š”์„ฑ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค. ์•„ํŒŒ์น˜ ํ†ฐ์บฃ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›ํ•˜๋Š” ๊ธฐ๋ณธ ์ปจํ…Œ์ด๋„ˆ๋กœ์จ ์ถฉ๋ถ„ํžˆ ์ž…์ฆ๋œ ๊ธฐ์ˆ ์ด์ง€๋งŒ ํ˜„์žฌ ์กฐ์ง๊ณผ ๊ฐ™์ด ์ผ๋ถ€ ์‹ค๋ฌด ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์–ธ๋”ํ† ์šฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํŽธ์ด๋‹ค.

build.gradle
configurations.configureEach { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-websocket' implementation 'org.springframework.boot:spring-boot-starter-undertow' }

์œ„ ์˜ˆ์‹œ์—์„œ spring-boot-starter-websocket ๋ชจ๋“ˆ์— ์˜ํ•ด spring-boot-starter-web์€ ๋ช…์‹œํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

WebSocketDeploymentInfo ๊ฒฝ๊ณ  ๋กœ๊ทธ ์—†์• ๊ธฐ

spring-boot-starter-websocket ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ WebSocketDeploymentInfo๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•„ ๊ธฐ๋ณธ ๋ฒ„ํผ ํ’€์ด ์‚ฌ์šฉ๋œ๋‹ค๋Š” ๊ฒฝ๊ณ  ๋กœ๊ทธ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค. ๋กœ๊ทธ ๋ ˆ๋ฒจ ์กฐ์ •์„ ํ†ตํ•ด ๋ฌด์‹œํ•ด๋„ ๋˜์ง€๋งŒ WebServerFactoryCustomizer๋ฅผ ํ†ตํ•ด์„œ WebSocketDeploymentInfo๊ฐ€ ๋“ฑ๋ก๋˜๋„๋ก ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

2023-03-16T21:49:43.249+09:00  WARN 35488 --- [main] io.undertow.websockets.jsr : UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
UndertowWebsocketCustomizer
@Component public class UndertowWebsocketCustomizer implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> { private final ServerProperties.Undertow undertow; public UndertowWebsocketCustomizer(final ServerProperties serverProperties) { this.undertow = serverProperties.getUndertow(); } @Override public void customize(UndertowServletWebServerFactory factory) { factory.addDeploymentInfoCustomizers(deploymentInfo -> { boolean direct = this.undertow.getDirectBuffers() != null && this.undertow.getDirectBuffers(); int bufferSize = this.undertow.getBufferSize() != null ? (int) this.undertow.getBufferSize().toBytes() : 1024; WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo(); webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(direct, bufferSize)); deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo); }); } }

HTTPS ํฌํŠธ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ

์ด์ œ๋Š” AWS ELB์™€ ๊ฐ™์€ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ ๋˜๋Š” ์—”์ง„์—‘์Šค์™€ ๊ฐ™์€ ์›น ์„œ๋ฒ„๋“ค์„ ํ†ตํ•ด์„œ ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹œ๋ฅผ ๊ตฌ์„ฑํ•˜๋ฏ€๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด HTTP/2๋ฅผ ์ง€์›ํ•˜๋„๋ก ๊ตฌ๋™ํ•˜์ง€ ์•Š๋Š” ํŽธ์ด์ง€๋งŒ TLS ์˜คํ”„๋กœ๋“œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด HTTP๋กœ ์—ฐ๊ฒฐ๋˜์—ˆ์„๋•Œ HTTPS๋กœ ์—ฐ๊ฒฐ๋˜๋„๋ก ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

UndertowHttp2Customizer
@Component public class UndertowHttp2Customizer implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> { private final ServerProperties serverProperties; private final int httpPort; public UndertowHttp2Customizer(final ServerProperties serverProperties, final Environment environment) { this.serverProperties = serverProperties; this.httpPort = environment.getProperty("server.http-port", Integer.class, 8080); } @Override public void customize(UndertowServletWebServerFactory factory) { factory.addBuilderCustomizers(builder -> builder.addHttpListener(this.httpPort, "0.0.0.0")); factory.addDeploymentInfoCustomizers(deploymentInfo -> deploymentInfo.addSecurityConstraint( new SecurityConstraint() .addWebResourceCollection(new WebResourceCollection().addUrlPattern("/*")) .setTransportGuaranteeType(TransportGuaranteeType.CONFIDENTIAL) .setEmptyRoleSemantic(SecurityInfo.EmptyRoleSemantic.PERMIT)) .setConfidentialPortManager(exchange -> serverProperties.getPort())); } }