Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Packaging and deployment

In liberty:dev mode the server lives inside the target folder. For a production system the application has to be packaged into a file and deployed. There are two paths: hand a WAR to an already installed application server — the classic way — or package the application together with the server into one file or image, as is customary in the cloud.

The WAR file

./mvnw package

Maven builds target/blog.war. It holds only your code and resources — about 40 KB, because the implementations of all the specifications live in the server.

Inside the WARWhat it is
WEB-INF/classes/Compiled classes and META-INF/persistence.xml
WEB-INF/lib/Third-party libraries, if any
index.html, posts.xhtmlFiles from src/main/webapp

An installed server

On a separately installed Open Liberty there are two ways to deploy a WAR:

WayHow
The dropins folderCopy the WAR to usr/servers/defaultServer/dropins/ — the server picks it up by itself and takes the context root from the file name
server.xmlPut the WAR into apps/ and declare <webApplication contextRoot="/blog" location="blog.war" />

The second way is better: server.xml shows what is deployed and with which settings. The featureManager, the data source and the driver library from our src/main/liberty/config/server.xml move there too.

A runnable JAR

The Liberty plugin can package the server, the configuration and the application into one JAR:

./mvnw package liberty:create liberty:install-feature liberty:deploy liberty:package -Dinclude=runnable
[INFO] CWWKM2136I: Package file location is ...\blog\target\blog.jar.
[INFO] BUILD SUCCESS

This file runs on any machine with Java 21 or newer:

java -jar target/blog.jar
Launching defaultServer (Open Liberty 26.0.0.9/wlp-1.0.117.cl260920260824-0859) on OpenJDK 64-Bit Server VM, version 25.0.4.1+1-LTS
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://home-pc:8080/blog/
[AUDIT   ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 18.206 seconds.

The output is shortened. On start the JAR unpacks the server into a temporary folder and starts it. It contains only the enabled server features: for the blog the file is about 100 MB.

In liberty:dev mode the server takes the keystore passwords from a generated server.env file. In the runnable JAR login did not work for us: the log had CWWKS4118E: LTPA configuration error. A keysPassword attribute is not configured on the <ltpa /> element, and requests with a password got Error 403: AuthenticationFailed. If the application uses Jakarta Security, set the passwords explicitly in server.xml:

<!-- src/main/liberty/config/server.xml (fragment) -->
<keyStore id="defaultKeyStore" password="changeme" />
<ltpa keysPassword="changeme" />

In a production system replace changeme with an environment variable: password="${env.KEYSTORE_PASSWORD}".

Docker

The Open Liberty generator put a Dockerfile into the project:

FROM icr.io/appcafe/open-liberty:kernel-slim-java21-openj9-ubi-minimal
 
COPY --chown=1001:0 /src/main/liberty/config /config
 
RUN features.sh
 
COPY --chown=1001:0 target/*.war /config/apps
 
RUN configure.sh

The image takes a minimal Liberty, copies server.xml, installs the needed features and adds the WAR. The H2 driver also has to go into the image — into the folder that library in server.xml points to.

Other servers

A WAR is portable: the same file deploys to WildFly, Payara or GlassFish. Only the server's own configuration differs.

ServerWhere to put the WARWhere the data source is configured
Open Libertydropins/ or apps/server.xml
WildFlystandalone/deployments/standalone.xml or the CLI
Payara, GlassFishautodeploy/ or asadmin deployThe console or asadmin

The jdbc/blog name from persistence.xml has to be created on each server in its own way — the application code does not change.

Common mistake

Starting a second server instance while the first one (for example liberty:dev in another terminal) is still running. The application formally starts, but the port is taken, and the log gets:

[ERROR   ] CWWKO0221E: TCP Channel defaultHttpEndpoint initialization did not succeed.  The socket bind did not succeed for host * and port 8080.  The port might already be in use.  Exception Message: Address already in use: bind

Stop the first server (q in liberty:dev or ./mvnw liberty:stop) or set another httpPort in server.xml.

Thanks for reading!

Donate to the site — we work hard for you.