Databases Azure

H2 Database Engine on Ubuntu 24.04 on Azure User Guide

| Product: H2 Database Engine on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of H2 Database Engine on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. H2 is a fast, compact relational database written entirely in Java. This image runs it as a server: one JVM (org.h2.tools.Server) exposes an H2 TCP server for JDBC clients and the built in H2 Web Console for interactive SQL. H2 is dual licensed under the Mozilla Public License 2.0 or the Eclipse Public License 1.0.

The image installs the official h2-2.4.240.jar (pinned and sha256 verified) from Maven Central and runs it as the unprivileged h2 system user. Both the TCP server and the Web Console bind to loopback only and are never exposed directly to the network. nginx on port 80 fronts the console with HTTP Basic Auth, and at first boot h2-database-firstboot.service generates three unique per VM secrets, the nginx console password, the H2 sa database password, and the console web admin password, creates the application database, proves the whole gate, and writes the secrets to /root/h2-database-credentials.txt (mode 0600, root only). There is no default or blank login baked into the image.

What is included:

  • H2 Database Engine 2.4.240 (official h2-2.4.240.jar, pinned and sha256 verified from Maven Central)

  • h2.service systemd unit running one JVM with the H2 TCP server (127.0.0.1:9092) and Web Console (127.0.0.1:8082), bound to loopback with a hardened service sandbox and -ifExists so only existing databases may be opened

  • h2-database-firstboot.service systemd oneshot that generates the per VM console, sa and web admin passwords, creates the application database, proves the authentication gate and a full SQL round trip, and writes /root/h2-database-credentials.txt

  • nginx on port 80 reverse proxying to the loopback bound Web Console, with HTTP Basic Auth and an unauthenticated /healthz for load balancer probes

  • An application database appdb with a small sample CUSTOMERS table so the console has content to explore on first boot

  • Ubuntu 24.04 LTS base with the latest security patches

  • Azure Linux Agent for seamless cloud integration and SSH key injection

  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • An active Azure subscription, an SSH public key, and a VNet plus subnet in the target region

  • A subscription to the H2 Database Engine on Ubuntu 24.04 listing on Azure Marketplace

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for evaluation, development and test workloads. For heavier use, raise the JVM heap in /etc/systemd/system/h2.service and choose Standard_D2s_v5 or larger.

Step 1: Deploy from the Azure Portal

Search H2 Database in Marketplace, select the cloudimg publisher entry, then click Create.

NSG rules: allow TCP 22 from your management IP and TCP 80 from your client IPs. The H2 TCP server and Web Console are bound to loopback, so only nginx on port 80 is exposed. The console is protected by HTTP Basic Auth, but for any deployment beyond a private network put a TLS terminating reverse proxy in front of port 80 so credentials and SQL are encrypted in transit.

Step 2: Deploy from the Azure CLI

RG="h2-prod"; LOCATION="eastus"; VM_NAME="h2-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/h2-database/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name h2-vnet --address-prefix 10.90.0.0/16 --subnet-name h2-subnet --subnet-prefix 10.90.1.0/24
az network nsg create -g "$RG" --name h2-nsg
az network nsg rule create -g "$RG" --nsg-name h2-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 h2-nsg --name allow-http --priority 110 \
  --source-address-prefixes "<your-client-cidr>" --destination-port-ranges 80 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name h2-vnet --subnet h2-subnet --nsg h2-nsg --public-ip-sku Standard

Step 3: Connect via SSH

ssh azureuser@<vm-ip>

The default administrator account is azureuser, authenticated with the SSH key you supplied at deployment.

Step 4: Verify the H2 Service

Confirm that H2 and nginx are running:

systemctl is-active h2 nginx

Both units report active. h2.service runs the single JVM that hosts the TCP server and the Web Console; nginx fronts the console on port 80.

H2 and nginx services both reporting active, and the ss listener table showing nginx bound to port 80 while the H2 console and TCP server are bound to loopback 127.0.0.1 on ports 8082 and 9092

Step 5: Inspect the Listeners

Confirm that nginx owns the public port while H2 stays on loopback:

sudo ss -tlnp | grep -E ':80 |:8082 |:9092 '

