Ol
Application Servers Azure

Open Liberty on Ubuntu 24.04 on Azure User Guide

| Product: Open Liberty on Ubuntu 24.04 LTS on Azure

Overview

Open Liberty is IBM's open source Java application server, implementing Jakarta EE and MicroProfile. Its defining feature is that it is assembled from features rather than shipped as a monolith: a single server.xml declares which capabilities load, so the same runtime can be a lean servlet host or a full enterprise platform. Install the cloudimg image and you have a running Java application server with a browser admin UI, ready to accept your own WAR and EAR files.

The image installs Open Liberty 26.0.0.7 from the official distribution and runs it as the dedicated liberty system service under OpenJDK 21. The shipped feature set is Jakarta EE 10 Web Profile (webProfile-10.0), MicroProfile 6.1 (microProfile-6.1) and Admin Center (adminCenter-1.0). Every one of Open Liberty's features is already on disk, so you can change platform level by editing server.xml with no downloads and no internet access.

Open Liberty itself listens only on the loopback interface (127.0.0.1:9080 and 127.0.0.1:9443). nginx is the only public listener: it terminates HTTPS on port 443 and reverse proxies to Open Liberty, while port 80 carries just an unauthenticated /healthz probe and redirects everything else to HTTPS. Admin Center is a privileged interface and its login depends on a cookie that browsers only accept over HTTPS, so the console is never served in cleartext. A small Jakarta EE application ships pre-deployed at the root context so the server visibly works the moment it boots.

Three separate secrets are generated on the first boot of every VM: the administrator password, Open Liberty's own TLS keystore, and the browser facing certificate nginx serves. Open Liberty normally writes a default keystore the first time it starts; this image deliberately ships no keystore and no nginx certificate at all, so no two deployments share a private key. The single sign on (LTPA) signing keys are generated per VM for the same reason. Until first boot has produced those secrets the server refuses to start and no public listener opens. Backed by 24/7 cloudimg support.

What is included:

  • Open Liberty 26.0.0.7 installed from the official distribution (sha256 verified) and run as the liberty system service under OpenJDK 21
  • Jakarta EE 10 Web Profile, MicroProfile 6.1 and Admin Center enabled; all other Liberty features present on disk
  • A pre-deployed Jakarta EE application at the root context: a JSP page plus a /api/info JSON endpoint
  • MicroProfile Health at /health and MicroProfile OpenAPI with Swagger UI at /openapi/ui/
  • Open Liberty bound to loopback only, with nginx terminating HTTPS on port 443 as the single browser facing listener
  • An unauthenticated /healthz endpoint on port 80 for load balancer probes; all other port 80 traffic redirected to HTTPS
  • A unique admin password, a unique Open Liberty keystore, unique LTPA single sign on keys and a unique nginx TLS certificate, all generated on first boot and recorded in a root only file
  • An explicit JVM heap cap in jvm.options, sized for the recommended VM size
  • openliberty.service, nginx.service and open-liberty-firstboot.service as systemd units
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is the recommended size and is sufficient for the shipped configuration; size up for heavier applications and raise -Xmx to match. NSG inbound: allow 22/tcp from your management network, 443/tcp for the application and Admin Center, and 80/tcp if you want the load balancer health probe and the redirect to HTTPS. You do not need to open 9080 or 9443 — Open Liberty is not reachable on those ports from outside the VM by design.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Open Liberty by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22), HTTPS (443) and HTTP (80). Then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name openliberty \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name openliberty --port 443 --priority 1010
az vm open-port --resource-group <your-rg> --name openliberty --port 80  --priority 1020

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

First boot generates this VM's secrets, then starts Open Liberty and nginx. All three units should report active:

systemctl is-active openliberty.service nginx.service open-liberty-firstboot.service
active
active
active

open-liberty-firstboot.service is a oneshot unit that stays active after it has completed, so this output is what a healthy, fully bootstrapped VM looks like.

