Deployment guide

Open Liberty

Overview

Open Liberty is IBM's open source Java application server, implementing Jakarta EE and MicroProfile. 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.

The SecureAnyCloud image gives you 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 that 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. The image is backed by 24/7 SecureAnyCloud support.

What you get:

  • 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, with 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, with 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 SecureAnyCloud support

Prerequisites

Before you deploy this image, make sure you have:

  • An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region
  • A VM size of Standard_B2s (2 vCPU / 4 GiB RAM), which is recommended and sufficient for the shipped configuration. Size up for heavier applications and raise -Xmx to match
  • An NSG that allows inbound 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. By design, Open Liberty is not reachable on those ports from outside the VM.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Open Liberty by SecureAnyCloud, and select Create.

On the Basics tab, 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).

Select Review + create, then select Create.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:open-liberty-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name openliberty \
  --image sac1647283583153:open-liberty-ubuntu-24-04:default:latest \
  --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. Check that all three units 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 completes, so this output is what a healthy, fully bootstrapped VM looks like.

Step 5 - Confirm the running release

Ask the server which release it is running. The output reflects the running release, 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, and 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 nginx 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. 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. Read it with:

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 that 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 you never need to read the file again.

Step 8 - Confirm the endpoints respond

Four endpoints are reachable through nginx on port 443. The command uses -k 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

nginx itself serves /healthz on port 80, and it needs no authentication or TLS. This 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, serialized 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 sac", "serverTimeUtc": "2026-07-26T21:13:47.053159649Z" }

libertyVersion is read from the running installation, and maxHeapMegabytes confirms that 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. When you add a @Liveness or @Readiness bean to your application, it appears here automatically.

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 that your credential works and that no default credential does. The command 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

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. nginx serves the one that your browser sees 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 = sac, CN = openliberty issuer=O = sac, 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 certificate secures the hop from nginx to Open Liberty inside the VM:

echo | openssl s_client -connect 127.0.0.1:9443 2>/dev/null \
  | openssl x509 -noout -subject -fingerprint -sha256
subject=OU = sac, 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. This confirms that the key material belongs to this VM and was not baked into the image. None of it is present in the shipped image, and all of it appears at first boot:

sudo ls -l /var/lib/openliberty/servers/sac/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 warns you on the first visit. For production, replace the nginx pair with your own trusted certificate (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.

Step 14 - Explore the Admin Center toolbox

After you sign in, Admin Center shows its toolbox. Use Explore to inspect the server, its applications and runtime, and Server Config to edit server.xml in the browser.

Step 15 - View the pre-deployed application

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

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) to open the Swagger UI, where you can call /api/info directly.

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 that 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/sac/dropins/myapp.war'

The server then serves myapp.war at https://<vm-public-ip>/myapp. Watch it deploy:

sudo tail -5 /var/lib/openliberty/servers/sac/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. Alternatively, 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/sac/server.xml:

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

jakartaee-10.0 gives you the full Jakarta EE 10 Platform (adding Messaging, Batch, Connectors and Enterprise Beans) instead of the Web Profile. jakartaee-11.0 with microProfile-7.1 moves to the newest platform level.

Then restart the server. Restarting 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. List it with:

sudo ls /var/lib/openliberty/servers/sac/
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/sac/bootstrap.properties and restart openliberty.service. The server refuses to start if that entry is empty or left at a stand-in value, 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, so 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/sac/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/sac/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

SecureAnyCloud provides 24/7 expert support for this image. Contact sales@secureanycloud.com.

Deploy on Azure

Launch Open Liberty on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure