H2 Database Engine on Ubuntu 24.04 on Azure User Guide
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.servicesystemd 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-ifExistsso only existing databases may be opened -
h2-database-firstboot.servicesystemd oneshot that generates the per VM console,saand 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
/healthzfor load balancer probes -
An application database
appdbwith a small sampleCUSTOMERStable 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.

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>

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.

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.

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:

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:

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:

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

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.servicerunsorg.h2.tools.Serveras theh2user with-Dh2.bindAddress=127.0.0.1,-tcp -tcpPort 9092,-web -webPort 8082,-baseDir /var/lib/h2/dataand-ifExists. Both servers accept only local connections. -
h2-database-firstboot.serviceis a oneshot that generates the per VM secrets, createsappdbwith thesapassword, 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 to127.0.0.1:8082behind HTTP Basic Auth (/etc/nginx/.h2.htpasswd, bcrypt, useradmin). -
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
-webAllowOthersor-tcpAllowOtherstoh2.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.txtare unique to this VM. To rotate them, change thesapassword withALTER USER SA SET PASSWORD '...', update the nginx password withsudo 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.