The three systemd units reporting active, the Open Liberty version banner naming release 26.0.0.7 on OpenJDK 21, and the listening sockets showing nginx on ports 443 and 80 with Open Liberty confined to loopback ports 9080 and 9443

Step 5 - Confirm the running release

The server reports the release it is actually running, not just what was unpacked:

sudo env WLP_USER_DIR=/var/lib/openliberty /opt/openliberty/wlp/bin/server version
Open Liberty 26.0.0.7 (1.0.115.cl260720260702-0043) on OpenJDK 64-Bit Server VM, version 21.0.11+10-1-24.04.2-Ubuntu (en)

Step 6 - Confirm the network shape

Open Liberty is bound to loopback only. nginx is the sole public listener:

sudo ss -ltn | grep -E ':(80|443|9080|9443)\b'
LISTEN 0 511          0.0.0.0:443 0.0.0.0:*
LISTEN 0 511           0.0.0.0:80 0.0.0.0:*
LISTEN 0 511 [::ffff:127.0.0.1]:9080      *:*
LISTEN 0 511             [::]:443    [::]:*
LISTEN 0 511 [::ffff:127.0.0.1]:9443      *:*
LISTEN 0 511              [::]:80    [::]:*

Ports 9080 and 9443 carry the 127.0.0.1 address, so they are unreachable from the network however your NSG is configured. Requests arrive on 443, nginx terminates TLS, and it forwards them to Open Liberty's HTTPS endpoint inside the VM.

Port 80 answers only the health probe and redirects everything else:

curl -s -o /dev/null -w 'GET :80 /healthz -> HTTP %{http_code}\n' http://127.0.0.1/healthz
curl -s -o /dev/null -w 'GET :80 /        -> HTTP %{http_code} %{redirect_url}\n' http://127.0.0.1/
GET :80 /healthz -> HTTP 200
GET :80 /        -> HTTP 301 https://127.0.0.1/

Admin Center's login form relies on a cookie that Open Liberty marks Secure, and browsers refuse to store such a cookie on an http:// origin, so signing in over cleartext cannot work. That is why the console is only served over HTTPS.

Step 7 - Retrieve your admin password

Every VM generates its own credentials into a root only file:

sudo sed -E 's/^(LIBERTY_ADMIN_PASSWORD|LIBERTY_KEYSTORE_PASSWORD|LIBERTY_LTPA_KEYS_SHA256)=.*/\1=<redacted-in-this-guide>/' /root/open-liberty-credentials.txt
# Open Liberty 26.0.0.7 — Per-VM Credentials
# Generated: Sun Jul 26 21:13:26 UTC 2026
#
# These values are unique to THIS virtual machine. The TLS keystore password below
# protects a keypair that was also generated on this VM's first boot, so no other
# deployment of this image shares its private key.
LIBERTY_ADMIN_USER=admin
LIBERTY_ADMIN_PASSWORD=<redacted-in-this-guide>
LIBERTY_KEYSTORE_PASSWORD=<redacted-in-this-guide>
LIBERTY_TLS_CERT_SHA256=ED:2C:C4:00:09:08:15:42:DD:CE:8A:58:DC:B1:28:74:47:5E:5A:84:8C:25:80:C9:A5:1B:5F:CF:4A:FC:EF:C7
LIBERTY_LTPA_KEYS_SHA256=<redacted-in-this-guide>
LIBERTY_NGINX_CERT_SHA256=CC:DF:51:47:04:0C:DD:5B:7E:F8:AE:86:8D:20:56:45:C6:8E:18:EE:0A:9F:84:95:F8:99:D7:58:7A:5F:FF:B1
LIBERTY_ADMIN_CENTER_URL=https://10.0.0.16/adminCenter/
LIBERTY_APP_URL=https://10.0.0.16/
LIBERTY_API_URL=https://10.0.0.16/api/info
LIBERTY_OPENAPI_URL=https://10.0.0.16/openapi/ui/
LIBERTY_HEALTH_URL=https://10.0.0.16/health
LIBERTY_LB_PROBE_URL=http://10.0.0.16/healthz

