diff --git a/pom.xml b/pom.xml
index bf225d82f0..890ab23ee6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -581,6 +581,7 @@
spring-5-reactive-client
spring-5-reactive-oauth
spring-5-reactive-security
+ spring-5-reactive-netty
spring-5-security
spring-5-security-oauth
diff --git a/spring-5-reactive-netty/.gitignore b/spring-5-reactive-netty/.gitignore
new file mode 100644
index 0000000000..70ed41e73a
--- /dev/null
+++ b/spring-5-reactive-netty/.gitignore
@@ -0,0 +1,11 @@
+# Folders #
+**/.idea
+**/target
+
+# Files #
+*.log
+
+# Packaged files #
+*.jar
+*.war
+*.ear
\ No newline at end of file
diff --git a/spring-5-reactive-netty/README.md b/spring-5-reactive-netty/README.md
new file mode 100644
index 0000000000..09f7cc0e24
--- /dev/null
+++ b/spring-5-reactive-netty/README.md
@@ -0,0 +1,3 @@
+## Spring 5 Reactive Project With Netty Server
+
+Includes configuration options for Netty server.
diff --git a/spring-5-reactive-netty/pom.xml b/spring-5-reactive-netty/pom.xml
new file mode 100644
index 0000000000..48fc0b201f
--- /dev/null
+++ b/spring-5-reactive-netty/pom.xml
@@ -0,0 +1,51 @@
+
+
+ 4.0.0
+ com.baeldung
+ spring-5-reactive-netty
+ 0.0.1-SNAPSHOT
+ spring-5-reactive-netty
+ jar
+ Spring 5 sample project about reactive web with Netty server
+
+
+ com.baeldung
+ parent-boot-2
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/CustomNettyWebServerFactory.java b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/CustomNettyWebServerFactory.java
new file mode 100644
index 0000000000..8a1cdbba97
--- /dev/null
+++ b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/CustomNettyWebServerFactory.java
@@ -0,0 +1,36 @@
+package com.baeldung.serverconfig;
+
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
+import org.springframework.boot.web.embedded.netty.NettyServerCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import reactor.netty.http.server.HttpServer;
+
+@Configuration
+@Profile("skipAutoConfig")
+public class CustomNettyWebServerFactory {
+
+ @Bean
+ public NettyReactiveWebServerFactory nettyReactiveWebServerFactory() {
+ NettyReactiveWebServerFactory webServerFactory = new NettyReactiveWebServerFactory();
+ webServerFactory.addServerCustomizers(new EventLoopNettyCustomizer());
+ return webServerFactory;
+ }
+
+ private static class EventLoopNettyCustomizer implements NettyServerCustomizer {
+
+ @Override
+ public HttpServer apply(HttpServer httpServer) {
+ EventLoopGroup parentGroup = new NioEventLoopGroup();
+ EventLoopGroup childGroup = new NioEventLoopGroup();
+ return httpServer
+ .tcpConfiguration(tcpServer -> tcpServer.bootstrap(
+ serverBootstrap -> serverBootstrap.group(parentGroup, childGroup).channel(NioServerSocketChannel.class)
+ ));
+ }
+ }
+}
diff --git a/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/GreetingController.java b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/GreetingController.java
new file mode 100644
index 0000000000..9cb5b27ac5
--- /dev/null
+++ b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/GreetingController.java
@@ -0,0 +1,23 @@
+package com.baeldung.serverconfig;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Mono;
+
+@RestController
+@RequestMapping("/greet")
+public class GreetingController {
+
+ private final GreetingService greetingService;
+
+ public GreetingController(GreetingService greetingService) {
+ this.greetingService = greetingService;
+ }
+
+ @GetMapping("/{name}")
+ private Mono greet(@PathVariable String name) {
+ return greetingService.greet(name);
+ }
+}
diff --git a/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/GreetingService.java b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/GreetingService.java
new file mode 100644
index 0000000000..5440f526aa
--- /dev/null
+++ b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/GreetingService.java
@@ -0,0 +1,12 @@
+package com.baeldung.serverconfig;
+
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+@Service
+public class GreetingService {
+
+ public Mono greet(String name) {
+ return Mono.just("Greeting " + name);
+ }
+}
diff --git a/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/NettyWebServerFactoryPortCustomizer.java b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/NettyWebServerFactoryPortCustomizer.java
new file mode 100644
index 0000000000..152e1285aa
--- /dev/null
+++ b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/NettyWebServerFactoryPortCustomizer.java
@@ -0,0 +1,30 @@
+package com.baeldung.serverconfig;
+
+import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
+import org.springframework.boot.web.embedded.netty.NettyServerCustomizer;
+import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.stereotype.Component;
+import reactor.netty.http.server.HttpServer;
+
+@Component
+public class NettyWebServerFactoryPortCustomizer implements WebServerFactoryCustomizer {
+
+ @Override
+ public void customize(NettyReactiveWebServerFactory serverFactory) {
+ serverFactory.addServerCustomizers(new PortCustomizer(8443));
+ }
+
+ private static class PortCustomizer implements NettyServerCustomizer {
+
+ private final int port;
+
+ private PortCustomizer(int port) {
+ this.port = port;
+ }
+
+ @Override
+ public HttpServer apply(HttpServer httpServer) {
+ return httpServer.port(port);
+ }
+ }
+}
diff --git a/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/NettyWebServerFactorySslCustomizer.java b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/NettyWebServerFactorySslCustomizer.java
new file mode 100644
index 0000000000..d0ad0dcac5
--- /dev/null
+++ b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/NettyWebServerFactorySslCustomizer.java
@@ -0,0 +1,26 @@
+package com.baeldung.serverconfig;
+
+import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
+import org.springframework.boot.web.embedded.netty.SslServerCustomizer;
+import org.springframework.boot.web.server.Http2;
+import org.springframework.boot.web.server.Ssl;
+import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.stereotype.Component;
+
+@Component
+public class NettyWebServerFactorySslCustomizer implements WebServerFactoryCustomizer {
+
+ @Override
+ public void customize(NettyReactiveWebServerFactory serverFactory) {
+ Ssl ssl = new Ssl();
+ ssl.setEnabled(true);
+ ssl.setKeyStore("classpath:sample.jks");
+ ssl.setKeyAlias("alias");
+ ssl.setKeyPassword("password");
+ ssl.setKeyStorePassword("secret");
+ Http2 http2 = new Http2();
+ http2.setEnabled(false);
+ serverFactory.addServerCustomizers(new SslServerCustomizer(ssl, http2, null));
+ serverFactory.setPort(8443);
+ }
+}
diff --git a/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/ServerConfigApplication.java b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/ServerConfigApplication.java
new file mode 100644
index 0000000000..9d420cc7da
--- /dev/null
+++ b/spring-5-reactive-netty/src/main/java/com/baeldung/serverconfig/ServerConfigApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.serverconfig;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ServerConfigApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ServerConfigApplication.class, args);
+ }
+}
diff --git a/spring-5-reactive-netty/src/main/resources/logback.xml b/spring-5-reactive-netty/src/main/resources/logback.xml
new file mode 100644
index 0000000000..48b68c6bf1
--- /dev/null
+++ b/spring-5-reactive-netty/src/main/resources/logback.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+ %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
+
+
+
+
+
+ netty-access.log
+
+ %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-5-reactive-netty/src/main/resources/sample.jks b/spring-5-reactive-netty/src/main/resources/sample.jks
new file mode 100644
index 0000000000..6aa9a28053
Binary files /dev/null and b/spring-5-reactive-netty/src/main/resources/sample.jks differ
diff --git a/spring-5-reactive-netty/src/test/java/com/baeldung/serverconfig/GreetingControllerIntegrationTest.java b/spring-5-reactive-netty/src/test/java/com/baeldung/serverconfig/GreetingControllerIntegrationTest.java
new file mode 100644
index 0000000000..3c2c08321a
--- /dev/null
+++ b/spring-5-reactive-netty/src/test/java/com/baeldung/serverconfig/GreetingControllerIntegrationTest.java
@@ -0,0 +1,41 @@
+package com.baeldung.serverconfig;
+
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.reactive.server.WebTestClient;
+import reactor.core.publisher.Mono;
+
+@RunWith(SpringRunner.class)
+@WebFluxTest
+public class GreetingControllerIntegrationTest {
+
+ @Autowired
+ private WebTestClient webClient;
+
+ @MockBean
+ private GreetingService greetingService;
+
+ private final String name = "Baeldung";
+
+ @Before
+ public void setUp() {
+ when(greetingService.greet(name)).thenReturn(Mono.just("Greeting Baeldung"));
+ }
+
+ @Test
+ public void shouldGreet() {
+ webClient.get().uri("/greet/{name}", name)
+ .exchange()
+ .expectStatus()
+ .isOk()
+ .expectBody(String.class)
+ .isEqualTo("Greeting Baeldung");
+ }
+}
diff --git a/spring-5-reactive-netty/src/test/java/com/baeldung/serverconfig/GreetingLiveTest.java b/spring-5-reactive-netty/src/test/java/com/baeldung/serverconfig/GreetingLiveTest.java
new file mode 100644
index 0000000000..7c4a37c890
--- /dev/null
+++ b/spring-5-reactive-netty/src/test/java/com/baeldung/serverconfig/GreetingLiveTest.java
@@ -0,0 +1,56 @@
+package com.baeldung.serverconfig;
+
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+import javax.net.ssl.SSLException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.http.client.reactive.ReactorClientHttpConnector;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.reactive.server.WebTestClient;
+import org.springframework.test.web.reactive.server.WebTestClient.ResponseSpec;
+import reactor.netty.http.client.HttpClient;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
+public class GreetingLiveTest {
+
+ private static final String BASE_URL = "https://localhost:8443";
+
+ private WebTestClient webTestClient;
+
+ @Before
+ public void setup() throws SSLException {
+ webTestClient = WebTestClient.bindToServer(getConnector())
+ .baseUrl(BASE_URL)
+ .build();
+ }
+
+ @Test
+ public void shouldGreet() {
+ final String name = "Baeldung";
+
+ ResponseSpec response = webTestClient.get()
+ .uri("/greet/{name}", name)
+ .exchange();
+
+ response.expectStatus()
+ .isOk()
+ .expectBody(String.class)
+ .isEqualTo("Greeting Baeldung");
+ }
+
+ private ReactorClientHttpConnector getConnector() throws SSLException {
+ SslContext sslContext = SslContextBuilder
+ .forClient()
+ .trustManager(InsecureTrustManagerFactory.INSTANCE)
+ .build();
+ HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext));
+ return new ReactorClientHttpConnector(httpClient);
+ }
+}
diff --git a/spring-5-reactive-netty/src/test/java/com/baeldung/serverconfig/GreetingSkipAutoConfigLiveTest.java b/spring-5-reactive-netty/src/test/java/com/baeldung/serverconfig/GreetingSkipAutoConfigLiveTest.java
new file mode 100644
index 0000000000..646742b3d7
--- /dev/null
+++ b/spring-5-reactive-netty/src/test/java/com/baeldung/serverconfig/GreetingSkipAutoConfigLiveTest.java
@@ -0,0 +1,8 @@
+package com.baeldung.serverconfig;
+
+import org.springframework.test.context.ActiveProfiles;
+
+@ActiveProfiles("skipAutoConfig")
+public class GreetingSkipAutoConfigLiveTest extends GreetingLiveTest {
+
+}
diff --git a/spring-5-reactive-netty/src/test/resources/logback-test.xml b/spring-5-reactive-netty/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..12cedf5952
--- /dev/null
+++ b/spring-5-reactive-netty/src/test/resources/logback-test.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+ %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
+
+
+
+
+
+
+