Hosting

Hosting with Docker

Docker allows to build, package and run your applications developed with genhttp-kt on any server, whether it is on your NAS at home or a Kubernetes cluster in the cloud.

As genhttp-kt runs on the JVM, we can use the base images of a JDK distribution to set up our build chain. The samples below use Eclipse Temurin - for a list of available base images, see their Docker Hub page.

Creating a new Dockerfile

The Dockerfile below builds your application with Gradle and runs it with the start script created by the application plugin, so your build.gradle.kts needs to apply it and name the main class of your app:

build.gradle.kts
plugins {
    kotlin("jvm") version "2.4.21"
    application
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.genhttp:genhttp-full:11.1.0.3")
}

kotlin {
    jvmToolchain(25)
}

application {
    mainClass = "MainKt" // the main function in Main.kt
}

Create a new file named Dockerfile in the root directory of your repository and paste the following content:

Dockerfile
# syntax=docker/dockerfile:1

FROM eclipse-temurin:25-jdk AS build

WORKDIR /source

# copy the project and build it - the cache mount keeps
# Gradle and the dependencies between builds
COPY . .
RUN --mount=type=cache,target=/root/.gradle ./gradlew installDist --no-daemon

# final stage/image
FROM eclipse-temurin:25-jre

# allow the heap to use 75 % of the memory of the container (instead of 25 %)
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75"

WORKDIR /app
COPY --from=build /source/build/install/my-app/ .

ENTRYPOINT ["/app/bin/my-app"]

EXPOSE 8080

To keep the output of local builds out of the image, add a .dockerignore file next to it that lists .gradle and **/build.

If you are hosting on the Netty engine, its native transports come with the dependency, the image needs nothing else. Keep in mind that io_uring (if you select it as the transport) is provided by the host’s Linux kernel, not the image - it is unavailable on hosts with an older kernel or on container runtimes that block its system calls (e.g. with their default seccomp profile). The default transport, epoll, works on every Linux host.

This assumes that you named your project my-app (rootProject.name in settings.gradle.kts), which is the folder installDist writes the application to: the JARs of your app and its dependencies in lib/ and a start script in bin/. Build and run the image with docker build -t my-app . and docker run -p 8080:8080 my-app. genhttp-kt requires Java 25 or newer, so images of a newer JDK work just as well.

The start script hands over to the JVM (exec), so the signal sent by docker stop reaches your application: run() stops the server gracefully when the JVM shuts down.

Managing dependencies

Typically, your web application will have some dependencies such as databases or a redis server. docker compose allows you to define and maintain the whole infrastructure needed by your app in a single file.