To print just the password:

sudo grep '^LIBERTY_ADMIN_PASSWORD=' /root/open-liberty-credentials.txt | cut -d= -f2-

The URLs are written using the address the VM could determine for itself. On Azure a Standard SKU public IP is not published through the instance metadata service, so the file records the VM's private address; browse to your VM's public IP instead. The file is 0600 root:root — copy the password into your password manager and it never needs to be read again.

The per-VM credentials file with the secret values masked, showing the admin user, the recorded fingerprints for the Open Liberty keystore, the LTPA keys and the nginx certificate, and the service URLs, alongside the 0600 root-only file mode

Step 8 - Confirm the endpoints respond

Four endpoints are reachable through nginx on port 443. -k is used because the certificate is this VM's own self signed one:

for p in / /api/info /health /openapi/ui/; do
  printf 'GET %-14s -> HTTP %s\n' "$p" \
    "$(curl -sk -o /dev/null -w '%{http_code}' -m 15 "https://127.0.0.1$p")"
done
GET /              -> HTTP 200
GET /api/info      -> HTTP 200
GET /health        -> HTTP 200
GET /openapi/ui/   -> HTTP 200

/healthz on port 80 is served by nginx itself and needs no authentication or TLS, which makes it the right target for an Azure Load Balancer or Application Gateway probe.

Step 9 - Query the pre-deployed application's REST endpoint

The shipped application exposes a Jakarta RESTful Web Services resource, serialised by Jakarta JSON Binding:

curl -sk https://127.0.0.1/api/info | python3 -m json.tool
{
    "availableProcessors": 2,
    "hostname": "openliberty",
    "jakartaEeProfile": "Jakarta EE 10 Web Profile (webProfile-10.0)",
    "javaVersion": "21.0.11",
    "libertyVersion": "26.0.0.7",
    "maxHeapMegabytes": 1024,
    "microProfileVersion": "MicroProfile 6.1 (microProfile-6.1)",
    "product": "Open Liberty on Ubuntu 24.04 LTS by cloudimg",
    "serverTimeUtc": "2026-07-26T21:13:47.053159649Z"
}

libertyVersion is read from the running installation, and maxHeapMegabytes confirms the explicit heap cap from jvm.options is in force.

Step 10 - Check MicroProfile Health

curl -sk https://127.0.0.1/health | python3 -m json.tool
{
    "status": "UP",
    "checks": []
}

checks is empty because the shipped application declares no health checks of its own. Add a @Liveness or @Readiness bean to your application and it appears here automatically.

The endpoints answering HTTP 200 through nginx over HTTPS, the /api/info JSON reporting Open Liberty 26.0.0.7 on Java 21 with the 1024 MB heap cap in force, and MicroProfile Health reporting status UP

Step 11 - Verify admin authentication from the command line

The management API shares the Admin Center login realm, so it is the quickest way to prove the credential works and that no default does. This reads the password from the credentials file, so it needs no editing:

sudo bash -c 'PW=$(grep "^LIBERTY_ADMIN_PASSWORD=" /root/open-liberty-credentials.txt | cut -d= -f2-)
A=https://127.0.0.1:9443/ibm/api/config
printf "correct password  -> HTTP %s\n" "$(curl -sk -o /dev/null -w "%{http_code}" -m 20 -u "admin:$PW"  $A)"
printf "wrong password    -> HTTP %s\n" "$(curl -sk -o /dev/null -w "%{http_code}" -m 20 -u "admin:wrong" $A)"
printf "empty password    -> HTTP %s\n" "$(curl -sk -o /dev/null -w "%{http_code}" -m 20 -u "admin:"      $A)"
printf "admin/admin       -> HTTP %s\n" "$(curl -sk -o /dev/null -w "%{http_code}" -m 20 -u "admin:admin" $A)"'
correct password  -> HTTP 200
wrong password    -> HTTP 401
empty password    -> HTTP 401
admin/admin       -> HTTP 401

