Deployment guide

Apache HBase 2.5.16

Overview

This guide covers launching and using Apache HBase 2.5.16 on Ubuntu 24.04 from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud Hardened Apache Cassandra, FerretDB & NoSQL Database AMIs listing on AWS Marketplace. You pick it as the software version when you subscribe and launch. The other databases in the listing are described on the listing's guide hub.

Apache HBase is a wide-column NoSQL database modelled 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 image runs HBase in standalone mode. The HMaster, one RegionServer and an embedded ZooKeeper run together in one Java process on one instance and store 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 security group.
  • 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 instance's first boot. Port 80 only redirects to HTTPS.
  • A password unique to your instance. 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, and nginx stores only its bcrypt hash. No password is baked into the image, and no two instances 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 EC2 instance metadata endpoint.
  • Your data on its own disk. Tables, the write-ahead log and ZooKeeper data live on a dedicated 20 GiB EBS volume mounted at /var/lib/hbase, which you can resize independently of the root volume.
  • Fixed host name and real client addresses. Requests for a host name the instance does not serve are dropped. nginx logs the real client address and overwrites client-supplied X-Forwarded-For headers. Cross-site browser requests that change state are refused.
  • Verified download. The Apache release was checked against Apache's published SHA-512 checksum and against 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).
  • Key-only SSH. Password logins, root logins and X11 forwarding are switched off.
  • 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 AWS Systems Manager agent.

Default user: ubuntu. Architecture: x86_64. Recommended instance type: m5.large.

Prerequisites

Before you deploy this image, make sure you have:

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet
  • A security group 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

Launch the instance

In the AWS Marketplace listing, choose Continue to Subscribe, and then Continue to Configuration. Pick Apache HBase 2.5.16 on Ubuntu 24.04 as the software version and select your Region. Then choose Launch through EC2.

Choose m5.large, your key pair and a security group as described above. The AMI brings its own 20 GiB data volume for HBase. Increase its size on the launch page if you expect more data (Step 8).

To launch with the AWS CLI instead, replace the values in angle brackets:

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=hbase}]'
2

Connect to your instance

Version SSH user

Apache HBase 2.5.16 on Ubuntu 24.04 ubuntu

ssh -i <your-key.pem> ubuntu@<public-ip>
3

Check the services

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

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:

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 run hbase shell for an interactive session. It talks to HBase over loopback, so it works for any user logged in to the instance.

The example below creates a table with one column family, writes two rows, and reads them 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-22T07:39:42.265, value=London user1 column=info:name, timestamp=2026-10-22T07:39:42.219, value=Ada Lovelace user2 column=info:city, timestamp=2026-10-22T07:39:42.339, value=Manchester user2 column=info:name, timestamp=2026-10-22T07:39:42.311, value=Alan Turing 2 row(s) hbase:007:0> get 'guide_users', 'user2', 'info:city' COLUMN CELL info:city timestamp=2026-10-22T07:39:42.339, 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 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://ec2-<public-ip-dashed>.compute-1.amazonaws.com/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 instance.

The URL uses the instance's public DNS name from EC2 instance metadata (IMDSv2). If the instance has no public name, it uses the public or private IPv4 address. The certificate names that host plus the instance's public and private IP addresses:

openssl x509 -in /etc/ssl/hbase/hbase.crt -noout -subject -ext subjectAltName -enddate
subject=CN = ec2-<public-ip-dashed>.compute-1.amazonaws.com, O = sac X509v3 Subject Alternative Name: DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<public-ip>, IP Address:<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://ec2-<public-ip-dashed>.compute-1.amazonaws.com/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

The --resolve option sends the request to this instance 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://<your-host>/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:

Click 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:

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 instance itself. Run your application, the HBase shell or the hbase tools here, and point the client at ZooKeeper on localhost:2181. That 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")))); }

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 -i <your-key.pem> -N -L 2181:127.0.0.1:2181 -L 16000:127.0.0.1:16000 -L 16020:127.0.0.1:16020 ubuntu@<public-ip>

Never open 2181 or 16000 to 16030 in a security group. 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 EBS volume 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
20G total, 19G 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 instance, raise HBASE_HEAPSIZE in /opt/hbase/conf/hbase-env.sh (about half of the instance's memory is a good start), then run sudo systemctl restart hbase.
  • Disk. To grow the volume, modify it in the EC2 console (Volumes, Modify volume) and then extend the file system online: 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 EBS snapshot of the data volume.
  • 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 instance and run the helper. The helper records the name, regenerates the self-signed certificate for it, updates the credentials file and reloads nginx:

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

If the instance's public DNS name changes after a stop and start, run the same command again, because a request for a name the instance does not serve is dropped. An Elastic IP avoids the change.

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 instance metadata endpoint.

In standalone mode the HMaster, the RegionServer and ZooKeeper share one process, so the block on the hbase service covers all three:

systemctl show hbase -p User -p NoNewPrivileges -p ProtectSystem -p PrivateTmp -p IPAddressDeny
systemctl show nginx -p IPAddressDeny
IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 User=hbase PrivateTmp=yes ProtectSystem=strict NoNewPrivileges=yes IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32

SSH accepts keys only. Passwords, root logins and X11 forwarding are switched off in /etc/ssh/sshd_config.d/00-sac.conf, which sorts before every other SSH setting. Check the effective values:

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

Other points:

  • HBase itself has no users or passwords, so anyone who can log in to the instance can use the HBase shell. Give SSH access only to people who may read and change every table.
  • nginx logs the real client address of every request and ignores X-Forwarded-For headers sent by clients.
  • The AMI requires IMDSv2. Restrict port 443 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, which 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) and the lz4-java 1.11.1 temporary-file issue (HBase uses a private Java temporary directory on this image). HBase 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 by email at sales@secureanycloud.com. Include the instance ID, the version (Apache HBase 2.5.16 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 instance at /opt/hbase/LICENSE.txt and /opt/hbase/NOTICE.txt. There is no per-user or per-CPU licence fee. The AMI price covers SecureAnyCloud's hardening, first-boot setup 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. SecureAnyCloud is not affiliated with or endorsed by these organisations.

Deploy on AWS

Launch Apache HBase 2.5.16 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS