76. Embedded Web Servers (2024)

76.Embedded Web Servers

Each Spring Boot web application includes an embedded web server. This feature leads to anumber of how-to questions, including how to change the embedded server and how toconfigure the embedded server. This section answers those questions.

76.1Use Another Web Server

Many Spring Boot starters include default embedded containers.

  • For servlet stack applications, the spring-boot-starter-web includes Tomcat by includingspring-boot-starter-tomcat, but you can use spring-boot-starter-jetty orspring-boot-starter-undertow instead.
  • For reactive stack applications, the spring-boot-starter-webflux includes Reactor Nettyby including spring-boot-starter-reactor-netty, but you can use spring-boot-starter-tomcat,spring-boot-starter-jetty, or spring-boot-starter-undertow instead.

When switching to a different HTTP server, you need to exclude the default dependenciesin addition to including the one you need. Spring Boot provides separate starters forHTTP servers to help make this process as easy as possible.

The following Maven example shows how to exclude Tomcat and include Jetty for Spring MVC:

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

The following Gradle example shows how to exclude Netty and include Undertow for SpringWebFlux:

configurations {// exclude Reactor Nettycompile.exclude module: 'spring-boot-starter-reactor-netty'}dependencies {compile 'org.springframework.boot:spring-boot-starter-webflux'// Use Undertow insteadcompile 'org.springframework.boot:spring-boot-starter-undertow'// ...}
76.Embedded Web Servers (1)Note

spring-boot-starter-reactor-netty is required to use the WebClient class, soyou may need to keep a dependency on Netty even when you need to include a different HTTPserver.

76.2Disabling the Web Server

If your classpath contains the necessary bits to start a web server, Spring Boot willautomatically start it. To disable this behaviour configure the WebApplicationType inyour application.properties, as shown in the following example:

spring.main.web-application-type=none

76.3Change the HTTP Port

In a standalone application, the main HTTP port defaults to 8080 but can be set withserver.port (for example, in application.properties or as a System property). Thanksto relaxed binding of Environment values, you can also use SERVER_PORT (for example,as an OS environment variable).

To switch off the HTTP endpoints completely but still create a WebApplicationContext,use server.port=-1. (Doing so is sometimes useful for testing.)

For more details, see“Section28.4.4, “Customizing Embedded Servlet Containers””in the ‘Spring Boot features’ section, or theServerProperties sourcecode.

76.4Use a Random Unassigned HTTP Port

To scan for a free port (using OS natives to prevent clashes) use server.port=0.

76.5Discover the HTTP Port at Runtime

You can access the port the server is running on from log output or from theServletWebServerApplicationContext through its WebServer. The best way to get that andbe sure that it has been initialized is to add a @Bean of typeApplicationListener<ServletWebServerInitializedEvent> and pull the containerout of the event when it is published.

Tests that use @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) canalso inject the actual port into a field by using the @LocalServerPort annotation, asshown in the following example:

@RunWith(SpringJUnit4ClassRunner.class)@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)public class MyWebIntegrationTests {@AutowiredServletWebServerApplicationContext server;@LocalServerPortint port;// ...}
76.Embedded Web Servers (2)Note

@LocalServerPort is a meta-annotation for @Value("${local.server.port}"). Do not tryto inject the port in a regular application. As we just saw, the value is set only afterthe container has been initialized. Contrary to a test, application code callbacks areprocessed early (before the value is actually available).

HTTP response compression is supported by Jetty, Tomcat, and Undertow. It can be enabledin application.properties, as follows:

server.compression.enabled=true

By default, responses must be at least 2048 bytes in length for compression to beperformed. You can configure this behavior by setting theserver.compression.min-response-size property.

By default, responses are compressed only if their content type is one of thefollowing:

  • text/html
  • text/xml
  • text/plain
  • text/css
  • text/javascript
  • application/javascript
  • application/json
  • application/xml

You can configure this behavior by setting the server.compression.mime-types property.

76.7Configure SSL

SSL can be configured declaratively by setting the various server.ssl.* properties,typically in application.properties or application.yml. The following example showssetting SSL properties in application.properties:

server.port=8443server.ssl.key-store=classpath:keystore.jksserver.ssl.key-store-password=secretserver.ssl.key-password=another-secret

See Ssl for details of all of thesupported properties.

Using configuration such as the preceding example means the application no longer supportsa plain HTTP connector at port 8080. Spring Boot does not support the configuration ofboth an HTTP connector and an HTTPS connector through application.properties. If youwant to have both, you need to configure one of them programmatically. We recommend usingapplication.properties to configure HTTPS, as the HTTP connector is the easier of thetwo to configure programmatically. See thespring-boot-sample-tomcat-multi-connectorssample project for an example.

76.8Configure HTTP/2

You can enable HTTP/2 support in your Spring Boot application with theserver.http2.enabled configuration property. This support depends on the chosen webserver and the application environment, since that protocol is not supportedout-of-the-box by JDK8.

76.Embedded Web Servers (3)Note

Spring Boot does not support h2c, the cleartext version of the HTTP/2 protocol. So youmust configure SSL first.

76.8.1HTTP/2 with Undertow

As of Undertow 1.4.0+, HTTP/2 is supported without any additional requirement on JDK8.

76.8.2HTTP/2 with Jetty

As of Jetty 9.4.8, HTTP/2 is also supported with theConscrypt library.To enable that support, your application needs to have two additional dependencies:org.eclipse.jetty:jetty-alpn-conscrypt-server and org.eclipse.jetty.http2:http2-server.

76.8.3HTTP/2 with Tomcat

Spring Boot ships by default with Tomcat 8.5.x. With that version, HTTP/2 is onlysupported if the libtcnative library and its dependencies are installed on the hostoperating system.

The library folder must be made available, if not already, to the JVM library path. Youcan do so with a JVM argument such as-Djava.library.path=/usr/local/opt/tomcat-native/lib. More on this in theofficial Tomcat documentation.

Starting Tomcat 8.5.x without that native support logs the following error:

ERROR 8787 --- [ main] o.a.coyote.http11.Http11NioProtocol : The upgrade handler [org.apache.coyote.http2.Http2Protocol] for [h2] only supports upgrade via ALPN but has been configured for the ["https-jsse-nio-8443"] connector that does not support ALPN.

This error is not fatal, and the application still starts with HTTP/1.1 SSL support.

Running your application with Tomcat 9.0.x and JDK9 does not require any native library tobe installed. To use Tomcat 9, you can override the tomcat.version build property withthe version of your choice.

Generally, you should first consider using one of the many available configuration keysand customize your web server by adding new entries in your application.properties (orapplication.yml, or environment, etc. see“Section75.8, “Discover Built-in Options for External Properties””). The server.*namespace is quite useful here, and it includes namespaces like server.tomcat.*,server.jetty.* and others, for server-specific features.See the list of AppendixA, Common application properties.

The previous sections covered already many common use cases, such as compression, SSLor HTTP/2. However, if a configuration key doesn’t exist for your use case, you shouldthen look atWebServerFactoryCustomizer.You can declare such a component and get access to the server factory relevant to yourchoice: you should select the variant for the chosen Server (Tomcat, Jetty, Reactor Netty,Undertow) and the chosen web stack (Servlet or Reactive).

The example below is for Tomcat with the spring-boot-starter-web (Servlet stack):

@Componentpublic class MyTomcatWebServerCustomizerimplements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {@Overridepublic void customize(TomcatServletWebServerFactory factory) {// customize the factory here}}

In addition Spring Boot provides:

ServerServlet stackReactive stack

Tomcat

TomcatServletWebServerFactory

TomcatReactiveWebServerFactory

Jetty

JettyServletWebServerFactory

JettyReactiveWebServerFactory

Undertow

UndertowServletWebServerFactory

UndertowReactiveWebServerFactory

Reactor

N/A

NettyReactiveWebServerFactory

Once you’ve got access to a WebServerFactory, you can often add customizers to it toconfigure specific parts, like connectors, server resources, or the server itself - allusing server-specific APIs.

As a last resort, you can also declare your own WebServerFactory component, which willoverride the one provided by Spring Boot. In this case, you can’t rely on configurationproperties in the server namespace anymore.

76.10Add a Servlet, Filter, or Listener to an Application

In a servlet stack application, i.e. with the spring-boot-starter-web, there are twoways to add Servlet, Filter, ServletContextListener, and the other listenerssupported by the Servlet API to your application:

  • Section76.10.1, “Add a Servlet, Filter, or Listener by Using a Spring Bean”
  • Section76.10.2, “Add Servlets, Filters, and Listeners by Using Classpath Scanning”

76.10.1Add a Servlet, Filter, or Listener by Using a Spring Bean

To add a Servlet, Filter, or Servlet *Listener by using a Spring bean, you mustprovide a @Bean definition for it. Doing so can be very useful when you want to injectconfiguration or dependencies. However, you must be very careful that they do not causeeager initialization of too many other beans, because they have to be installed in thecontainer very early in the application lifecycle. (For example, it is not a good idea tohave them depend on your DataSource or JPA configuration.) You can work around suchrestrictions by initializing the beans lazily when first used instead of oninitialization.

In the case of Filters and Servlets, you can also add mappings and init parameters byadding a FilterRegistrationBean or a ServletRegistrationBean instead of or inaddition to the underlying component.

76.Embedded Web Servers (4)Note

If no dispatcherType is specified on a filter registration, REQUEST is used. Thisaligns with the Servlet Specification’s default dispatcher type.

Like any other Spring bean, you can define the order of Servlet filter beans; pleasemake sure to check the“the section called “Registering Servlets, Filters, and Listeners as Spring Beans””section.

Disable Registration of a Servlet or Filter

As described earlier, anyServlet or Filter beans are registered with the servlet container automatically. Todisable registration of a particular Filter or Servlet bean, create a registrationbean for it and mark it as disabled, as shown in the following example:

@Beanpublic FilterRegistrationBean registration(MyFilter filter) {FilterRegistrationBean registration = new FilterRegistrationBean(filter);registration.setEnabled(false);return registration;}

76.10.2Add Servlets, Filters, and Listeners by Using Classpath Scanning

@WebServlet, @WebFilter, and @WebListener annotated classes can be automaticallyregistered with an embedded servlet container by annotating a @Configuration classwith @ServletComponentScan and specifying the package(s) containing the componentsthat you want to register. By default, @ServletComponentScan scans from the packageof the annotated class.

76.11Configure Access Logging

Access logs can be configured for Tomcat, Undertow, and Jetty through their respectivenamespaces.

For instance, the following settings log access on Tomcat with acustom pattern.

server.tomcat.basedir=my-tomcatserver.tomcat.accesslog.enabled=trueserver.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
76.Embedded Web Servers (5)Note

The default location for logs is a logs directory relative to the Tomcat basedirectory. By default, the logs directory is a temporary directory, so you may want tofix Tomcat’s base directory or use an absolute path for the logs. In the precedingexample, the logs are available in my-tomcat/logs relative to the working directory ofthe application.

Access logging for Undertow can be configured in a similar fashion, as shown in thefollowing example:

server.undertow.accesslog.enabled=trueserver.undertow.accesslog.pattern=%t %a "%r" %s (%D ms)

Logs are stored in a logs directory relative to the working directory of theapplication. You can customize this location by setting theserver.undertow.accesslog.directory property.

Finally, access logging for Jetty can also be configured as follows:

server.jetty.accesslog.enabled=trueserver.jetty.accesslog.filename=/var/log/jetty-access.log

By default, logs are redirected to System.err. For more details, seethe Jetty documentation.

76.12Running Behind a Front-end Proxy Server

Your application might need to send 302 redirects or render content with absolute linksback to itself. When running behind a proxy, the caller wants a link to the proxy and notto the physical address of the machine hosting your app. Typically, such situations arehandled through a contract with the proxy, which adds headers to tell the back end how toconstruct links to itself.

If the proxy adds conventional X-Forwarded-For and X-Forwarded-Proto headers (mostproxy servers do so), the absolute links should be rendered correctly, providedserver.use-forward-headers is set to true in your application.properties.

76.Embedded Web Servers (6)Note

If your application runs in Cloud Foundry or Heroku, theserver.use-forward-headers property defaults to true. In allother instances, it defaults to false.

76.12.1Customize Tomcat’s Proxy Configuration

If you use Tomcat, you can additionally configure the names of the headers used tocarry “forwarded” information, as shown in the following example:

server.tomcat.remote-ip-header=x-your-remote-ip-headerserver.tomcat.protocol-header=x-your-protocol-header

Tomcat is also configured with a default regular expression that matches internalproxies that are to be trusted. By default, IP addresses in 10/8, 192.168/16,169.254/16 and 127/8 are trusted. You can customize the valve’s configuration byadding an entry to application.properties, as shown in the following example:

server.tomcat.internal-proxies=192\\.168\\.\\d{1,3}\\.\\d{1,3}
76.Embedded Web Servers (7)Note

The double backslashes are required only when you use a properties file forconfiguration. If you use YAML, single backslashes are sufficient, and a valueequivalent to that shown in the preceding example would be 192\.168\.\d{1,3}\.\d{1,3}.

76.Embedded Web Servers (8)Note

You can trust all proxies by setting the internal-proxies to empty (but do not doso in production).

You can take complete control of the configuration of Tomcat’s RemoteIpValve byswitching the automatic one off (to do so, set server.use-forward-headers=false) andadding a new valve instance in a TomcatServletWebServerFactory bean.

76.13Enable Multiple Connectors with Tomcat

You can add an org.apache.catalina.connector.Connector to theTomcatServletWebServerFactory, which can allow multiple connectors, including HTTP andHTTPS connectors, as shown in the following example:

@Beanpublic ServletWebServerFactory servletContainer() {TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();tomcat.addAdditionalTomcatConnectors(createSslConnector());return tomcat;}private Connector createSslConnector() {Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();try {File keystore = new ClassPathResource("keystore").getFile();File truststore = new ClassPathResource("keystore").getFile();connector.setScheme("https");connector.setSecure(true);connector.setPort(8443);protocol.setSSLEnabled(true);protocol.setKeystoreFile(keystore.getAbsolutePath());protocol.setKeystorePass("changeit");protocol.setTruststoreFile(truststore.getAbsolutePath());protocol.setTruststorePass("changeit");protocol.setKeyAlias("apitester");return connector;}catch (IOException ex) {throw new IllegalStateException("can't access keystore: [" + "keystore"+ "] or truststore: [" + "keystore" + "]", ex);}}

76.14Use Tomcat’s LegacyCookieProcessor

By default, the embedded Tomcat used by Spring Boot does not support "Version 0" of theCookie format, so you may see the following error:

java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value

If at all possible, you should consider updating your code to only store valuescompliant with later Cookie specifications. If, however, you cannot change theway that cookies are written, you can instead configure Tomcat to use aLegacyCookieProcessor. To switch to the LegacyCookieProcessor, use anWebServerFactoryCustomizer bean that adds a TomcatContextCustomizer, as shownin the following example:

@Beanpublic WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {return (factory) -> factory.addContextCustomizers((context) -> context.setCookieProcessor(new LegacyCookieProcessor()));}

76.15Enable Multiple Listeners with Undertow

Add an UndertowBuilderCustomizer to the UndertowServletWebServerFactory andadd a listener to the Builder, as shown in the following example:

@Beanpublic UndertowServletWebServerFactory servletWebServerFactory() {UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {@Overridepublic void customize(Builder builder) {builder.addHttpListener(8080, "0.0.0.0");}});return factory;}

76.16Create WebSocket Endpoints Using @ServerEndpoint

If you want to use @ServerEndpoint in a Spring Boot application that used an embeddedcontainer, you must declare a single ServerEndpointExporter @Bean, as shown in thefollowing example:

@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}

The bean shown in the preceding example registers any @ServerEndpoint annotated beanswith the underlying WebSocket container. When deployed to a standalone servlet container,this role is performed by a servlet container initializer, and theServerEndpointExporter bean is not required.

76. Embedded Web Servers (2024)
Top Articles
Latest Posts
Article information

Author: Rob Wisoky

Last Updated:

Views: 5870

Rating: 4.8 / 5 (48 voted)

Reviews: 87% of readers found this page helpful

Author information

Name: Rob Wisoky

Birthday: 1994-09-30

Address: 5789 Michel Vista, West Domenic, OR 80464-9452

Phone: +97313824072371

Job: Education Orchestrator

Hobby: Lockpicking, Crocheting, Baton twirling, Video gaming, Jogging, Whittling, Model building

Introduction: My name is Rob Wisoky, I am a smiling, helpful, encouraging, zealous, energetic, faithful, fantastic person who loves writing and wants to share my knowledge and understanding with you.