Configuring the Server

    Ktor also uses a set of lambdas with a typed DSL (Domain Specific Language) to configure the applicationand server engine when using embeddedServer.

    Starting with Ktor 1.0.0-beta-2, the DevelopmentEngine class has been renamed to EngineMain, for older versions just rename it.

    Table of contents:

    This is the preferred way of configuring Ktor applications as it allows youto easily change the configuration without recompiling your application.

    When Ktor is started using a EngineMain, or by calling the commandLineEnvironment,it tries to load a HOCON file called application.conf from the application resources.You can change the location of the file using command line arguments.

    Available development engines that you can use as mainClassName:

    • io.ktor.server.cio.EngineMain
    • io.ktor.server.tomcat.EngineMain
    • io.ktor.server.jetty.EngineMain
    • io.ktor.server.netty.EngineMain

    Ktor only requires you to specify which you want it to load when starting the server using the ktor.application.modules property.All the other properties are optional.

    A typical, simple HOCON file for Ktor (application.conf) would look like this:

    Using dot notation it would be equivalent to:

    1. ktor.deployment.port = 8080
    2. ktor.application.modules = [ io.ktor.samples.metrics.MetricsApplicationKt.main ]

    Ktor allows you to configure much more: from additional core configurationsto Ktor features, and even custom configurations for your applications:

    1. ktor {
    2. deployment {
    3. environment = development
    4. port = 8080
    5. sslPort = 8443
    6. autoreload = true
    7. watch = [ httpbin ]
    8. }
    9. application {
    10. modules = [ io.ktor.samples.httpbin.HttpBinApplicationKt.main ]
    11. }
    12. security {
    13. ssl {
    14. keyStore = build/temporary.jks
    15. keyAlias = mykey
    16. keyStorePassword = changeit
    17. privateKeyPassword = changeit
    18. }
    19. }
    20. }
    21. jwt {
    22. domain = "https://jwt-provider-domain/"
    23. audience = "jwt-audience"
    24. realm = "ktor sample app"
    25. }
    26. youkube {
    27. session {
    28. cookie {
    29. key = 03e156f6058a13813816065
    30. }
    31. }
    32. upload {
    33. dir = ktor-samples/ktor-samples-youkube/.video
    34. }

    There is a list of the available core configurations in this document.

    You can use HOCON to .

    There is an IntelliJ plugin for HOCON, that you may want to install.

    Command Line

    When using commandLineEnvironment(any EngineMain main) there are several switches and configuration parameters you can use to configureyour application module.

    If you start the application from the command line with -config=anotherfile.conf, it willload the config file from the specific local file instead of from the resources.

    Using switches, you can, for example, override the bound port defined by executing:

    There is a in this document.

    embeddedServer is a simple way to start a Ktor application. You provide your own main function,and being more explicit, it is easier to understand what happens exactly.

    embeddedServer includes an optional parameter configure that allows you to set the configuration for theengine specified in the first parameter.Independent to the engine used, you will have some available properties to configure:

    1. embeddedServer(AnyEngine, configure = {
    2. // Size of the event group for accepting connections
    3. connectionGroupSize = parallelism / 2 + 1
    4. // Size of the event group for processing connections,
    5. // parsing messages and doing engine's internal work
    6. workerGroupSize = parallelism / 2 + 1
    7. // Size of the event group for running application code
    8. callGroupSize = parallelism
    9. }) {
    10. // ...
    11. }.start(true)

    It is possible to define by code several connectors using the applicationEngineEnvironment.

    Inside the applicationEngineEnvironment, you can define HTTP and HTTPS connectors:

    To define a HTTP connector:

    1. connector {
    2. host = "0.0.0.0"
    3. port = 9090
    4. }

    To define a HTTPS connector:

    1. sslConnector(keyStore = keyStore, keyAlias = "mykey", keyStorePassword = { "changeit".toCharArray() }, privateKeyPassword = { "changeit".toCharArray() }) {
    2. port = 9091
    3. keyStorePath = keyStoreFile.absoluteFile

    An actual example:

    1. fun main(args: Array<String>) {
    2. val env = applicationEngineEnvironment {
    3. module {
    4. main()
    5. }
    6. // Private API
    7. connector {
    8. host = "127.0.0.1"
    9. port = 9090
    10. }
    11. // Public API
    12. connector {
    13. host = "0.0.0.0"
    14. port = 8080
    15. }
    16. }
    17. embeddedServer(Netty, env).start(true)
    18. }

    The application will handle all the connections. You have access to the local port for each ApplicationCall,so you can decide what to do based on the local port:

    1. fun Application.main() {
    2. routing {
    3. get("/") {
    4. if (call.request.local.port == 8080) {
    5. call.respondText("Connected to public api")
    6. } else {
    7. call.respondText("Connected to private api")
    8. }
    9. }
    10. }
    11. }

    You can see a complete example of this in ktor-samples/multiple-connectors.

    When using Netty as the engine, in addition to common properties, you can configure some other properties:

    When using Jetty as the engine, in addition to common properties, you can configure the Jetty server.

    1. embeddedServer(Jetty, configure = {
    2. // Property to provide a lambda that will be called during Jetty
    3. // server initialization with the server instance as an argument.
    4. configureServer = {
    5. // ...
    6. }
    7. }) {
    8. // ...
    9. }.start(true)

    When using CIO (Coroutine I/O) as the engine, in addition to common properties, you can configure the connectionIdleTimeoutSeconds property.

    1. embeddedServer(CIO, configure = {
    2. // Number of seconds that the server will keep HTTP IDLE connections open.
    3. // A connection is IDLE if there are no active requests running.
    4. connectionIdleTimeoutSeconds = 45
    5. }) {
    6. }.start(true)

    When using Tomcat, in addition to common properties, you can configure the Tomcat server.

    1. embeddedServer(Tomcat, configure = {
    2. // Property to provide a lambda that will be called during Tomcat
    3. // server initialization with the server instance as argument.
    4. configureTomcat { // this: Tomcat ->
    5. // ...
    6. }
    7. }) {
    8. // ...
    9. }.start(true)

    Those are the official engines developed for Ktor, but it is also possible to and provide custom configurations for them.

    Available configuration parameters

    There is a list of properties which Ktor understands out of the box and that you canpass from the command line or the HOCON file.

    java -jar myapp-fatjar.jar -port=8080

    Parameter paths are paths inside the application.conf file:

    1. ktor.deployment.port = 8080
    1. ktor {
    2. deployment {
    3. port = 8080
    4. }
    5. }

    General switches and parameters:

    Required when SSL port is defined:

    SwitchParameter pathDefaultDescription
    -sslPort=ktor.deployment.sslPortnullSSL port
    -sslKeyStore=ktor.security.ssl.keyStorenullSSL key store
    ktor.security.ssl.keyAliasmykeyAlias for the SSL key store
    ktor.security.ssl.keyStorePasswordnullPassword for the SSL key store
    ktor.security.ssl.privateKeyPasswordnullPassword for the SSL private key

    You can use -P: to specify parameters that don’t have a specific switch. For example:-P:ktor.deployment.callGroupSize=7.

    If you are using a EngineMain instead of an embeddedServer, the HOCON file is loaded,and you are able to access its configuration properties.

    You can also define arbitrary property paths to configure your application.

    1. val port: String = application.environment.config
    2. .propertyOrNull("ktor.deployment.port")?.getString()
    3. ?: "80"

    It is possible to access the HOCON application.conf configuration too, by using a custom main with commandLineEnvironment:

    1. embeddedServer(Netty, commandLineEnvironment(args + arrayOf("-port=8080"))).start(true)

    Or by redirecting it to the specific EngineMain.main:

    Or with a custom applicationEngineEnvironment:

    1. embeddedServer(Netty, applicationEngineEnvironment {
    2. log = LoggerFactory.getLogger("ktor.application")
    3. config = HoconApplicationConfig(ConfigFactory.load()) // Provide a Hocon config file
    4. module {
    5. routing {
    6. get("/") {
    7. call.respondText("HELLO")
    8. }
    9. }
    10. }
    11. connector {
    12. port = 8080
    13. host = "127.0.0.1"
    14. }
    15. }).start(true)

    You can also access the configuration properties by manually loading the default config file application.conf:

    1. val config = HoconApplicationConfig(ConfigFactory.load())

    Using environment variables

    For HOCON, if you want to configure some parameters using environment variables,you can use environment substitution using ${ENV} syntax. For example:

    1. ktor {
    2. deployment {
    3. port = ${PORT}
    4. }
    5. }

    This will look for a PORT environment variable, and if not found an exception will be thrown:

    1. Exception in thread "main" com.typesafe.config.ConfigException$UnresolvedSubstitution: application.conf @ file:/path/to/application.conf: 3: Could not resolve substitution to a value: ${PORT}

    In case you want to provide a default value for a property because the environment doesn’t exist, you can set the property with the default value, and then set it again with the ${?ENV} syntax:

    1. ktor {
    2. deployment {
    3. port = 8080
    4. port = ${?PORT}
    5. }
    6. }

    If you are using embeddedServer you can still use System.getenv from Java. For example:

    1. val port = System.getenv("PORT")?.toInt() ?: 8080

    Ktor provides an interface that you can implement the configuration in, available at application.environment.config.You can construct and set the configuration properties inside an applicationEngineEnvironment.

    1. interface ApplicationConfig {
    2. fun property(path: String): ApplicationConfigValue
    3. fun propertyOrNull(path: String): ApplicationConfigValue?
    4. fun config(path: String): ApplicationConfig
    5. fun configList(path: String): List<ApplicationConfig>
    6. }
    7. interface ApplicationConfigValue {
    8. fun getString(): String
    9. fun getList(): List<String>
    10. }

    You can create and compose config implementations and set them at , so it is available to all theapplication components.