Documentation

You are viewing the documentation for the 3.0.0 release. The latest stable release series is 3.0.x.

§Configuring the Pekko HTTP server backend

By default, Play uses the Pekko HTTP server backend.

Like the rest of Play, the Pekko HTTP server backend is configured with Typesafe Config.

# Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>

# Configuration for Play's PekkoHttpServer
play {

  server {
    # The server provider class name
    provider = "play.core.server.PekkoHttpServerProvider"

    pekko {
      # How long to wait when binding to the listening socket
      bindTimeout = 5 seconds

      # How long a request takes until it times out. Set to null or "infinite" to disable the timeout.
      requestTimeout = infinite

      # Enables/disables automatic handling of HEAD requests.
      # If this setting is enabled the server dispatches HEAD requests as GET
      # requests to the application and automatically strips off all message
      # bodies from outgoing responses.
      # Note that, even when this setting is off the server will never send
      # out message bodies on responses to HEAD requests.
      # For Play to work correctly with WebSockets, you should avoid setting this config to "on",
      # see https://github.com/playframework/playframework/pull/7060
      transparent-head-requests = off

      # If this setting is empty the server only accepts requests that carry a
      # non-empty `Host` header. Otherwise it responds with `400 Bad Request`.
      # Set to a non-empty value to be used in lieu of a missing or empty `Host`
      # header to make the server accept such requests.
      # Note that the server will never accept HTTP/1.1 request without a `Host`
      # header, i.e. this setting only affects HTTP/1.1 requests with an empty
      # `Host` header as well as HTTP/1.0 requests.
      # Examples: `www.spray.io` or `example.com:8080`
      default-host-header = ""

      # The default value of the `Server` header to produce if no
      # explicit `Server`-header was included in a response.
      # If this value is null and no header was included in
      # the request, no `Server` header will be rendered at all.
      server-header = null
      server-header = ${?play.server.server-header}

      # Configures the processing mode when encountering illegal characters in
      # header value of response.
      #
      # Supported mode:
      # `error`  : default mode, throw an ParsingException and terminate the processing
      # `warn`   : ignore the illegal characters in response header value and log a warning message
      # `ignore` : just ignore the illegal characters in response header value
      illegal-response-header-value-processing-mode = warn

      # Enables/disables inclusion of an Tls-Session-Info header in parsed
      # messages over Tls transports (i.e., HttpRequest on server side and
      # HttpResponse on client side).
      #
      # See Pekko HTTP `pekko.http.server.parsing.tls-session-info-header` for
      # more information about how this works.
      tls-session-info-header = on

      # The maximum number of requests that are accepted (and dispatched to
      # the application) on one single connection before the first request
      # has to be completed.
      # Incoming requests that would cause the pipelining limit to be exceeded
      # are not read from the connections socket so as to build up "back-pressure"
      # to the client via TCP flow control.
      # A setting of 1 disables HTTP pipelining, since only one request per
      # connection can be "open" (i.e. being processed by the application) at any time.
      # This value must be > 0 and <= 1024.
      pipelining-limit = 16
    }
  }

}

The configurations above are specific to Pekko HTTP server backend, but other more generic configurations are also available:

# Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>

play {

  server {

    # The root directory for the Play server instance. This value can
    # be set by providing a path as the first argument to the Play server
    # launcher script. See `ServerConfig.loadConfiguration`.
    dir = ${?user.dir}

    # HTTP configuration
    http {
      # The HTTP port of the server. Use a value of "disabled" if the server
      # shouldn't bind an HTTP port.
      port = 9000
      port = ${?PLAY_HTTP_PORT}
      port = ${?http.port}

      # The interface address to bind to.
      address = "0.0.0.0"
      address = ${?PLAY_HTTP_ADDRESS}
      address = ${?http.address}

      # The idle timeout for an open connection after which it will be closed
      # Set to null or "infinite" to disable the timeout, but notice that this
      # is not encouraged since timeout are important mechanisms to protect your
      # servers from malicious attacks or programming mistakes.
      idleTimeout = 75 seconds
    }

    # HTTPS configuration
    https {

      # The HTTPS port of the server.
      port = ${?PLAY_HTTPS_PORT}
      port = ${?https.port}

      # The interface address to bind to
      address = "0.0.0.0"
      address = ${?PLAY_HTTPS_ADDRESS}
      address = ${?https.address}

      # The idle timeout for an open connection after which it will be closed
      # Set to null or "infinite" to disable the timeout, but notice that this
      # is not encouraged since timeout are important mechanisms to protect your
      # servers from malicious attacks or programming mistakes.
      idleTimeout = ${play.server.http.idleTimeout}

      # The SSL engine provider
      engineProvider = "play.core.server.ssl.DefaultSSLEngineProvider"
      engineProvider = ${?play.http.sslengineprovider}

      # HTTPS keystore configuration, used by the default SSL engine provider
      keyStore {
        # The path to the keystore
        path = ${?https.keyStore}

        # The type of the keystore
        type = "JKS"
        type = ${?https.keyStoreType}

        # The password for the keystore
        password = ""
        password = ${?https.keyStorePassword}

        # The algorithm to use. If not set, uses the platform default algorithm.
        algorithm = ${?https.keyStoreAlgorithm}
      }

      # HTTPS truststore configuration
      trustStore {

        # If true, does not do CA verification on client side certificates
        noCaVerification = false
      }

      # Whether JSSE want client auth mode should be used. This means, the server
      # will request a client certificate, but won't fail if one isn't provided.
      wantClientAuth = false

      # Whether JSSE need client auth mode should be used. This means, the server
      # will request a client certificate, and will fail and terminate the session
      # if one isn't provided.
      needClientAuth = false
    }

    # The path to the process id file created by the server when it runs.
    # If set to "/dev/null" then no pid file will be created.
    pidfile.path = ${play.server.dir}/RUNNING_PID
    pidfile.path = ${?pidfile.path}

    websocket {
      # Maximum allowable frame payload length. Setting this value to your application's
      # requirement may reduce denial of service attacks using long data frames.
      frame.maxLength = 64k
      frame.maxLength = ${?websocket.frame.maxLength}

      # Periodic keep alive may be implemented using by sending Ping frames
      # upon which the other side is expected to reply with a Pong frame,
      # or by sending a Pong frame, which serves as unidirectional heartbeat.
      # Valid values:
      #   ping - default, for bi-directional ping/pong keep-alive heartbeating
      #   pong - for uni-directional pong keep-alive heartbeating
      periodic-keep-alive-mode = ping

      # Interval for sending periodic keep-alives
      # If a client does not send a frame within this idle time, the server will sent the the keep-alive frame.
      # The frame sent will be the one configured in play.server.websocket.periodic-keep-alive-mode
      # `infinite` by default, or a duration that is the max idle interval after which an keep-alive frame should be sent
      # The value `infinite` means that *no* keep-alive heartbeat will be sent, as: "the allowed idle time is infinite"
      periodic-keep-alive-max-idle = infinite
    }

    debug {
      # If set to true this will attach an attribute to each request containing debug information. If the application
      # fails to load (e.g. due to a compile issue in dev mode), then this configuration value is ignored and the debug
      # information is always attached.
      #
      # Note: This configuration option is not part of Play's public API and is subject to change without the usual
      # deprecation cycle.
      addDebugInfoToRequests = false
    }

    # The maximum length of the HTTP headers. The most common effect of this is a restriction in cookie length, including
    # number of cookies and size of cookie values.
    max-header-size = 8k

    # If a request contains a Content-Length header it will be checked against this maximum value.
    # If the value of a given Content-Length header exceeds this configured value, the request will not be processed
    # further but instead the error handler will be called with Http status code 413 "Entity too large".
    # If set to infinite or if no Content-Length header exists then no check will take place at all
    # and the request will continue to be processed.
    # Play uses the concept of a `BodyParser` to enforce this limit, so we set it to infinite.
    max-content-length = infinite

    # Timeout after which all requests and connections shall be forcefully terminated
    # when shutting down the server. When this timeout gets applied, already the server is not bound to ports
    # and therefore not accepting new connections anymore. It will default to Coordinated Shutdown service-requests-done
    # phase timeout. Because of that default, Play will trigger the timeout 100 milliseconds earlier than actually configured
    # via this config to make sure it fires before the service-requests-done phase ends.
    # Value must be a duration, for example:
    #   play.server.terminationTimeout = 5 seconds
    # This should be less than or equal to the value for `pekko.coordinated-shutdown.phases.service-requests-done.timeout`
    # to prevent early server terminations by the underlying Pekko Coordinated Shutdown system.
    terminationTimeout = null

    # The delay to wait before the server will shut down requests and connections via "graceful" termination. When
    # this delay gets applied, already the server is not bound to ports and therefore not accepting new connections anymore.
    # This config might help you do work around a bug which causes the pekko-http backend to not take response entity streams into account
    # during graceful termination, giving those responses time to finish: https://github.com/akka/akka-http/issues/3209
    # By default, no delay is applied.
    # Value must be a duration, for example:
    #   play.server.waitBeforeTermination = 2 seconds
    # Be aware that `waitBeforeTermination` and `terminationTimeout` both happen within the Coordinated Shutdown `service-requests-done` phase.
    # Therefore, the total value of the two configs should not be longer than the total timeout of the `service-requests-done` phase.
    waitBeforeTermination = 0

    # If body parsing should happen before executing actions defined via action composition (default) or if it should
    # be deferred to a later point in time.
    # Depending on the used Play plugin (PlayScala or PlayJava), setting this config to true will behave slightly differently.
    # Please see the docs for more details:
    # PlayScala
    # https://playframework.com/documentation/latest/ScalaActionsComposition#Action-composition-in-interaction-with-body-parsing
    # PlayJava
    # https://playframework.com/documentation/latest/JavaActionsComposition#Action-composition-in-interaction-with-body-parsing
    deferBodyParsing = false
  }

  editor = ${?PLAY_EDITOR}

}

You can read more about the configuration settings in the Pekko HTTP documentation.

Note: Pekko HTTP has a number of timeouts configurations that you can use to protect your application from attacks or programming mistakes. The Pekko HTTP Server in Play will automatically recognize all these Pekko configurations. For example, if you have idle-timeout and request-timeout configurations like below:

pekko.http.server.idle-timeout = 30s
pekko.http.server.request-timeout = 20s

They will be automatically recognized. Keep in mind that Play configurations listed above will override the Pekko ones.

When setting the request-timeout, make sure it is smaller than the idle-timeout. Otherwise the idle-timeout will kick in first and reset the TCP connection without a response.

There is also a separate configuration file for the HTTP/2 support in Pekko HTTP, if you have enabled the `PekkoHttp2Support` plugin:

# Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>

# Determines whether HTTP2 is enabled.
play.server.pekko.http2 {
  enabled = true
  enabled = ${?http2.enabled}
}

Note: In dev mode, when you use the run command, your application.conf settings will not be picked up by the server. This is because in dev mode the server starts before the application classpath is available. There are several other options you’ll need to use instead.

§Direct Pekko HTTP configuration

If you need direct access to Pekko HTTP’s ServerSettings and ParserSettings objects you can do this by extending Play’s PekkoHttpServer class with your own. The PekkoHttpServer class has several protected methods which can be overridden to change how Play configures its Pekko HTTP backend.

Note that writing your own server class is advanced usage. Usually you can do all the configuration you need through normal configuration settings.

The code below shows an example of a custom server which modifies some Pekko HTTP settings. Below the server class is a ServerProvider class which acts as a factory for the custom server.

package server

import java.util.Random

import org.apache.pekko.http.scaladsl.model.HttpMethod
import org.apache.pekko.http.scaladsl.settings.ParserSettings
import org.apache.pekko.http.scaladsl.settings.ServerSettings
import org.apache.pekko.http.scaladsl.ConnectionContext
import play.core.server.PekkoHttpServer
import play.core.server.PekkoHttpServerProvider
import play.core.server.ServerProvider

/** A custom Pekko HTTP server with advanced configuration. */
class CustomPekkoHttpServer(context: PekkoHttpServer.Context) extends PekkoHttpServer(context) {
  protected override def createParserSettings(): ParserSettings = {
    val defaultSettings: ParserSettings =
      super.createParserSettings()
    defaultSettings.withCustomMethods(HttpMethod.custom("TICKLE"))
  }
  protected override def createServerSettings(
      port: Int,
      connectionContext: ConnectionContext,
      secure: Boolean
  ): ServerSettings = {
    val defaultSettings: ServerSettings =
      super.createServerSettings(port, connectionContext, secure)
    defaultSettings.withWebsocketRandomFactory(() => new Random())
  }
}

/** A factory that instantiates a CustomPekkoHttpServer. */
class CustomPekkoHttpServerProvider extends ServerProvider {
  def createServer(context: ServerProvider.Context): CustomPekkoHttpServer = {
    val serverContext = PekkoHttpServer.Context.fromServerProviderContext(context)
    new CustomPekkoHttpServer(serverContext)
  }
}

Once you’ve written a custom server and ServerProvider class you’ll need to tell Play about them by setting the play.server.provider configuration option to the full name of your ServerProvider class.

For example, adding the following settings to your build.sbt and application.conf will tell Play to use your new server for both the sbt run task and when your application is deployed.

build.sbt:

PlayKeys.devSettings += "play.server.provider" -> "server.CustomPekkoHttpServerProvider"

application.conf:

play.server.provider = server.CustomPekkoHttpServerProvider

Next: Configuring Netty Server Backend