Deployment guide

Apache HBase

Overview

Apache HBase is a wide-column NoSQL database modeled on Google's Bigtable. Rows are sorted by row key, cells are grouped into column families, and every cell is versioned by timestamp. Tables split into regions that a cluster spreads across RegionServers. You use HBase through the HBase shell, the Java client API or the REST and Thrift gateways.

This guide covers deploying and using Apache HBase 2.5.16 on Ubuntu 24.04 LTS from SecureAnyCloud on Microsoft Azure. The image runs HBase in standalone mode: the HMaster, one RegionServer and an embedded ZooKeeper run together in one Java process on one VM, storing data on the local file system. That is a complete HBase for development, testing, prototyping and single-node workloads, without a Hadoop or HDFS cluster.

HBase has no authentication of its own unless you set up Kerberos, so an upstream install exposes its ports and web pages to anyone who can reach them. The SecureAnyCloud image changes that.

What you get:

  • HBase on localhost only. ZooKeeper (2181), the Master (RPC 16000, web UI 16010) and the RegionServer (RPC 16020, web UI 16030) are bound to 127.0.0.1 and are never reachable from the network. Never open those ports in a network security group (NSG).
  • HTTPS from the first boot for the status UI. nginx is the only network entry point. It publishes the HBase Master status UI on port 443 with a certificate generated on your VM's first boot. Port 80 only redirects to HTTPS, so no password ever crosses the network in clear text.
  • A password unique to your VM. Every page except a static /healthz needs HTTP Basic Auth as the user admin. The password is generated on first boot and written to the root-only file /root/hbase-credentials.txt. nginx stores only its bcrypt hash, and the password is never passed on a command line. No password is baked into the image and no two VMs share one.
  • A read-only status UI. The table pages show no compact, split or merge actions, and the runtime log level setter and the profiler are refused (HTTP 403) even when you are signed in.
  • Fail closed. nginx refuses to start until first boot has written the certificate and the password, so the UI is never served without a login.
  • A sandboxed, unprivileged HBase. HBase runs as its own hbase user with no capabilities, a read-only system and private temporary files. Neither HBase nor nginx can reach the Azure instance metadata service or the Azure wire server.
  • Your data on its own disk. Tables, the write-ahead log and ZooKeeper data live on a dedicated 40 GiB Azure data disk mounted at /var/lib/hbase, which you can resize independently of the OS disk.
  • Fixed host name and real client addresses. Requests for a host name the VM does not serve are dropped. nginx logs the real client address (client-supplied X-Forwarded-For headers are overwritten), and cross-site browser requests that change state are refused.
  • Verified download. The Apache release was checked against Apache's published SHA-512 checksum and its OpenPGP signature from the Apache HBase release manager's key. The image uses the Hadoop 3 build of HBase 2.5.16 (Hadoop 3.4.3 client libraries).
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: Apache HBase 2.5.16 (/opt/hbase, the Hadoop 3 build, Apache-2.0), Ubuntu's OpenJDK 11 runtime, nginx, Ubuntu 24.04 LTS, cloud-init and the Azure Linux agent.

Default user: azureuser (or the administrator name you choose). Recommended size: Standard_B4ms (4 vCPU, 16 GiB).

Prerequisites

  • An Azure subscription, an SSH key pair (or a password) for the administrator account, and a virtual network in the target region.
  • An NSG that allows TCP 22 (SSH) from your own networks and TCP 443 (the status UI) from the networks you will browse from. TCP 80 only redirects to HTTPS and is optional. Do not open 2181 or 16000 to 16030.
1

Deploy the VM

In the Azure portal, choose Create a resource, search the Marketplace for Apache HBase by SecureAnyCloud, and select Create.

On Basics, pick your subscription, resource group, region and Standard_B4ms. Under Administrator account, choose SSH public key (or password). Under Inbound port rules, allow SSH (22) and HTTPS (443). The Disks tab shows the image's dedicated 40 GiB data disk for HBase. Then choose Review + create.

To deploy with the Azure CLI instead, run these commands on your workstation and replace the values in angle brackets:

az vm image terms accept --urn sac1647283583153:apache-hbase-ubuntu-24-04:default:latest
az vm create --resource-group <your-rg> --name hbase \
  --image sac1647283583153:apache-hbase-ubuntu-24-04:default:latest \
  --size Standard_B4ms --admin-username azureuser --ssh-key-values ~/.ssh/id_ed25519.pub \
  --public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name hbase --port 443 --priority 1010
2

Connect to your VM

Connect over SSH:

ssh azureuser@<vm-public-ip>
3

Check the services

First boot generates the certificate and the password, then nginx starts. HBase starts on its own and is ready about half a minute after boot. Check the services:

systemctl is-active hbase nginx apache-hbase-firstboot
sudo test -f /var/lib/sac/data/apache-hbase-firstboot.done && echo FIRSTBOOT_DONE /opt/hbase/bin/hbase version 2>/dev/null | head -1 java -version 2>&1 | head -1
active active active FIRSTBOOT_DONE HBase 2.5.16-hadoop3 openjdk version "11.0.32.1" 2026-08-18

Only SSH and nginx listen on public addresses. Every HBase port is on loopback. List the listening ports:

sudo ss -Hlntp | awk '{print $4, $6}' | grep -v '127.0.0.5' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort
0.0.0.0:22 users:(("sshd"),("systemd")) 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) 127.0.0.1:16000 users:(("java")) 127.0.0.1:16010 users:(("java")) 127.0.0.1:16020 users:(("java")) 127.0.0.1:16030 users:(("java")) 127.0.0.1:2181 users:(("java")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx"))
4

Use the HBase shell

The HBase shell is on every login's PATH, so after you connect you can type hbase shell for an interactive session. It talks to HBase over loopback, so it works for any user logged in to the VM.

The example below creates a table with one column family and writes two rows. It then reads the rows back with scan, get and count. The -n flag runs the commands non-interactively:

/opt/hbase/bin/hbase shell -n <<'EOF' 2>&1 | grep -v '^Took ' create 'guide_users', 'info' put 'guide_users', 'user1', 'info:name', 'Ada Lovelace' put 'guide_users', 'user1', 'info:city', 'London' put 'guide_users', 'user2', 'info:name', 'Alan Turing' put 'guide_users', 'user2', 'info:city', 'Manchester' scan 'guide_users' get 'guide_users', 'user2', 'info:city' count 'guide_users' EOF
hbase:001:0> create 'guide_users', 'info' Created table guide_users => Hbase::Table - guide_users hbase:002:0> put 'guide_users', 'user1', 'info:name', 'Ada Lovelace' hbase:003:0> put 'guide_users', 'user1', 'info:city', 'London' hbase:004:0> put 'guide_users', 'user2', 'info:name', 'Alan Turing' hbase:005:0> put 'guide_users', 'user2', 'info:city', 'Manchester' hbase:006:0> scan 'guide_users' ROW COLUMN+CELL user1 column=info:city, timestamp=2026-10-23T11:26:38.014, value=London user1 column=info:name, timestamp=2026-10-23T11:26:37.967, value=Ada Lovelace user2 column=info:city, timestamp=2026-10-23T11:26:38.070, value=Manchester user2 column=info:name, timestamp=2026-10-23T11:26:38.042, value=Alan Turing 2 row(s) hbase:007:0> get 'guide_users', 'user2', 'info:city' COLUMN CELL info:city timestamp=2026-10-23T11:26:38.070, value=Manchester 1 row(s) hbase:008:0> count 'guide_users' 2 row(s) => 2 hbase:009:0>

Rows come back sorted by row key, and each cell shows its column (family:qualifier), its timestamp and its value. Leave the table in place for now so that you can see it in the web UI (Step 6). Remove it at the end of this guide.

5

Get your URL and password

The URL and the user name are in the root-only credentials file:

sudo grep -E '^HBASE_(UI_URL|ADMIN_USER)=' /root/hbase-credentials.txt
HBASE_UI_URL=https://<vm-public-ip>/master.jsp HBASE_ADMIN_USER=admin

The password is the HBASE_ADMIN_PASSWORD line of the same file: sudo grep '^HBASE_ADMIN_PASSWORD=' /root/hbase-credentials.txt. Store it in your password manager. It is unique to this VM.

The URL uses the VM's public IP address from the Azure instance metadata service, or its private IP address when the VM has no public one. The certificate names that address plus the VM's private address and loopback. Inspect the certificate:

openssl x509 -in /etc/ssl/hbase/hbase.crt -noout -subject -ext subjectAltName -enddate
subject=CN = <vm-public-ip>, O = sac X509v3 Subject Alternative Name: IP Address:<vm-public-ip>, IP Address:<vm-private-ip>, IP Address:127.0.0.1, DNS:localhost notAfter=<date about 27 months after first boot>

Without the password, every page is refused. A wrong password is refused, the log level setter is refused even with the password, and port 80 redirects to HTTPS.

The commands below read the password from the credentials file into a shell variable and pass it to curl through a file descriptor, so it never appears in the process list or your shell history:

H=$(sudo sed -n 's#^HBASE_UI_URL=https://\([^/]*\)/.*#\1#p' /root/hbase-credentials.txt)
PW=$(sudo sed -n 's/^HBASE_ADMIN_PASSWORD=//p' /root/hbase-credentials.txt) CA=/etc/ssl/hbase/hbase.crt curl -s -o /dev/null -w 'http:// -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/master.jsp" curl -s -o /dev/null -w 'no login -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" "https://$H/master.jsp" curl -s -o /dev/null -w 'wrong password -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -u admin:not-the-password "https://$H/master.jsp" curl -s -o /dev/null -w 'admin + password -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") "https://$H/master.jsp" curl -s -o /dev/null -w 'log level setter (signed in) -> HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") "https://$H/logLevel" curl -s -w ' <- /healthz (no login) HTTP %{http_code}\n' --cacert $CA --resolve "$H:443:127.0.0.1" "https://$H/healthz"
http:// -> 301 https://<vm-public-ip>/master.jsp no login -> HTTP 401 wrong password -> HTTP 401 admin + password -> HTTP 200 log level setter (signed in) -> HTTP 403 ok <- /healthz (no login) HTTP 200

--resolve sends the request to this VM while keeping the real host name, so the certificate check passes. From another machine, drop --resolve and use the URL directly.

6

Browse the Master status UI

Open the HBASE_UI_URL from Step 5 (https://<vm-public-ip>/master.jsp) in a browser. The certificate is self-signed, so the browser warns once. Accept it, or install your own certificate (Step 9). Sign in as admin with the password from the credentials file.

The home page shows the active Master, the RegionServer with its request rate and region count, and your tables:

Select a table name (or Table Details) to see its attributes and the settings of each column family: Bloom filter, versions kept, time to live, compression and block size. The page is read-only on this image:

Table Details lists every user table with its full descriptor:

The Debug Dump menu and the ZooKeeper page (/zk.jsp) show what HBase keeps in its embedded ZooKeeper: the active master, the server holding hbase:meta, the RegionServers and the client connections, all on localhost:

The Log Level and Profiler menu entries are refused on this image (HTTP 403), so nobody can change HBase's logging or start a profiler from a browser.

The RegionServer's own status page (port 16030) is not published. If you need it, reach it through an SSH tunnel (ssh -L 16030:127.0.0.1:16030 ...).

7

Connect applications

HBase in standalone mode is meant to be used from the VM itself. Run your application, the HBase shell or hbase tools here, and point the client at ZooKeeper on localhost:2181. This is the default in /opt/hbase/conf/hbase-site.xml, so a client that reads that file needs no extra settings.

The Java client needs the HBase client libraries (/opt/hbase/lib, or the hbase-shaded-client 2.5.16 artifact from Maven Central) and this configuration:

Configuration conf = HBaseConfiguration.create(); conf.set("hbase.zookeeper.quorum", "localhost"); conf.set("hbase.zookeeper.property.clientPort", "2181"); try (Connection connection = ConnectionFactory.createConnection(conf); Table table = connection.getTable(TableName.valueOf("guide_users"))) { Result r = table.get(new Get(Bytes.toBytes("user1"))); System.out.println(Bytes.toString(r.getValue(Bytes.toBytes("info"), Bytes.toBytes("name")))); }

To connect from a workstation, forward the three client ports over SSH and run the client against localhost. The Master and RegionServer advertise themselves as localhost, so the tunnel carries all the traffic:

ssh -N -L 2181:127.0.0.1:2181 -L 16000:127.0.0.1:16000 -L 16020:127.0.0.1:16020 azureuser@<vm-public-ip>

Never open 2181 or 16000 to 16030 in an NSG. HBase has no authentication of its own, so anyone who can reach those ports can read, change and delete every table.

For several application servers or a multi-node cluster, run HBase in distributed mode on HDFS with Kerberos authentication, as described in the Apache HBase reference guide.

8

Storage, memory and logs

HBase keeps its data (hbase.rootdir), its write-ahead log and the ZooKeeper data on the dedicated Azure data disk mounted at /var/lib/hbase, and runs with a 2 GB Java heap:

df -h /var/lib/hbase | tail -1 | awk '{print $2" total, "$4" free on "$6}' grep -oE '<name>hbase\.(rootdir|wal\.dir|zookeeper\.property\.dataDir)</name><value>[^<]*' /opt/hbase/conf/hbase-site.xml | sed 's#</name><value># = #; s#<name>##' grep -E '^export HBASE_HEAPSIZE' /opt/hbase/conf/hbase-env.sh
40G total, 38G free on /var/lib/hbase hbase.rootdir = file:///var/lib/hbase/data hbase.wal.dir = file:///var/lib/hbase/wal hbase.zookeeper.property.dataDir = /var/lib/hbase/zookeeper export HBASE_HEAPSIZE=2G
  • Heap. On a larger VM, raise HBASE_HEAPSIZE in /opt/hbase/conf/hbase-env.sh. About half of the VM's memory is a good start. Then run sudo systemctl restart hbase.
  • Disk. To grow the data disk, stop (deallocate) the VM and increase the disk size in the portal (Disks, select the data disk, Size + performance). Then start the VM and extend the file system: sudo resize2fs "$(findmnt -no SOURCE /var/lib/hbase)".
  • Backups. Take an HBase snapshot of a table with snapshot 'guide_users', 'guide_users-snap' in the shell. Or stop HBase (sudo systemctl stop hbase) and take an Azure snapshot of the data disk.
  • Logs. HBase writes /var/log/hbase/hbase-standalone.log (rolled at 64 MB, ten files kept), also visible under Local Logs in the UI. journalctl -u apache-hbase-firstboot shows what first boot did.
9

Use your own DNS name or certificate

The served host name is fixed by configuration and never taken from a request. To serve the UI under your own DNS name, point the name at the VM's public IP. Then run the helper, which records the name, regenerates the self-signed certificate for it, updates the credentials file and reloads nginx:

sudo hbase-set-hostname <your-dns-name>

Run the same command if the VM's public IP address changes, because a request for a name the VM does not serve is dropped. A static public IP avoids that.

To use a certificate from your own CA or a public CA instead, replace /etc/ssl/hbase/hbase.crt (full chain) and /etc/ssl/hbase/hbase.key (mode 0600, owner root), then run sudo nginx -t && sudo systemctl reload nginx.

10

Security notes

HBase runs as its own unprivileged user with a read-only system and private temporary files. Neither HBase nor nginx can reach the Azure instance metadata service (169.254.169.254) or the Azure wire server (168.63.129.16). The Azure Linux agent keeps its own access.

In standalone mode the HMaster, the RegionServer and ZooKeeper share one process, so the block on the hbase service covers all three. Check the service sandbox settings and the denied addresses:

systemctl show hbase -p User -p NoNewPrivileges -p ProtectSystem -p PrivateTmp | sort for u in hbase nginx; do echo "$u denies: $(systemctl show $u -p IPAddressDeny --value | tr ' ' '\n' | sort | xargs)"; done
NoNewPrivileges=yes PrivateTmp=yes ProtectSystem=strict User=hbase hbase denies: 168.63.129.16/32 169.254.169.254/32 nginx denies: 168.63.129.16/32 169.254.169.254/32

Root logins, empty passwords and X11 forwarding are switched off in /etc/ssh/sshd_config.d/00-sac.conf, which sorts before every other SSH setting. Whether SSH accepts passwords is your choice when you deploy (SSH key or password in the portal). The image never overrides it. Check the effective values:

sudo sshd -T | grep -E '^(permitrootlogin|permitemptypasswords|x11forwarding|pubkeyauthentication) ' | sort
permitemptypasswords no permitrootlogin no pubkeyauthentication yes x11forwarding no

Other points:

  • HBase itself has no users or passwords. Anyone who can log in to the VM can use the HBase shell, so give SSH access only to people who may read and change every table.
  • nginx logs the real client address of every request. X-Forwarded-For headers sent by clients are ignored.
  • Restrict port 443 in your NSG to the networks you browse from.
  • To rotate the UI password, write a new bcrypt hash with sudo htpasswd -iB /etc/nginx/.hbase.htpasswd admin (it reads the new password from standard input). Then update /root/hbase-credentials.txt and reload nginx.
  • Bundled libraries. HBase 2.5.16 ships Netty 4.1.131, which a scanner reports as affected by CVE-2026-75595 (critical) and several high-severity Netty codec advisories. The critical issue is in Netty's SNI-based TLS routing, which HBase does not use; HBase's RPC runs without TLS and listens on localhost only, and the affected HTTP/2, SPDY, Redis, STOMP, HAProxy, XML and DNS codecs are not exposed. The same reasoning covers the high-severity Jetty 9.4.57 advisories (the status UI is reached only through nginx, and HBase uses no DIGEST authentication), the Jackson 2.21.1 polymorphic-typing advisories (HBase enables no default typing on untrusted JSON), protobuf-java 2.5.0 (loopback RPC only) and the lz4-java 1.11.1 temporary-file issue (HBase uses a private Java temporary directory on this image). 2.5.16 is the newest HBase 2.5 release, and SecureAnyCloud updates the image when a newer 2.5 release ships.

When you have finished with the example table from Step 4, remove it. A table must be disabled before it can be dropped:

/opt/hbase/bin/hbase shell -n <<'EOF' 2>&1 | grep -v '^Took ' disable 'guide_users' drop 'guide_users' list EOF
hbase:001:0> disable 'guide_users' hbase:002:0> drop 'guide_users' hbase:003:0> list TABLE 0 row(s) => [] hbase:004:0>

Support and licensing

SecureAnyCloud supports this image 24/7 by email at sales@secureanycloud.com. Include the VM name, the image (Apache HBase on Ubuntu 24.04) and what you were doing.

Apache HBase is open source software under the Apache License 2.0. The licence and notices are on the VM at /opt/hbase/LICENSE.txt and /opt/hbase/NOTICE.txt, and there is no per-user or per-CPU licence fee. The SecureAnyCloud charge covers the hardening, first-boot setup, image maintenance and support.

Apache HBase, HBase, Apache Hadoop, Apache ZooKeeper and Apache are trademarks of the Apache Software Foundation. Ubuntu is a trademark of Canonical Ltd. Java is a trademark of Oracle and/or its affiliates. Microsoft and Azure are trademarks of the Microsoft group of companies. SecureAnyCloud is not affiliated with or endorsed by these organisations.

Deploy on Azure

Launch Apache HBase 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