nginx listens on 0.0.0.0:80, while the H2 Web Console (8082) and TCP server (9092) listen on 127.0.0.1 only. They are unreachable from the network except through the authenticated nginx front.

Step 6: Retrieve the Credentials

The per VM secrets are generated at first boot and stored in a root only file:

sudo cat /root/h2-database-credentials.txt

You will see the console sign in user and password, the JDBC URL with the sa database user and password, and the console web admin password:

H2_CONSOLE_URL=http://<vm-ip>/
H2_CONSOLE_USERNAME=admin
H2_CONSOLE_PASSWORD=<H2_CONSOLE_PASSWORD>
H2_JDBC_URL=jdbc:h2:tcp://localhost:9092/appdb
H2_DB_USER=sa
H2_DB_PASSWORD=<H2_DB_PASSWORD>
H2_WEB_ADMIN_PASSWORD=<H2_WEB_ADMIN_PASSWORD>

The per VM H2 credentials file at /root/h2-database-credentials.txt shown with sudo cat, the passwords redacted, listing the console URL and user, the JDBC URL, the sa database user, and the console web admin entry

Step 7: Verify Access Control over HTTP

The console is reached only through the authenticated nginx proxy, and the database rejects a blank sa password. Confirm all three:

CP=$(sudo grep '^H2_CONSOLE_PASSWORD=' /root/h2-database-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'no creds: %{http_code}\n' http://127.0.0.1/
curl -s -o /dev/null -w 'with console password: %{http_code}\n' -u "admin:$CP" http://127.0.0.1/
JAR=$(ls /opt/h2/h2-*.jar)
java -cp "$JAR" org.h2.tools.Shell -url jdbc:h2:tcp://localhost:9092/appdb -user sa -password '' -sql 'SELECT 1' 2>&1 | grep -m1 -o 'Wrong user name or password.*' || true

The unauthenticated request returns 401, the authenticated console returns 200, and the blank sa password is rejected with Wrong user name or password [28000-240]. The unauthenticated /healthz endpoint stays open for load balancer probes.

Access control proof over HTTP: an unauthenticated request returning HTTP 401, an authenticated console request returning HTTP 200, and a blank sa database password rejected with error 28000 Wrong user name or password

Step 8: Query the Database from the Command Line

Use the bundled H2 Shell tool with the per VM sa password to query the sample table:

DBPW=$(sudo grep '^H2_DB_PASSWORD=' /root/h2-database-credentials.txt | cut -d= -f2-)
JAR=$(ls /opt/h2/h2-*.jar)
java -cp "$JAR" org.h2.tools.Shell -url jdbc:h2:tcp://localhost:9092/appdb -user sa -password "$DBPW" \
  -sql 'SELECT ID, NAME, EMAIL FROM CUSTOMERS ORDER BY ID;'

The sample CUSTOMERS table returns three rows. This same JDBC URL and sa password connect any application running on the VM.

The H2 Shell command line tool connected over the loopback TCP server running SELECT ID, NAME, EMAIL FROM CUSTOMERS ORDER BY ID and returning three rows for Ada Lovelace, Alan Turing and Grace Hopper

Step 9: Open the H2 Web Console

Open http://<vm-ip>/ from your workstation (assuming the NSG allows TCP 80). Your browser prompts for HTTP Basic Auth: sign in with user admin and the H2_CONSOLE_PASSWORD from the credentials file. The H2 login form appears. Enter the JDBC URL jdbc:h2:tcp://localhost:9092/appdb, the user sa, and the H2_DB_PASSWORD, then click Connect:

The H2 Web Console login form served through nginx after HTTP Basic Auth, with the Driver Class org.h2.Driver, the JDBC URL jdbc:h2:tcp://localhost:9092/appdb, the user name sa and a masked password filled in, and the Connect and Test Connection buttons

Step 10: Explore the Console

Once connected, the console shows the schema tree on the left (the appdb database, the CUSTOMERS table, INFORMATION_SCHEMA and Users) and the SQL editor on the right, with the H2 version and helpful sample commands:

The connected H2 Web Console showing the schema tree on the left with the appdb database, the CUSTOMERS table, INFORMATION_SCHEMA and Users, the SQL editor toolbar with Run, and the H2 2.4.240 version, plus the Important Commands and Sample SQL Script help panels

Step 11: Run a Query

Type a SQL statement into the editor and press Run (or Ctrl+Enter). The result grid appears below the editor:

The H2 Web Console running SELECT star FROM CUSTOMERS with the result grid below showing the ID, NAME, EMAIL and SIGNED_UP columns and three rows for Ada Lovelace, Alan Turing and Grace Hopper, with a three rows result summary

Step 12: Explore the Schema

Expand a table in the schema tree to inspect its columns and types without writing any SQL:

The H2 Web Console schema tree with the CUSTOMERS table expanded to show its ID, NAME, EMAIL and SIGNED_UP columns and its Indexes node, alongside the INFORMATION_SCHEMA and Users entries

Step 13: Connect Your Application over JDBC

The H2 TCP server is bound to loopback for safety. An application running on the same VM connects directly with the JDBC URL jdbc:h2:tcp://localhost:9092/appdb, the user sa, and the per VM password. To reach the database from your workstation, forward the port over SSH rather than exposing it:

ssh -L 9092:127.0.0.1:9092 azureuser@<vm-ip>

Then point a local JDBC client at jdbc:h2:tcp://localhost:9092/appdb. For a production application tier, open TCP 9092 in the NSG restricted to your application subnets only, and prefer a TLS terminator in front of the console on port 443.

Step 14: Server Components

  • h2.service runs org.h2.tools.Server as the h2 user with -Dh2.bindAddress=127.0.0.1, -tcp -tcpPort 9092, -web -webPort 8082, -baseDir /var/lib/h2/data and -ifExists. Both servers accept only local connections.

  • h2-database-firstboot.service is a oneshot that generates the per VM secrets, creates appdb with the sa password, sets the console web admin password in /var/lib/h2/.h2.server.properties, seeds the nginx Basic Auth file, and proves the gate before writing the sentinel /var/lib/cloudimg/h2-database-firstboot.done.

  • nginx listens on port 80, serves an unauthenticated /healthz, and reverse proxies everything else to 127.0.0.1:8082 behind HTTP Basic Auth (/etc/nginx/.h2.htpasswd, bcrypt, user admin).

  • The database files live in /var/lib/h2/data.

Step 15: Managing the Service

systemctl status h2
sudo systemctl restart h2
sudo journalctl -u h2 -n 50 --no-pager

To change the JVM heap, edit ExecStart in /etc/systemd/system/h2.service, then sudo systemctl daemon-reload && sudo systemctl restart h2.

Step 16: Security Recommendations

  • Keep the servers on loopback. Do not add -webAllowOthers or -tcpAllowOthers to h2.service. The Web Console can connect to arbitrary JDBC URLs and read files, so it must never be exposed to the network directly. nginx plus the per VM Basic Auth password is the only front door.

  • Add TLS. Put a TLS terminating reverse proxy (or nginx with a certificate) in front of port 80 on 443 so the console password and SQL are encrypted in transit.

  • Restrict the NSG. Allow TCP 22 and TCP 80 only from the addresses that need them, and open TCP 9092 only to your application subnets if you must reach JDBC off the VM.

  • Rotate secrets. The per VM passwords in /root/h2-database-credentials.txt are unique to this VM. To rotate them, change the sa password with ALTER USER SA SET PASSWORD '...', update the nginx password with sudo htpasswd -B /etc/nginx/.h2.htpasswd admin, and reset the console web admin password from the console Preferences page.

Step 17: Support and Licensing

H2 Database Engine is dual licensed under the Mozilla Public License 2.0 or the Eclipse Public License 1.0. This image bundles the unmodified official h2-2.4.240.jar from Maven Central. cloudimg provides the packaging, hardening and first boot automation, plus 24/7 support with a guaranteed 24 hour response SLA. This listing is not affiliated with or endorsed by the H2 project.

Deploy on Azure

Find H2 Database Engine on Ubuntu 24.04 LTS on the Azure Marketplace by cloudimg, or visit www.cloudimg.co.uk for the full catalogue.

Need Help?

Email support@cloudimg.co.uk for deployment help, JDBC integration questions, or anything else. cloudimg support responds within 24 hours.