Deployment guide

Eclipse Jetty 12

Overview

Eclipse Jetty is a lightweight, embeddable Java HTTP server and Jakarta Servlet/JSP container. Teams choose it when Tomcat or WildFly are heavier than a workload needs, and it is a common embedded application server behind Java microservices.

This SecureAnyCloud image runs Eclipse Jetty 12 on Ubuntu 24.04 on Azure. It installs the official jetty-home 12.0.37 distribution (Jakarta EE10 / Servlet 6.0 environment) from Maven Central, pinned by exact version and verified against a sha256 checksum, and runs it on OpenJDK 21 (Jetty 12 requires Java 17+).

The image also ships a browsable web interface: a SecureAnyCloud-branded landing page at the server root, plus Jetty's own standard demo web applications pre-deployed. Point a browser at the VM and click through working examples: a Hello-World servlet, request/session/cookie dump servlets, WebSocket and Comet chat demos, and JSP/JSTL examples.

What you get:

  • Eclipse Jetty 12.0.37 (jetty-home distribution) from the official Maven Central release, sha256-pinned
  • OpenJDK 21 headless JRE (Jetty 12 requires Java 17+)
  • A jetty.service systemd unit that starts on boot and runs as the unprivileged jetty:jetty system user
  • An eclipse-jetty-firstboot.service systemd oneshot that starts Jetty and nginx and confirms the demo webapps answer before it completes
  • An HTTP connector bound to loopback only (127.0.0.1:8080), with nginx in front on :80
  • An unauthenticated /healthz endpoint (served by nginx, HTTP 200) for load balancer and probe checks
  • A root landing page at context / that renders a live server timestamp and request counter, which shows the JSP container executing on every request, and links to the demo apps
  • Jetty's own demo web applications pre-deployed: the flagship demo webapp at /ee10-test/ and the JSP/JSTL demo webapp at /ee10-demo-jsp/
  • JETTY_BASE=/var/lib/jetty on a dedicated 20 GiB Azure data disk, so webapps, logs and deployed application state survive independently of the OS disk
  • An Ubuntu 24.04 LTS base with the latest security patches applied at build time
  • The Azure Linux Agent for cloud integration and SSH key injection
  • 24/7 SecureAnyCloud support with a guaranteed 24-hour response SLA

Prerequisites

You need an active Azure subscription, an SSH public key, and a VNet with a subnet in the target region. You also need a subscription to the Eclipse Jetty 12 listing on Azure Marketplace.

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for development. Production Servlet workloads should use Standard_D4s_v5 (4 vCPU, 16 GB RAM) or larger.

1

Deploy from the Azure Portal

Search the Azure Marketplace for Eclipse Jetty 12, select the SecureAnyCloud publisher and click Create.

Add network security group (NSG) rules that allow these ports from your client networks: TCP 22 (admin), TCP 80 (HTTP) and TCP 443 (reserved for TLS).

2

Deploy from the Azure CLI

RG="jetty-prod"; LOCATION="eastus"; VM_NAME="jetty-01" IMAGE_URN="sac1647283583153:eclipse-jetty-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name jetty-vnet --address-prefix 10.100.0.0/16 --subnet-name jetty-subnet --subnet-prefix 10.100.1.0/24 az network nsg create -g "$RG" --name jetty-nsg az network nsg rule create -g "$RG" --nsg-name jetty-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name jetty-nsg --name allow-http --priority 110 \
  --destination-port-ranges 80 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name jetty-nsg --name allow-https --priority 120 \
  --destination-port-ranges 443 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:eclipse-jetty-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name jetty-vnet --subnet jetty-subnet --nsg jetty-nsg --public-ip-sku Standard
3

Connect via SSH

ssh azureuser@<vm-ip>

jetty.service, nginx.service and eclipse-jetty-firstboot.service all start automatically on first boot. There is no admin account to set up, because Jetty has no login of its own.

4

Verify the Jetty and nginx Services

sudo systemctl status jetty.service --no-pager sudo systemctl status nginx.service --no-pager sudo test -f /var/lib/sac/data/eclipse-jetty-firstboot.done && echo FIRSTBOOT_DONE
sudo ss -tln | grep -E ':(80|8080) '

Expected output:

● jetty.service - Eclipse Jetty Servlet Container Active: active (running) Main PID: 3661 (java) ...Started ServerConnector@...{HTTP/1.1, (http/1.1)}{127.0.0.1:8080} ● nginx.service - A high performance web server and a reverse proxy server Active: active (running) FIRSTBOOT_DONE LISTEN 0 511 0.0.0.0:80 0.0.0.0:* LISTEN 0 50 [::ffff:127.0.0.1]:8080 *:* LISTEN 0 511 [::]:80 [::]:*

The HTTP connector is bound to 127.0.0.1:8080 only. Jetty is never directly reachable from the network, and nginx on :80 is the only public entry point.

5

Check the Health Endpoint

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/healthz

Expected output: 200. nginx serves this unauthenticated endpoint directly and does not proxy it to Jetty, so it answers even under Servlet-container load. Use it for a load balancer or uptime probe.

6

Open the Jetty Landing Page in a Browser

Browse to the VM's public address, http://<vm-ip>/. The NSG must allow TCP 80.

The image serves a SecureAnyCloud-branded landing page that Jetty's JSP servlet container renders itself. The server timestamp and hit count are recomputed on every request, and the page links to Jetty's demo web applications.

You can confirm the per-request execution from the shell too. Request the root twice and watch both values change:

curl -s http://127.0.0.1/ | grep -oE '(Server time:|Hit count \(this JVM\):)</strong>[^<]*'
curl -s http://127.0.0.1/ | grep -oE '(Server time:|Hit count \(this JVM\):)</strong>[^<]*'

Expected output: the timestamp and hit count both change on every request.

Server time:</strong> 2026-07-09T19:58:11.578448807Z Hit count (this JVM):</strong> 1 Server time:</strong> 2026-07-09T19:58:12.031117662Z Hit count (this JVM):</strong> 2

This shows the Servlet/JSP container executing code on every request. A request-scoped counter and a live server timestamp cannot come from a cached or static file. That is the value a Servlet container adds over a plain web server such as nginx or Apache HTTPD on its own.

7

Explore Jetty's Demo Web Applications

The image pre-deploys Jetty's own standard demo webapps so you can see the container running real applications. Open them in a browser and click through the examples.

The flagship Jetty demo webapp is served at http://<vm-ip>/ee10-test/. It includes a Hello-World servlet, request/session/cookie dump servlets, async responses, a Comet long-polling chat and WebSocket examples. Confirm it responds:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/ee10-test/

Expected output: 200.

Click the Request dump servlet (/ee10-test/dump/info) to see Jetty inspect the live HTTP request: method, headers, scheme, session id and more, all produced by a running servlet.

The JSP & JSTL demo webapp at http://<vm-ip>/ee10-demo-jsp/ shows the JSP engine compiling and executing pages on the fly, with a JSP dump, JSTL iteration and expression-language examples. Confirm it responds:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/ee10-demo-jsp/

Expected output: 200.

8

Confirm the Jetty Version and Deployed Webapps

head -1 /opt/jetty/VERSION.txt ls -1 /var/lib/jetty/webapps/

Expected output:

12.0.37 - 27 June 2026 ee10-demo-jetty.d ee10-demo-jetty.war ee10-demo-jetty.xml ee10-demo-jsp.war root

The root directory maps to context path / (Jetty's convention, matching the demo-root module shipped in jetty-home itself); ee10-demo-jetty.war deploys at /ee10-test (see its ee10-demo-jetty.xml context descriptor) and ee10-demo-jsp.war at /ee10-demo-jsp.

9

Read the Endpoint Notes

On first boot, eclipse-jetty-firstboot.service writes a non-secret notes file that documents the deployed URLs. Jetty has no credentials to rotate. Read the file:

sudo cat /var/lib/sac/data/eclipse-jetty-endpoints.notes

Expected output:

# Eclipse Jetty — Endpoint Notes
# Generated on first boot by eclipse-jetty-firstboot.service
#
# Jetty has no admin UI or login — there is nothing to authenticate to.
# JETTY_DEMO_URL=http://<vm-ip>/ JETTY_DEMO_WEBAPP_URL=http://<vm-ip>/ee10-test/ JETTY_JSP_DEMO_URL=http://<vm-ip>/ee10-demo-jsp/ JETTY_HEALTHZ_URL=http://<vm-ip>/healthz JETTY_HOME=/opt/jetty JETTY_BASE=/var/lib/jetty DEPLOY_YOUR_OWN_WAR=Drop a .war file into /var/lib/jetty/webapps/ — Jetty hot-deploys it.
10

Deploy Your Own WAR

Jetty's ee10-deploy module watches $JETTY_BASE/webapps/ and hot-deploys any WAR file you drop into it, with no restart required:

# Build your WAR (locally) mvn package -DskipTests
# Copy to the VM scp target/myapp.war azureuser@<vm-ip>:/tmp/
# Deploy (hot-deploy, no restart needed)
ssh azureuser@<vm-ip> 'sudo mv /tmp/myapp.war /var/lib/jetty/webapps/'
# Jetty auto-detects and deploys within a few seconds; visit:
# http://<vm-ip>/myapp/

To deploy at context path / instead, replacing the demo landing page, remove /var/lib/jetty/webapps/root/ first. Then drop in a WAR or exploded directory named root.

When you no longer need the demo webapps, remove ee10-demo-jetty* and ee10-demo-jsp.war from /var/lib/jetty/webapps/.

11

Server Components

Component Path

JETTY_HOME (binaries, immutable) /opt/jetty

JETTY_BASE (data disk) /var/lib/jetty

Webapps /var/lib/jetty/webapps/

Root landing webapp /var/lib/jetty/webapps/root/index.jsp

Jetty demo webapp (/ee10-test) /var/lib/jetty/webapps/ee10-demo-jetty.war

JSP demo webapp (/ee10-demo-jsp) /var/lib/jetty/webapps/ee10-demo-jsp.war

Start modules /var/lib/jetty/start.d/

Logs systemd journal (journalctl -u jetty.service); /var/lib/jetty/logs/ if the requestlog module is enabled

Systemd unit /etc/systemd/system/jetty.service

Firstboot script /usr/local/sbin/eclipse-jetty-firstboot.sh

Firstboot service /etc/systemd/system/eclipse-jetty-firstboot.service

Endpoint notes /var/lib/sac/data/eclipse-jetty-endpoints.notes (mode 0644)

Firstboot sentinel /var/lib/sac/data/eclipse-jetty-firstboot.done

nginx vhost /etc/nginx/sites-available/sac-jetty

12

Managing the Jetty Service

sudo systemctl status jetty.service --no-pager sudo systemctl restart jetty.service
sudo journalctl -u jetty.service -n 50 --no-pager

By default, Jetty's stdout and stderr go to the systemd journal (journalctl -u jetty.service), not to a file under $JETTY_BASE/logs/. Run sudo journalctl -u jetty.service -f to follow the log live.

To also write a request/access log to a file, enable Jetty's requestlog module from /var/lib/jetty with sudo -u jetty java -jar /opt/jetty/start.jar --add-modules=requestlog. It writes to $JETTY_BASE/logs/.

Enabling additional Jetty modules (WebSocket, HTTP/2, SSL termination at Jetty itself and others) takes a single --add-modules command from $JETTY_BASE:

cd /var/lib/jetty
sudo -u jetty java -jar /opt/jetty/start.jar --add-modules=http2c sudo systemctl restart jetty.service
13

Security Recommendations

  • Never expose port 8080 directly. It is bound to loopback only by design. Always go through nginx (:80) or add a TLS-terminating reverse proxy on :443.
  • Add TLS. Front nginx with Let's Encrypt/Certbot, or terminate TLS in Jetty itself with the ssl module and a certificate on the data disk.
  • Remove the demo webapps if you do not need them. Delete ee10-demo-jetty* and ee10-demo-jsp.war from /var/lib/jetty/webapps/. The bundled Jetty demo login realm is used only by the demo webapp's protected example pages and grants no OS access, but a lean production image should carry only your own application.

Deploy on Azure

Launch Eclipse Jetty 12 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