How to create a simple HTTP server in Java - with Undertow

Sometimes, we all just need something really simple. A simple breakfast. A simple supper. And sometimes, a simple Java web server demo.

To do this, you could use something like Spring Boot or Quarkus.

But these frameworks require a little bit of knowledge upfront, and they add a lot of layers of complexity and overhead, for something that can really be very simple.

So in this tutorial, I’ll show you how to create a standalone Java application with a main method, which uses the Undertow web server to serve a simple “Hello, world!” message over HTTP.

You’ll create a simple, standalone command-line Java application, which is packaged as a self-contained, nicely-portable, executable JAR.

Why though?

But first - why? Where would you use this?

I created this little setup to scratch my own itch. Quite often, I need a very simple example Java application to use as part of a demo.

Sometimes, I’m writing CI/CD pipelines and I need to have a demo app that I can run through the pipeline to check that it works.

Or sometimes, I’m teaching about containers and I want a simple application that students can use and play with.

Here are some other reasons why you might use something like this:

  • To run a minimal web server in Java, which returns a static web page

  • To have an example Java app that you can use as part of something else: like a CI/CD pipeline, or perhaps to package into a Docker image and deploy to Kubernetes

  • To see how to write a standalone Java application without having to use a framework like Spring Boot or Quarkus (yes, it’s possible!)

  • How small you can go…. this produces a self-contained (fat-jar) application that packages super-small - less than 3MB! (well, small by Java standards :))


In this example we’ll use:

  • Java 8+: You’ll need to be running Java 8 or higher, because this example uses lambda syntax. So make sure you have a JDK installed.

  • Maven: We’ll use Maven as the build tool, so make sure Maven is installed.

  • Undertow: This is an embedded web server for Java. We’ll add Undertow to the project and use it to serve a simple HTML page. You don’t need to download it, as Maven will pull it in during the build.

What is Undertow?

Undertow is an alternative to other embedded web servers like Tomcat or Jetty.

Creating the project

This tutorial has just 2 files, the pom.xml and the Application class.

Your project tree should look something like this when finished:

├── pom.xml
└── src
    └── main
        └── java
            └── com
                └── tutorialworks
                    └── demos
                        └── hellorestjava

Set up pom.xml

We need to set up Maven first. So we create a pom.xml in the root. This will contain all of the dependencies that we need. Inside the pom.xml:

  • Add the io.undertow:undertow-core dependency to your pom.xml.

  • Configure the maven-assembly-plugin to build a jar-with-dependencies – this tells Maven to build our “fat-jar” artifact. You also need to tell the Assembly Plugin the mainClass which will boot your application.

Your pom.xml should look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="" xmlns:xsi=""


    <name>Hello Java</name>
    <description>An extremely simple web service that returns Hello World!</description>





Set up

Next we need to add the main code. Since this is a simple, standalone Java application, we’re going to create a main class – that is, a class with a public static void main() method, which will be the entry point to our program.

  • You can create your in any package you like, but in this example I’ve located it at src/main/java/com/tutorialworks/demos/hellorestjava/

  • In the main method, import packages from io.undertow and create an instance of Undertow. We use the builder() to configure the host and port that the web server will listen on, and the payload that it should return.

Your code should look something like this:

package com.tutorialworks.demos.hellorestjava;

import io.undertow.Undertow;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.Headers;

 * Hello world!
 * Returns a simple web page on port 8080.
public class Application {

    public static void main(String[] args) {
        Undertow server = Undertow.builder()
                // Set up the listener - you can change the port/host here
                .addHttpListener(8080, "")

                .setHandler(exchange -> {
                    // Sets the return Content-Type to text/html
                            .put(Headers.CONTENT_TYPE, "text/html");

                    // Returns a hard-coded HTML document
                            .send("<html>" +
                                    "<body>" +
                                    "<h1>Hello, world!</h1>" +
                                    "</body>" +

        // Boot the web server

Compile and run

Now, to compile the application:

mvn clean package

What does this build?

This will build a “fat-jar” (a JAR containing your application, and all of its dependencies) inside the target/ folder:

$ ll target/hello-java-1.0.0-SNAPSHOT.jar 
-rw-r--r--. 1 tdonohue tdonohue 2.8M Dec  8 08:37 target/hello-java-1.0.0-SNAPSHOT.jar

As you can see, the final jar on my laptop was only 2.8Mb!

And now to run the application, just run java -jar with the relative path to the packaged JAR file:

java -jar target/hello-java-1.0.0-SNAPSHOT.jar

Undertow should now be running on port 8080. You can use a web browser to go to http://localhost:8080 to see the output rendered as a web page, or you can use a command-line HTTP client, like curl, to fetch the web page:

$ curl http://localhost:8080
<html><body><h1>Hello, world!</h1></body></html>

To quit, just press Ctrl+C.


There you have it! We’ve created a simple Java application with an embedded web server, Undertow. The web server returns a simple web page that says “hello world”, ideal for your next demo or simple application to test.

Happy coding!


Got any thoughts on what you've just read? Anything wrong, or no longer correct? Sign in with your GitHub account to leave a comment.

(All comments get added as Issues in our GitHub repo here, using the comments tool Utterances)