Computer scienceBackendKtorKtor Introduction

Ktor configuration

6 minutes read

In this topic, we will learn how to configure your Ktor application. When you write an application, you can leave the default settings such as host, port, and so on. What if the default port is already occupied by another process, or you want to set SSL encryption for your application? In such cases, the default configuration is not enough, and you can do some fine-tuning by configuring your application.

Configuration in code

The first way to configure the server is to specify the necessary parameters in the embeddedServer constructor in Application.kt file. The advantages of this way are:

  • Easy to use.
  • All parameters are right in the server builder constructor.
  • No need for external configuration files.

For example, you can specify host and port in constructor as named parameters. Let's configure our Netty server to listen 0.0.0.0:8080:

fun main() {
    embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
        // server code
    }.start(wait = true)
}

Engine configuration

To configure specific settings for the engine, we can use configure parameter:

fun main() {
    embeddedServer(
        Netty, port = 8080, host = "0.0.0.0", configure = {
            responseWriteTimeoutSeconds = 10
            workerGroupSize = 5
            callGroupSize = 10
        }
    ) {
        // server code
    }.start(wait = true)
}

As always, we have configured the server to listen 8080 port on the localhost. When configuring the server engine, it is important to configure the number of resources to perform a specific task.

  • responseWriteTimeoutSeconds — timeout in seconds for sending responses to client.
  • workerGroupSize — specifies the number of resources for doing engine's internal work (processing connections, parsing messages, and so on).
  • callGroupSize — specifies the number of resources for running application code.

Custom application environment

Finally, you can configure application settings with a custom environment represented by the ApplicationEngineEnvironment interface. This is a more flexible way to configure the application than the previous ones. For example, you can configure SSL encryption by specifying the appropriate connector.

The following code snippet is a simple example of a custom application environment:

fun Application.serverModule() {
    configureRouting()
}

fun main() {
    embeddedServer(Netty, environment = applicationEngineEnvironment {
        connector {
            port = 8080
            host = "127.0.0.1"
        }
        
        module {
            serverModule()
        }
    }).start(true)
}
  • connector — describes where and how server should listen. Connector supports HTTP and HTTPS protocols. In our case, server will listen 8080 port on the localhost over the HTTP protocol.
  • module — application module to run. The module provides the main logic of the application, processing routes as in our example.

Configuration in HOCON file

The other way to configure the server is to specify server parameters in the external application.conf HOCON file placed in application resources. The advantages of this way are:

  • Greater flexibility in the server configuration.
  • The ability to change configuration without rebuilding the application.
  • The ability to override parameters by passing command-line arguments when running the packaged application.

HOCON is a JSON-based config file format, but this format is less strict. Usually, files of this format have an extension.conf as well as the application.conf settings file.

If you want to configure the server this way, application.conf should contain modules to load and port to listen:

application.conf

ktor {
    deployment {
        port = 8080
    }
    application {
        modules = [ com.example.ApplicationKt.serverModule ]
    }
}

Application.kt

fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)

fun Application.serverModule() {
    configureRouting()
}

Note that the modules you specify in application.conf match the extension functions that will be loaded.

Predefined settings that you can use:

  • ktor.config — a server engine configuration block (similar to the enigne settings in the code).

  • ktor.deployment.host — a host address.

  • ktor.deployment.port — a listening port. You can set this property to 0 to run the server on a random port.

  • ktor.deployment.watch — watch paths used for auto-reloading.

  • ktor.deployment.rootPath — a servlet context path.

  • ktor.deployment.shutdown.url — a shutdown URL.

  • ktor.deployment.sslPort — a listening SSL port. You can set this property to 0 to run the server on a random port. SSL requires additional options:

    • ktor.security.ssl.keyStore — an SSL key store.

    • ktor.security.ssl.keyAlias — an alias for the SSL key store.

    • ktor.security.ssl.keyStorePassword — a password for the SSL key store.

    • ktor.security.ssl.privateKeyPassword — a password for the SSL private key.

Advanced configuration

If you want to set up an ssl encryption, just specify security block and add an SSL port in the application.conf:

ktor {
    deployment {
        port = 8080
        sslPort = 8443
    }
    application {
        modules = [ com.example.ApplicationKt.serverModule ]
    }
    security {
        ssl {
            keyStore = keystore.jks
            keyAlias = sampleAlias
            keyStorePassword = keep_it_secret
            privateKeyPassword = keep_it_secret
        }
    }
}

Do not store secret data like keyStorePassword, privateKeyPassword or secret in configuration files. Use environment variables to specify such parameters.

Environment variables

As mentioned above, we should store some data in environment variables (not only secrets). For example, you may need to obtain a port parameter or a JWT secret from environment variables:

ktor {
    deployment {
        port = ${PORT}
    }
    jwt {
        secret = ${JWT_SECRET}
        issuer = "http://0.0.0.0:8080/"
        audience = "http://0.0.0.0:8080/admin"
        realm = "Access to admin page"
    }
}

What is more, you can provide a default variable value if you are not sure that the required environment variable exists:

ktor {
    deployment {
        port = 8080
        port = ${?PORT}
    }
}

Command line arguments

When you are running packaged (or built) application from the command-line, you can override parameters by passing command-line arguments. For example, you are going to run ktor-sample.jar, but the specified port is occupied by another process, so you want to specify a free one:

java -jar ktor-sample.jar -port=8081

You can override the following parameters:

  • -config — a path to a custom configuration file used instead of application.conf from resources.
  • -host — a host address.

  • -port — a listening port.

  • -watch — watch paths used for auto-reloading.

  • -sslPort — a listening SSL port.

  • -sslKeyStore — an SSL key store.

Conclusion

We have learned two ways to configure the application:

  • In code is the quick and easy way with no need in external config files.
  • In HOCON config file is the flexible, secure way with no need to rebuild the application to apply the new settings.

Now, you can choose the way to configure your application depending on your needs.

5 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo