74. Embedded Web servers

74.1 Use another Web server

The Spring Boot starters bring a default embedded container for you:

  • spring-boot-starter-web brings Tomcat with spring-boot-starter-tomcat, but spring-boot-starter-jetty and spring-boot-starter-undertow can be used instead.
  • spring-boot-starter-webflux brings Reactor Netty with spring-boot-starter-reactor-netty, but spring-boot-starter-tomcat, spring-boot-starter-jetty and spring-boot-starter-undertow can be used instead.

Many starters only support Spring MVC, so they transitively bring spring-boot-starter-web into your application classpath

If you choose to use a different HTTP server, you need to exclude those dependencies and include the one you chose instead. Spring Boot provides separate starters for HTTP servers to help make this process as easy as possible.

Example in Maven, for Spring MVC:

        <!-- Exclude the Tomcat dependency -->
<!-- Use Jetty instead -->

Example in Gradle, for Spring WebFlux:

configurations {
    // exclude Reactor Netty
    compile.exclude module: 'spring-boot-starter-reactor-netty'

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-webflux'
    // Use Undertow instead
    compile 'org.springframework.boot:spring-boot-starter-undertow'
    // ...

spring-boot-starter-reactor-netty is required to use the WebClient, so excluding it is not required if you wish to use a different HTTP server.

74.2 Configure Jetty

Generally you can follow the advice from Section 73.8, “Discover built-in options for external properties” about @ConfigurationProperties (ServerProperties is the main one here), but also look at ServletWebServerFactoryCustomizer. The Jetty APIs are quite rich so once you have access to the JettyServletWebServerFactory you can modify it in a number of ways. Or the nuclear option is to add your own JettyServletWebServerFactory.

74.3 Add a Servlet, Filter or Listener to an application

There are two ways to add Servlet, Filter, ServletContextListener and the other listeners supported by the Servlet spec to your application. You can either provide Spring beans for them, or enable scanning for Servlet components.

74.3.1 Add a Servlet, Filter or Listener using a Spring bean

To add a Servlet, Filter, or Servlet *Listener provide a @Bean definition for it. This can be very useful when you want to inject configuration or dependencies. However, you must be very careful that they don’t cause eager initialization of too many other beans because they have to be installed in the container very early in the application lifecycle (e.g. it’s not a good idea to have them depend on your DataSource or JPA configuration). You can work around restrictions like that by initializing them lazily when first used instead of on initialization.

In the case of Filters and Servlets you can also add mappings and init parameters by adding a FilterRegistrationBean or ServletRegistrationBean instead of or as well as the underlying component.


If no dispatcherType is specified on a filter registration, it will match FORWARD,INCLUDE and REQUEST. If async has been enabled, it will match ASYNC as well.

If you are migrating a filter that has no dispatcher element in web.xml you will need to specify a dispatcherType yourself:

public FilterRegistrationBean myFilterRegistration() {
    FilterRegistrationBean registration = new FilterRegistrationBean();

    return registration;

Disable registration of a Servlet or Filter

As described above any Servlet or Filter beans will be registered with the servlet container automatically. To disable registration of a particular Filter or Servlet bean create a registration bean for it and mark it as disabled. For example:

public FilterRegistrationBean registration(MyFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    return registration;

74.3.2 Add Servlets, Filters, and Listeners using classpath scanning

@WebServlet, @WebFilter, and @WebListener annotated classes can be automatically registered with an embedded servlet container by annotating a @Configuration class with @ServletComponentScan and specifying the package(s) containing the components that you want to register. By default, @ServletComponentScan will scan from the package of the annotated class.

74.4 Change the HTTP port

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

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

For more details look at Section 27.4.4, “Customizing embedded servlet containers” in the ‘Spring Boot features’ section, or the ServerProperties source code.

74.5 Use a random unassigned HTTP port

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

74.6 Discover the HTTP port at runtime

You can access the port the server is running on from log output or from the ServletWebServerApplicationContext via its EmbeddedWebServer. The best way to get that and be sure that it has initialized is to add a @Bean of type ApplicationListener<ServletWebServerInitializedEvent> and pull the container out of the event when it is published.

Tests that use @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) can also inject the actual port into a field using the @LocalServerPort annotation. For example:

public class MyWebIntegrationTests {

    ServletWebServerApplicationContext server;

    int port;

    // ...


@LocalServerPort is a meta-annotation for @Value("${local.server.port}"). Don’t try to inject the port in a regular application. As we just saw, the value is only set once the container has initialized; contrary to a test, application code callbacks are processed early (i.e. before the value is actually available).

74.7 Configure SSL

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


See Ssl for details of all of the supported properties.

Using configuration like the example above means the application will no longer support plain HTTP connector at port 8080. Spring Boot doesn’t support the configuration of both an HTTP connector and an HTTPS connector via application.properties. If you want to have both then you’ll need to configure one of them programmatically. It’s recommended to use application.properties to configure HTTPS as the HTTP connector is the easier of the two to configure programmatically. See the spring-boot-sample-tomcat-multi-connectors sample project for an example.

74.8 Configure Access Logging

Access logs can be configured for Tomcat, Undertow and Jetty via their respective namespaces.

For instance, the following logs access on Tomcat with a custom pattern.

server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)

The default location for logs is a logs directory relative to the tomcat base dir and said directory is a temp directory by default so you may want to fix Tomcat’s base directory or use an absolute path for the logs. In the example above, the logs will be available in my-tomcat/logs relative to the working directory of the application.

Access logging for undertow can be configured in a similar fashion

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

Logs are stored in a logs directory relative to the working directory of the application. This can be customized via server.undertow.accesslog.directory.

Finally, access logging for jetty can also be configured that way:


By default, logs will be redirected to System.err. For more details, please refer to the documentation.

74.9 Use behind a front-end proxy server

Your application might need to send 302 redirects or render content with absolute links back to itself. When running behind a proxy, the caller wants a link to the proxy, and not to the physical address of the machine hosting your app. Typically such situations are handled via a contract with the proxy, which will add headers to tell the back end how to construct links to itself.

If the proxy adds conventional X-Forwarded-For and X-Forwarded-Proto headers (most do this out of the box) the absolute links should be rendered correctly as long as server.use-forward-headers is set to true in your application.properties.


If your application is running in Cloud Foundry or Heroku the server.use-forward-headers property will default to true if not specified. In all other instances it defaults to false.

74.9.1 Customize Tomcat’s proxy configuration

If you are using Tomcat you can additionally configure the names of the headers used to carry “forwarded” information:


Tomcat is also configured with a default regular expression that matches internal proxies 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 by adding an entry to application.properties, e.g.


The double backslashes are only required when you’re using a properties file for configuration. If you are using YAML, single backslashes are sufficient and a value that’s equivalent to the one shown above would be 192\.168\.\d{1,3}\.\d{1,3}.


You can trust all proxies by setting the internal-proxies to empty (but don’t do this in production).

You can take complete control of the configuration of Tomcat’s RemoteIpValve by switching the automatic one off (i.e. set server.use-forward-headers=false) and adding a new valve instance in a TomcatServletWebServerFactory bean.

74.10 Configure Tomcat

Generally you can follow the advice from Section 73.8, “Discover built-in options for external properties” about @ConfigurationProperties (ServerProperties is the main one here), but also look at ServletWebServerFactoryCustomizer and various Tomcat-specific *Customizers that you can add in one of those. The Tomcat APIs are quite rich so once you have access to the TomcatServletWebServerFactory you can modify it in a number of ways. Or the nuclear option is to add your own TomcatServletWebServerFactory.

74.11 Enable Multiple Connectors with Tomcat

Add an org.apache.catalina.connector.Connector to the TomcatServletWebServerFactory which can allow multiple connectors, e.g. HTTP and HTTPS connector:

public ServletWebServerFactory servletContainer() {
    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
    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();
        return connector;
    catch (IOException ex) {
        throw new IllegalStateException("can't access keystore: [" + "keystore"
                + "] or truststore: [" + "keystore" + "]", ex);

74.12 Use Tomcat’s LegacyCookieProcessor

The embedded Tomcat used by Spring Boot does not support "Version 0" of the Cookie format out of the box, and 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 values compliant with later Cookie specifications. If, however, you’re unable to change the way that cookies are written, you can instead configure Tomcat to use a LegacyCookieProcessor. To switch to the LegacyCookieProcessor use an ServletWebServerFactoryCustomizer bean that adds a TomcatContextCustomizer:

public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
    return (serverFactory) -> serverFactory.addContextCustomizers(
            (context) -> context.setCookieProcessor(new LegacyCookieProcessor()));

74.13 Configure Undertow

Generally you can follow the advice from Section 73.8, “Discover built-in options for external properties” about @ConfigurationProperties (ServerProperties and ServerProperties.Undertow are the main ones here), but also look at ServletWebServerFactoryCustomizer. Once you have access to the UndertowServletWebServerFactory you can use an UndertowBuilderCustomizer to modify Undertow’s configuration to meet your needs. Or the nuclear option is to add your own UndertowServletWebServerFactory.

74.14 Enable Multiple Listeners with Undertow

Add an UndertowBuilderCustomizer to the UndertowServletWebServerFactory and add a listener to the Builder:

public UndertowServletWebServerFactory servletWebServerFactory() {
    UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
    factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {

        public void customize(Builder builder) {
            builder.addHttpListener(8080, "");

    return factory;

74.15 Create WebSocket endpoints using @ServerEndpoint

If you want to use @ServerEndpoint in a Spring Boot application that used an embedded container, you must declare a single ServerEndpointExporter @Bean:

public ServerEndpointExporter serverEndpointExporter() {
    return new ServerEndpointExporter();

This bean will register any @ServerEndpoint annotated beans with the underlying WebSocket container. When deployed to a standalone servlet container this role is performed by a servlet container initializer and the ServerEndpointExporter bean is not required.

74.16 Enable HTTP response compression

HTTP response compression is supported by Jetty, Tomcat, and Undertow. It can be enabled via application.properties:


By default, responses must be at least 2048 bytes in length for compression to be performed. This can be configured using the server.compression.min-response-size property.

By default, responses will only be compressed if their content type is one of the following:

  • text/html
  • text/xml
  • text/plain
  • text/css

This can be configured using the server.compression.mime-types property.