Apache HertzBeat 1.9.0
Overview
Apache HertzBeat is an open-source, real-time monitoring and alerting system from the Apache Software Foundation. It monitors websites, APIs, TLS certificates, servers, databases, middleware and network services without installing an agent on the target. It evaluates threshold rules and sends alerts through email, webhooks, Slack, Discord, Telegram and many other channels.
This image runs the official Apache HertzBeat 1.9.0 package on OpenJDK 25 on Amazon EC2, as a self-contained single node. An embedded H2 database holds the configuration and an embedded DuckDB store holds the metric history, so there is no external database to provision. It is one version of the SecureAnyCloud Zabbix and Infrastructure Monitoring listing on AWS Marketplace, and you pick it as the software version when you subscribe and launch.
What you get
- HTTPS from the first boot. nginx serves the console on port 443 with a certificate generated on your instance's first boot, and port 80 redirects to HTTPS.
- Secrets unique to your instance. First boot generates the
adminpassword, the key that signs HertzBeat's login tokens (JWT), the key that encrypts the credentials you store in monitors, and the embedded database password. The admin password is stored only as a salted hash, and the password itself is written to/root/hertzbeat-credentials.txt. HertzBeat's well-known defaults (admin/hertzbeatand the published JWT key) are refused, and nothing is baked into the image. - HertzBeat 1.9.0 security fixes and role rules. This release stops serving the signing and encryption keys over the configuration API. It requires sign-in for the live alert, manager and log streams, and limits plugin upload, actuator and warehouse queries to the
adminrole. The image ships exactly one account, admin. - Fail closed. HertzBeat refuses to start until first boot has generated every secret, and nginx refuses to start until first boot has finished.
- HertzBeat on loopback only. HertzBeat listens on
127.0.0.1:1157behind nginx. The remote collector port (1158) is switched off, and the OpenTelemetry gRPC receiver is bound to loopback. The only open ports are 22, 80 and 443. nginx refuses HertzBeat's unauthenticated Prometheus push endpoint (Step 11 shows how to open it), and sign-in attempts are rate limited. - Metadata access blocked for the monitoring engine. HertzBeat probes any host or URL you give it, so the HertzBeat and nginx services are blocked from the instance metadata service. A monitor pointed at
169.254.169.254simply times out, and the AMI requires IMDSv2. - Hardened defaults. HertzBeat runs as its own unprivileged user in a systemd sandbox that can write only its data, its logs and the plugin directory. The program and its configuration belong to root. The console's address comes from your configuration, never from a request, and requests for a host name the instance does not serve are dropped.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on. They also keep OpenJDK and nginx patched.
- 24/7 SecureAnyCloud support.
What is on the image: Apache HertzBeat 1.9.0 (the official apache-hertzbeat-1.9.0-bin.tar.gz, checksum verified), OpenJDK 25 from Ubuntu, 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, make sure you have:
- An AWS account subscribed to the listing, an EC2 key pair, and a VPC subnet with a route to the internet or a private route that you use for management.
- A security group that allows TCP 22 (SSH), TCP 443 (the console) and TCP 80 (redirects to HTTPS) from your own networks only.
- Outbound access from the instance to whatever you want to monitor.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick Apache HertzBeat 1.9.0 on Ubuntu 24.04 as the software version, choose your Region, then choose Launch through EC2.
Choose m5.large, your key pair and a security group as described above. HertzBeat's data lives under /var/lib/hertzbeat on the root volume.
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=hertzbeat}]'Connect to your instance
For the Apache HertzBeat 1.9.0 on Ubuntu 24.04 version, the SSH user is ubuntu. Connect with the key pair you chose:
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot takes a few seconds, and HertzBeat needs about a minute more to start. After that, the three units are active:
systemctl is-active hertzbeat-firstboot hertzbeat nginxactive active activeHertzBeat (the java process) listens on loopback only, and nginx serves ports 80 and 443:
sudo ss -tlnp | awk 'NR==1 || /java|nginx|sshd/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'State Local Peer LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) LISTEN 0.0.0.0:22 users:(("sshd"),("systemd")) LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) LISTEN 127.0.0.1:1157 users:(("java")) LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx")) LISTEN [::]:22 users:(("sshd"),("systemd")) LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx"))The versions on the image:
head -2 /usr/share/doc/hertzbeat/RELEASE java -version 2>&1 | head -1Apache HertzBeat 1.9.0 package apache-hertzbeat-1.9.0-bin.tar.gz openjdk version "25.0.4.1" 2026-08-18The console footer also shows Apache HertzBeat v1.9.0. The Java libraries inside the 1.9.0 package are named *-2.0-SNAPSHOT.jar. That is how Apache built the 1.9.0 release, and it is not a different version.
Get your URL and password
sudo cat /root/hertzbeat-credentials.txtThe file holds the address the console is served on (your instance's public DNS name by default), the administrator user and the password generated on this instance:
HERTZBEAT_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/ HERTZBEAT_ADMIN_USER=admin HERTZBEAT_ADMIN_PASSWORD=<24 letters and digits>Sign in from your browser
Open HERTZBEAT_URL in your browser. The certificate is self-signed and generated on your instance, so accept the browser warning once, or install your own certificate (Step 9). Sign in with admin and the password from Step 4.
On the first sign-in, HertzBeat shows a welcome box. Tick Do not show this popup on next login and close it. The dashboard summarizes your monitors by state and type and lists recent alarms.
Add your first monitor
Choose Monitors, then New Monitor, and pick a monitor type, for example Website under Service. Enter the target host, a task name, the port and whether to use HTTPS. Choose Detect to test the connection, then choose OK to save. Every monitor runs on the built-in collector at the interval you set, which is 60 seconds by default.
The Monitors list shows each monitor's state. Open a monitor to see its live metrics. Open the Monitor Historical Chart Detail tab to see the history kept in the embedded store, which is 90 days by default.
To be told when something breaks, add a rule under Alerting, Threshold. Then add a receiver (email, webhook, Slack, Telegram and others) under Alerting, Notification. Outgoing mail needs your own SMTP server, which you set under Settings, Message Server Setting.
Security checks
These checks confirm the hardening. Port 80 sends browsers to HTTPS, the console answers over HTTPS, the live alert stream needs a sign-in, and the push endpoint is refused. nginx closes the connection for a host name the instance does not serve (000 means no answer), and HertzBeat's default password is refused:
H=$(sudo sed -n 's#^HERTZBEAT_URL=https://\([^/]*\)/.*#\1#p' /root/hertzbeat-credentials.txt)
curl -s -o /dev/null -w 'port 80: %{http_code} -> %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/"
curl -sk -o /dev/null -w 'console: %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/"
curl -sk -o /dev/null -w 'alert stream without sign-in: %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/api/alert/sse/subscribe"
curl -sk -o /dev/null -w 'push endpoint: %{http_code}\n' --resolve "$H:443:127.0.0.1" -X POST "https://$H/api/push/prometheus/test"
curl -s -o /dev/null -w 'unknown host name: %{http_code}\n' -H 'Host: example.com' http://127.0.0.1/ || true
curl -sk --resolve "$H:443:127.0.0.1" -H 'Content-Type: application/json' -d '{"identifier":"admin","credential":"hertzbeat"}' "https://$H/api/account/auth/form"; echoport 80: 301 -> https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/ console: 200 alert stream without sign-in: 401 push endpoint: 403 unknown host name: 000 {"code":5,"data":null,"msg":"Incorrect Account or Password"}Use the REST API
Everything in the console is available over HertzBeat's REST API. Sign in with the form endpoint to get a token, then send it as a bearer token. The password is read from the credentials file and passed in a temporary file, so it never appears on a command line. The signing and encryption keys can never be read back over the API, whatever account asks:
H=$(sudo sed -n 's#^HERTZBEAT_URL=https://\([^/]*\)/.*#\1#p' /root/hertzbeat-credentials.txt)
B=$(mktemp); trap 'rm -f "$B"' EXIT { printf '{"identifier":"admin","credential":"';
sudo sed -n 's/^HERTZBEAT_ADMIN_PASSWORD=//p' /root/hertzbeat-credentials.txt | tr -d '\n'; printf '"}'; } > "$B"
TOKEN=$(curl -sk --resolve "$H:443:127.0.0.1" -H 'Content-Type: application/json' --data-binary @"$B" "https://$H/api/account/auth/form" | jq -r .data.token)
curl -sk --resolve "$H:443:127.0.0.1" -H "Authorization: Bearer $TOKEN" "https://$H/api/monitors?pageSize=10" | jq -r '.data.content[] | "\(.name) \(.app) \(.instance) status=\(.status)"'
curl -sk --resolve "$H:443:127.0.0.1" -H "Authorization: Bearer $TOKEN" -o /dev/null -w 'secret config: %{http_code}\n' "https://$H/api/config/secret"sac website website secureanycloud.com:443 status=1 secret config: 403A value of status=1 means up. The list is empty until you add a monitor.
For scripts that run unattended, create an API token in the console under Settings, API Token Management instead of signing in each time. Give every token an expiry date. In HertzBeat 1.9.0, a revoked token is still accepted when it is passed as a ?token= query parameter until it expires (fixed upstream after 1.9.0), so a short expiry is what really limits a leaked token.
Use your own domain name and certificate
By default, the console is served under your instance's public DNS name with a self-signed certificate. To serve it under your own name, point a DNS record at the instance and run:
sudo hertzbeat-set-hostname monitoring.example.comThis command records the name in /etc/sac/hertzbeat-hostname and generates a new self-signed certificate for it. It pins the name in nginx, so other names get no answer, and sets it as the base of the links in HertzBeat's alert messages. Then it reloads nginx and restarts HertzBeat.
To use a certificate from your own certificate authority, replace /etc/nginx/ssl/hertzbeat.crt and /etc/nginx/ssl/hertzbeat.key, keeping the key mode 0600. Then run sudo systemctl reload nginx.
With Let's Encrypt, install certbot and point it at the same name. HertzBeat's nginx site is /etc/nginx/sites-available/sac-hertzbeat.
Change the admin password
sudo hertzbeat-set-password printf '%s\n' '<your-new-password>' | sudo hertzbeat-set-password --stdinThe first form generates a new random password. The second sets your own password, which must be 24 to 64 letters and digits. Both update /root/hertzbeat-credentials.txt, store only a salted hash in /etc/hertzbeat/sureness.yml and restart HertzBeat.
More accounts. HertzBeat's accounts and their roles (admin, user, guest) are defined in /etc/hertzbeat/sureness.yml. The role rules in the same file are the ones shipped with HertzBeat 1.9.0, and the image ships only admin.
The startup check refuses to start HertzBeat with more than one account. To add accounts, read the Apache HertzBeat account documentation first, then deliberately remove the check (guard) from /usr/local/lib/sac/hertzbeat-config.py.
Optional features that are off by default
- Prometheus push (
/api/push/): HertzBeat accepts pushed metrics there without a sign-in and can create monitors from them, so nginx refuses it. To use it, remove thelocation ^~ /api/push/line from/etc/nginx/sites-available/sac-hertzbeatand runsudo systemctl reload nginx. Then allow the port only from the systems that push. - Remote collectors (port 1158): HertzBeat can hand work to collectors on other hosts. The image switches the collector server off (
scheduler.server.enabled: falsein/etc/hertzbeat/application.yml), and the built-in collector runs every monitor. If you turn the collector server on, the port listens on every interface, so open it in the security group only to your collectors' addresses. - OpenTelemetry gRPC (port 14317): bound to
127.0.0.1by theHERTZBEAT_OTLP_GRPC_HOSTsetting in/etc/systemd/system/hertzbeat.service. - AI assistant and MCP server (the Ask me anything box and Advanced, MCP Server): administrator only in 1.9.0. The assistant does nothing until you configure a model provider for it.
Metadata access is blocked for HertzBeat
HertzBeat connects to any host or URL a monitor names, so the HertzBeat and nginx services cannot reach the EC2 instance metadata service or the cloud wire server. A monitor pointed at 169.254.169.254 times out instead of returning the instance's credentials:
systemctl show -p IPAddressDeny hertzbeat nginxIPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32The block is in /etc/systemd/system/hertzbeat.service.d/50-sac-imds-deny.conf, with an equivalent for nginx. The rest of the instance, including the SSM agent and first boot, uses IMDSv2 as usual.
Your data and backups
HertzBeat keeps its configuration and monitors in an embedded H2 database and the metric history in an embedded DuckDB store:
sudo ls /var/lib/hertzbeat /var/lib/hertzbeat/db/var/lib/hertzbeat: db history.duckdb history.duckdb.wal logs /var/lib/hertzbeat/db: hertzbeat.mv.dbBack up /var/lib/hertzbeat together with /etc/hertzbeat, or snapshot the root volume. The database password and the key that encrypts the credentials stored in your monitors are in /etc/hertzbeat/application.yml, and a copy of the database is not readable without them. Stop HertzBeat (sudo systemctl stop hertzbeat) for a consistent file copy.
The image ships the HertzBeat release named in the listing. Ubuntu's unattended upgrades keep the operating system, nginx and OpenJDK patched. To move to a newer HertzBeat release later, snapshot the instance first and follow the Apache HertzBeat upgrade guide for that release, keeping /var/lib/hertzbeat and /etc/hertzbeat.
Server components
These are the important files and directories on the instance:
- HertzBeat program: /opt/hertzbeat, with the release record in /usr/share/doc/hertzbeat/RELEASE.
- Settings: /etc/hertzbeat/application.yml, linked as /opt/hertzbeat/config.
- Accounts and role rules: /etc/hertzbeat/sureness.yml.
- Data (H2 database, DuckDB history): /var/lib/hertzbeat.
- Uploaded plugins: /opt/hertzbeat/lib/plugin-lib.
- Logs: /var/log/hertzbeat, also available with journalctl -u hertzbeat.
- Service units: /etc/systemd/system/hertzbeat.service and /etc/systemd/system/hertzbeat-firstboot.service.
- nginx site: /etc/nginx/sites-available/sac-hertzbeat.
- Certificate and key: /etc/nginx/ssl/.
- Host name and password helpers: /usr/local/sbin/hertzbeat-set-hostname and /usr/local/sbin/hertzbeat-set-password.
- Credentials: /root/hertzbeat-credentials.txt (mode 0600).
Security recommendations
- Allow ports 22, 80 and 443 in the security group from your own networks only.
- Keep the administrator password secret, and rotate it if it may have been shared (Step 10).
- Use your own DNS name and a certificate that your browsers trust (Step 9).
- Monitors store target credentials, such as database and SSH passwords, encrypted with this instance's key. Give HertzBeat least-privilege accounts on the systems it watches.
- Leave the push endpoint, remote collector port and metadata block as shipped unless you need them (Step 11).
- Keep the operating system patched. Unattended security upgrades are on, and
sudo apt-get update && sudo apt-get upgradeapplies everything else. - Back up
/var/lib/hertzbeatand/etc/hertzbeatregularly (Step 13).
Support and licensing
Apache HertzBeat is open source under the Apache License 2.0. Its license and notice are at /usr/share/doc/hertzbeat/, and there is no per-user or per-CPU license fee. The AMI price covers SecureAnyCloud's hardening, first-boot setup and support.
Apache HertzBeat, HertzBeat and Apache are trademarks of The Apache Software Foundation. SecureAnyCloud is not affiliated with or endorsed by it.
- Email: sales@secureanycloud.com
- Website: https://secureanycloud.com
- Support: 24/7, with a 24 hour response SLA
Deploy on AWS
Launch Apache HertzBeat 1.9.0 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