The management API login round trip: the per-VM password authenticates with HTTP 200 while a wrong password, an empty password and the common admin/admin default are all rejected with HTTP 401, plus the browser facing certificate subject and fingerprint

Step 12 - Verify the TLS certificates are unique to this VM

There are two certificates, and both are generated on this VM at first boot. The one your browser sees is served by nginx on port 443:

echo | openssl s_client -connect 127.0.0.1:443 2>/dev/null \
  | openssl x509 -noout -subject -issuer -fingerprint -sha256
subject=O = cloudimg, CN = openliberty
issuer=O = cloudimg, CN = openliberty
sha256 Fingerprint=CC:DF:51:47:04:0C:DD:5B:7E:F8:AE:86:8D:20:56:45:C6:8E:18:EE:0A:9F:84:95:F8:99:D7:58:7A:5F:FF:B1

The second secures the internal hop from nginx to Open Liberty:

echo | openssl s_client -connect 127.0.0.1:9443 2>/dev/null \
  | openssl x509 -noout -subject -fingerprint -sha256
subject=OU = cloudimg, CN = localhost
sha256 Fingerprint=ED:2C:C4:00:09:08:15:42:DD:CE:8A:58:DC:B1:28:74:47:5E:5A:84:8C:25:80:C9:A5:1B:5F:CF:4A:FC:EF:C7

Both fingerprints match the values recorded in the credentials file in Step 7 — that is how you can confirm the key material belongs to this VM and was not baked into the image. None of it is present in the shipped image; all of it appears at first boot:

sudo ls -l /var/lib/openliberty/servers/cloudimg/resources/security/
sudo ls -l /etc/nginx/ssl/
-rw-r----- 1 liberty liberty 2698 Jul 26 21:13 key.p12
-rw------- 1 liberty liberty  897 Jul 26 21:13 ltpa.keys
-rw-r--r-- 1 root    root    1212 Jul 26 21:13 open-liberty.crt
-rw------- 1 root    root    1704 Jul 26 21:13 open-liberty.key

Both certificates are self signed, so your browser will warn on the first visit. Replace the nginx pair with your own trusted certificate for production (see Maintenance).

Step 13 - Sign in to Admin Center

Browse to https://<vm-public-ip>/adminCenter/ and sign in as admin with the password from Step 7. Accept the certificate warning, or install your own certificate first.

The Open Liberty Admin Center login page requesting a user name and password

Step 14 - Explore the Admin Center toolbox

After signing in, Admin Center presents its toolbox: Explore for the server, its applications and runtime, and Server Config for editing server.xml in the browser.

The Open Liberty Admin Center toolbox after signing in, showing the Explore, Server Config and openliberty.io tiles available to the administrator

Step 15 - View the pre-deployed application

Browse to https://<vm-public-ip>/. The page is rendered by the Jakarta Pages (JSP) container, so every value is computed per request — reload it and the server time changes.

The pre-deployed Jakarta EE application rendering live server state including the server time, hostname, servlet container version, Java runtime and request scheme, with links to the REST, OpenAPI, health and Admin Center endpoints

Step 16 - Browse the OpenAPI document

MicroProfile OpenAPI documents the deployed REST endpoints automatically. Browse to https://<vm-public-ip>/openapi/ui/ (the trailing slash matters) for the Swagger UI, from which you can call /api/info directly.

The MicroProfile OpenAPI Swagger UI listing the GET /api/info operation from the deployed application, with the schema of the JSON response

The raw document is available at /openapi:

curl -sk https://127.0.0.1/openapi | head -14
---
openapi: 3.0.3
info:
  title: Generated API
  version: "1.0"
