How to create a simple HTTP server in Java with Undertow

You can use the Undertow project to spin up an embedded web server, inside your Java app.

Sometimes, we just want something really simple. A simple breakfast. Or perhaps, a simple web server, embedded in a Java app.

To add an embedded web server to your application, you could use a framework, like Spring Boot or Quarkus. Both of these include easy options for embedding web servers.

But… frameworks require a little knowledge upfront. And frameworks add a lot of overhead, for something that can actually be solved without them.

So in this tutorial, we’ll see 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 very portable, executable JAR file.

But first, why?

Why though?

But first, why? Where would you use this?

I created this little app to scratch my own itch. Often, I need a simple example Java application, which I can use as part of a demo or teaching.

But maybe you want to do something else! Here are some other uses you might find for this little tutorial:

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

  • To add an HTTP endpoint to your existing app, perhaps to return a status message or something else to clients.

  • To create an example Java app to use as part of something bigger: like testing 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 using a framework like Spring Boot or Quarkus (yes, it’s possible!)

  • To dip your toe into the world of Java + Maven with a real project

  • To find out how small you can go…. this produces a self-contained (“fat-jar”) application that’s quite small – less than 3MB! (well, that’s small by Java standards 😉)

What is Undertow?

Undertow is a web server written in Java.

Undertow is an embedded web server for Java.

Like most Java projects, it’s an open source, community-driven project. You can check it out on GitHub.

How do you use it?

To add Undertow into your Java application, you import it as a library. Then you can use its API (its classes and methods) to create, configure, and start a web server.

Some application frameworks like Spring Boot can configure and start Undertow for you. But, in this tutorial, we’re going to do it manually.

So let’s get started!

Create the Java app and add Undertow

We’ll add Undertow to a Java project, and use it to serve a simple HTML page.

You don’t need to download Undertow yourself, as Maven will pull it as a dependency in during the build.

So now let’s get started and set up the project!

What we’ll create

  • A standalone Java application (without a framework)

  • Containing an embedded web server, which returns some static HTML as a string

What you’ll need

To follow this tutorial, you will need these tools in your toolbox:

  • Java 11+: You’ll need to be running JDK 11. This example uses lambda expressions, which were a new feature in Java 8.

  • Apache Maven: We’ll use Maven to download dependencies and compile the code, so make sure that it’s installed and accessible on your path.

Overview of the project

This project we’ll create has just 2 files:

  • pom.xml

  • Application.java

Your project tree will look something like this when finished:

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

Set up pom.xml

Let’s start by creating and configuring a pom.xml in the root directory of the project.

This file tells Maven all of the dependencies that we need.

  1. In your Java IDE, create a new Java Maven Project. It should create your POM file (pom.xml) for you.

  2. In the <dependencies> section of your POM file, add the dependency io.undertow:undertow-core.

    The latest version of Undertow at the time of writing is 2.2.17.Final.

    <dependencies>
        <dependency>
            <groupId>io.undertow</groupId>
            <artifactId>undertow-core</artifactId>
            <version>2.2.17.Final</version>
        </dependency>
    </dependencies>
    

Set up Application.java

Next we need to add the main code.

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

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

Let’s look at what we need to do.

Import Undertow and create the server

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.simplehttp;

import io.undertow.Undertow;
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
                // 0.0.0.0 means "listen on ALL available addresses"
                .addHttpListener(8080, "0.0.0.0")

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

                    // Returns a hard-coded HTML document
                    exchange.getResponseSender()
                            .send("<html>" +
                                    "<body>" +
                                    "<h1>Hello, world!</h1>" +
                                    "</body>" +
                                    "</html>");
                }).build();

        // Boot the web server
        server.start();
    }
}

At this stage, the app is ready to run!

Run the app

We can now run the app with Maven:

mvn clean compile exec:java -Dexec.mainClass="com.tutorialworks.simplehttp.Application"

You can test the web server by going to http://localhost:8080 in your web browser.

Or, you can use a command line tool like curl to test it:

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

To quit, just press Ctrl+C.

But, it would be better if we could package this app into a JAR file which we can share! So let’s do that next.

Package the app as an executable JAR

The modern way of packaging Java applications is to put them inside an executable JAR file.

This means that anyone with the JRE installed can take the JAR file, and just run it with the java -jar command.

Configure Maven to build a JAR

In the POM file, configure Maven’s Assembly Plugin to produce the kind of package we want. We want to:

  • Build our fat JAR artifact (it’s actually called a “jar-with-dependencies”)

  • Specify our “main” class, so that the right method is called when the program starts.

To do this, add the following config inside the build section of your POM file:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                        <archive>
                            <manifest>
                                <mainClass>com.tutorialworks.hellorestjava.Application</mainClass>
                            </manifest>
                        </archive>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                        <appendAssemblyId>false</appendAssemblyId>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Now we’re ready to package and run.

Create the JAR and run it

Now, to compile the application and build the JAR file:

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/java-http-server-undertow-1.0-SNAPSHOT-jar-with-dependencies.jar 
-rw-r--r--. 1 tdonohue tdonohue 3.4M Apr  5 12:30 target/java-http-server-undertow-1.0-SNAPSHOT-jar-with-dependencies.jar

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

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

java -jar target/java-http-server-undertow-1.0-SNAPSHOT-jar-with-dependencies.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.

Summary

There you have it! We’ve created a simple Java application with an embedded web server, Undertow.

To grab the full code, click the button below:

Download the code on GitHub

What we’ve done:

  • Seen that Undertow can be used to create an embedded web server in a Java app

  • Created a standalone Java app with a main class, which creates and starts an instance of Undertow

  • Packaged the application into an executable JAR file

  • Tested the web server with curl, seeing the message returned!

Well done, and happy coding!