servers:
- url: https://127.0.0.1
paths:
  /api/info:
    get:
      responses:
        "200":
          description: OK
          content:

Step 17 - Deploy your own application

Open Liberty watches dropins/ and deploys anything you copy in, with no restart and no configuration. Copy your WAR from your workstation and install it with the ownership the server expects:

scp myapp.war azureuser@<vm-public-ip>:/tmp/
ssh azureuser@<vm-public-ip> \
  'sudo install -o liberty -g liberty -m 0640 /tmp/myapp.war \
     /var/lib/openliberty/servers/cloudimg/dropins/myapp.war'

myapp.war is then served at https://<vm-public-ip>/myapp. Watch it deploy:

sudo tail -5 /var/lib/openliberty/servers/cloudimg/logs/messages.log

The pre-deployed demo application occupies the root context (/). To put your own application there instead, edit the <application> element in server.xml and change location to your WAR, or remove the element and name your file dropins/ROOT.war.

Step 18 - Change the feature set

Every Open Liberty feature is on disk, so changing platform level is a server.xml edit with no downloads. Edit /var/lib/openliberty/servers/cloudimg/server.xml:

<featureManager>
    <feature>jakartaee-11.0</feature>
    <feature>microProfile-7.1</feature>
    <feature>adminCenter-1.0</feature>
</featureManager>

jakartaee-10.0 gives the full Jakarta EE 10 Platform (adding Messaging, Batch, Connectors and Enterprise Beans) instead of the Web Profile, and jakartaee-11.0 with microProfile-7.1 moves to the newest platform level. Then restart, which is safe to run at any time:

sudo systemctl restart openliberty.service
for i in $(seq 1 60); do
  code=$(curl -sk -o /dev/null -w '%{http_code}' -m 5 https://127.0.0.1/ 2>/dev/null || true)
  [ "$code" = "200" ] && break
  sleep 2
done
curl -sk -o /dev/null -w 'after restart / -> HTTP %{http_code}\n' https://127.0.0.1/
systemctl is-active openliberty.service
after restart / -> HTTP 200
active

Step 19 - Confirm where state lives

Configuration, the deployed applications, the generated key material and the logs all live under one directory:

sudo ls /var/lib/openliberty/servers/cloudimg/
apps
bootstrap.properties
configDropins
dropins
jvm.options
logs
resources
server.xml
workarea

Back up /var/lib/openliberty to protect your applications, configuration and key material.

Maintenance

  • Password: the admin password is generated on first boot and stored in /root/open-liberty-credentials.txt. To change it, put your new value in the admin_password entry of /var/lib/openliberty/servers/cloudimg/bootstrap.properties and restart openliberty.service. The server refuses to start if that entry is empty or left at a placeholder, so a VM can never fall back to a known credential.
  • TLS and certificates: nginx terminates HTTPS with a self signed certificate generated on this VM at /etc/nginx/ssl/open-liberty.crt and .key. For production, point a DNS name at the VM, obtain a trusted certificate (for example with certbot and Let's Encrypt), and replace that pair — the /etc/nginx/sites-available/open-liberty server block is where the paths are set. Admin Center is a privileged interface: restrict port 443 to your management network in the NSG until you have a trusted certificate and are satisfied with your access controls.
  • Deploying applications: copy WAR or EAR files into /var/lib/openliberty/servers/cloudimg/dropins/ as liberty:liberty, or declare them explicitly with an <application> element in server.xml when you need a specific context root.
  • Features: the full Liberty feature repository is on disk, so server.xml changes never need network access. featureUtility is available if you want to add features from Maven Central later.
  • Heap sizing: jvm.options caps the heap at 1 GiB, which suits the recommended Standard_B2s. On a larger VM raise -Xmx and restart.
  • Logs: /var/lib/openliberty/servers/cloudimg/logs/messages.log is Open Liberty's own log; journalctl -u openliberty.service shows the console output, and journalctl -u open-liberty-firstboot.service shows what first boot did.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.