Streaming & Messaging AWS

Apache ActiveMQ Classic on AWS User Guide

| Product: Apache ActiveMQ Classic on AWS

Overview

This image runs Apache ActiveMQ Classic, the long established open source message broker from the Apache Software Foundation. ActiveMQ Classic implements the Jakarta Messaging (JMS) API and speaks a broad set of wire protocols, so applications written in Java, Python, .NET, C++, Go and Node.js can all exchange messages through one broker. It supports point to point queues, publish and subscribe topics, durable subscriptions, message persistence, and a web management console for inspecting and operating destinations.

ActiveMQ Classic is a Java application and runs on OpenJDK 17, installed from the Ubuntu archive. The broker itself is installed from the official Apache binary distribution under /opt/activemq, is checksum verified during the build, runs as a dedicated unprivileged activemq service user, and is supervised by systemd as activemq.service.

The broker exposes its native OpenWire connector on port 61616, together with AMQP on 5672, STOMP on 61613 and MQTT on 1883. The Jetty web management console is deliberately bound to the loopback interface on port 8161 and is never exposed directly. An nginx reverse proxy serves the console on port 80, so the console is reached at the instance address without the raw management listener being reachable from the network. nginx also serves an unauthenticated health endpoint at /health for load balancer and monitoring checks.

Stock ActiveMQ Classic ships a well known admin / admin credential for both the web console and the broker. This image contains no such default. The build removes the administrator entry from the shipped realm files entirely, and a one shot first boot service generates a password unique to each deployed instance, applies it to both the console realm and the broker authentication plugin, and then proves the rotation worked before recording anything. Two instances launched from the same image never share a password.

The broker's KahaDB persistence store, data directory and temporary space live on a dedicated EBS data volume mounted at /var/lib/activemq, separate from the operating system disk, so message storage can be resized independently of the root volume.

ActiveMQ Classic and ActiveMQ Artemis are different products. This image is Classic, the 6.x generation of the original broker. Artemis is a separate, independently versioned broker with a different codebase and console, and cloudimg publishes it as its own listing. If you specifically need Artemis, use that listing instead.

Prerequisites

Before you deploy this image you need:

  • An Amazon Web Services account where you can launch EC2 instances
  • IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
  • An EC2 key pair in the target Region for SSH access to the instance
  • A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network, inbound port 80 from the trusted networks that will reach the console, and inbound port 61616 from the networks where your messaging clients run
  • The AWS CLI (version 2) installed locally if you plan to deploy from the command line

Step 1: Launch the Instance from the AWS Marketplace

Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images choose AWS Marketplace AMIs and search for Apache ActiveMQ Classic. Select the cloudimg listing and choose Select, then Continue on the subscription summary.

Pick an instance type of m5.large or larger. ActiveMQ Classic is a Java application and benefits from memory; the dedicated data volume gives the persistence store room to grow. Choose your EC2 key pair under Key pair (login). Under Network settings select your VPC and subnet, and either create or select a security group as described in the prerequisites. Do not open the console or broker ports to the public internet unless you intend them to be publicly reachable. Leave the root volume at the default size or larger.

Select Launch instance. First boot initialisation takes approximately one to two minutes after the instance state becomes Running and the status checks pass, while the broker generates and verifies the administrator password.

Step 2: Launch the Instance from the AWS CLI

The following block launches an instance from the cloudimg Apache ActiveMQ Classic Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens ports 22, 80 and 61616 as described above.

aws ec2 run-instances \
  --image-id <ami-id> \
  --instance-type m5.large \
  --key-name <key-name> \
  --subnet-id <subnet-id> \
  --security-group-ids <security-group-id> \
  --block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":30,"VolumeType":"gp3"}}]' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=activemq-01}]'

The command prints a JSON document on success. Note the instance ID, then retrieve its public address once it is running with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.

Step 3: Connect and Retrieve the Credentials

Connect over SSH with the key pair you selected and the public IP address from step 2. The SSH login user depends on the operating system of the AMI variant you launched:

AMI variant SSH login user
Apache ActiveMQ Classic 6.2.7 on Ubuntu 24.04 ubuntu

The first boot service completes before the broker starts, so the credentials file is always in place when you log in for the first time.

sudo cat /root/activemq-credentials.txt
# Apache ActiveMQ Classic - generated on first boot by activemq-firstboot.service.
# This password is unique to this instance and was verified against the running broker
# before this file was written. Store it somewhere safe.

ACTIVEMQ_URL=http://<vm-ip>/
ACTIVEMQ_ADMIN_USER=admin
ACTIVEMQ_ADMIN_PASSWORD=<ACTIVEMQ_ADMIN_PASSWORD>

# Web console:      http://<vm-ip>/   (sign in as 'admin' with the password above)
# OpenWire broker:  tcp://<vm-ip>:61616   (same credential; broker auth is enabled)
# AMQP 5672 | STOMP 61613 | MQTT 1883  (enabled on the broker, not opened by the default security group)
# KahaDB persistence store + broker data: /var/lib/activemq

Copy these values somewhere secure such as a password manager or an encrypted vault, and do not commit them to source control. The same admin credential authenticates both the web console and the broker connectors.

The credentials file is owned by root and readable only by root:

sudo ls -l /root/activemq-credentials.txt
-rw------- 1 root root 680 Jul 20 08:00 /root/activemq-credentials.txt

Step 4: Verify the Broker Is Running

Both services should report active:

systemctl is-active activemq.service nginx.service
active
active

The unauthenticated health endpoint returns 200 OK and is intended for load balancer target group checks and uptime monitoring:

curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1/health
HTTP 200

The console rejects unauthenticated requests, and it also rejects the stock admin / admin credential that upstream ActiveMQ ships, because that credential does not exist on this image:

curl -s -o /dev/null -w 'unauthenticated: HTTP %{http_code}\n' http://127.0.0.1/admin/
curl -s -o /dev/null -w 'default credential: HTTP %{http_code}\n' -u admin:admin http://127.0.0.1/admin/
unauthenticated: HTTP 401
default credential: HTTP 401

The listening sockets show nginx on port 80, the management console bound to loopback only on 8161, and the four broker connectors:

sudo ss -tln | grep -E ':(80|8161|61616|5672|61613|1883) '
LISTEN 0    511          0.0.0.0:80         0.0.0.0:*
LISTEN 0    128  [::ffff:127.0.0.1]:8161          *:*
LISTEN 0    128                *:5672           *:*
LISTEN 0    128                *:1883           *:*
LISTEN 0    128                *:61613          *:*
LISTEN 0    128                *:61616          *:*

Note that port 8161 is bound to 127.0.0.1 only. The management console is never directly reachable from the network; nginx on port 80 is the only path to it.

Step 5: Sign In to the Management Console

Browse to http://<instance-public-ip>/ and sign in as admin with the password from step 3. The console home view reports the broker name, version, uptime and store utilisation.

ActiveMQ Classic management console home view showing broker name, version 6.2.7, uptime and store utilisation

The Queues view lists every queue destination with its pending, enqueued and dequeued message counts, and offers browse, purge, pause and delete operations per destination.

ActiveMQ Classic queues view listing destinations with pending, enqueued and dequeued message counts

The Topics view does the same for publish and subscribe destinations.

ActiveMQ Classic topics view listing publish and subscribe destinations

The Connections view shows the client connections currently attached to each transport connector, which is the quickest way to confirm a new client has connected successfully.

ActiveMQ Classic connections view showing client connections per transport connector

The Send view publishes a message to any queue or topic straight from the browser, which is useful for smoke testing a consumer without writing a client.

ActiveMQ Classic send message form for publishing a test message to a queue or topic

Step 6: Send and Receive a Test Message

The distribution ships a command line producer and consumer. Both require the administrator credential, because broker authentication is enabled on this image. Read the password into a shell variable rather than typing it on the command line so it does not land in your shell history:

PW=$(sudo grep '^ACTIVEMQ_ADMIN_PASSWORD=' /root/activemq-credentials.txt | cut -d= -f2-)
. /etc/default/activemq
sudo runuser -u activemq -- env ACTIVEMQ_HOME="$ACTIVEMQ_HOME" ACTIVEMQ_BASE="$ACTIVEMQ_BASE" \
  ACTIVEMQ_CONF="$ACTIVEMQ_CONF" ACTIVEMQ_DATA="$ACTIVEMQ_DATA" ACTIVEMQ_TMP="$ACTIVEMQ_TMP" \
  "$ACTIVEMQ_HOME/bin/activemq" producer --brokerUrl tcp://127.0.0.1:61616 \
  --user admin --password "$PW" --destination queue://demo.orders --messageCount 5 \
  --persistent true 2>&1 | tail -3

Consume the same five messages back off the queue:

PW=$(sudo grep '^ACTIVEMQ_ADMIN_PASSWORD=' /root/activemq-credentials.txt | cut -d= -f2-)
. /etc/default/activemq
sudo runuser -u activemq -- env ACTIVEMQ_HOME="$ACTIVEMQ_HOME" ACTIVEMQ_BASE="$ACTIVEMQ_BASE" \
  ACTIVEMQ_CONF="$ACTIVEMQ_CONF" ACTIVEMQ_DATA="$ACTIVEMQ_DATA" ACTIVEMQ_TMP="$ACTIVEMQ_TMP" \
  "$ACTIVEMQ_HOME/bin/activemq" consumer --brokerUrl tcp://127.0.0.1:61616 \
  --user admin --password "$PW" --destination queue://demo.orders --messageCount 5 2>&1 | tail -3

After the producer runs, the queue appears in the Queues view of the console with its enqueued count, and after the consumer runs the dequeued count matches.

Step 7: Connect Your Own Clients

Point your application at the broker address using the credential from step 3. The connector endpoints are:

Protocol Port Client URL
OpenWire (native JMS) 61616 tcp://<instance-public-ip>:61616
AMQP 1.0 5672 amqp://<instance-public-ip>:5672
STOMP 61613 stomp://<instance-public-ip>:61613
MQTT 1883 tcp://<instance-public-ip>:1883

Only port 61616 is opened by the security group recommended on the listing. If you need AMQP, STOMP or MQTT, add inbound rules for those ports to the instance's security group, restricted to the networks where your clients run. All four connectors require the admin credential; anonymous access is disabled.

A minimal Java JMS client connects like this:

ActiveMQConnectionFactory factory =
    new ActiveMQConnectionFactory("tcp://<instance-public-ip>:61616");
Connection connection = factory.createConnection("admin", "<ACTIVEMQ_ADMIN_PASSWORD>");
connection.start();

For production traffic, terminate TLS in front of the broker or configure ActiveMQ's own SSL transport connectors, and restrict the broker ports to private networks. Do not send credentials over a plain connector across an untrusted network.

Step 8: Understand the Storage Layout

The persistence store sits on its own EBS volume, mounted by filesystem UUID so the mount survives device renaming across reboots and instance types:

df -h /var/lib/activemq | tail -1
/dev/nvme1n1     30G  1.3M   28G   1% /var/lib/activemq
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT | grep -v loop
NAME          SIZE TYPE MOUNTPOINT
nvme1n1        30G disk /var/lib/activemq
nvme0n1        30G disk 
├─nvme0n1p1    29G part /
├─nvme0n1p14    4M part 
├─nvme0n1p15  106M part /boot/efi
└─nvme0n1p16  913M part /boot

Under that mount point:

  • kahadb is the KahaDB persistence store, where persistent messages are written
  • data is the broker data and log directory
  • tmp is temporary spool space for large messages

To grow message storage, modify the EBS volume in the AWS console or CLI, then run sudo resize2fs /dev/nvme1n1 on the instance. The root volume is untouched by this, so you can scale the data tier independently.

Step 9: Rotate the Administrator Password

To set a new password yourself, replace the admin entry in the console realm and the broker credential, then restart the broker. Both files must carry the same value, because the console and the broker share the one credential:

AMQ_CONF=/opt/activemq/current/conf
NEW_PW='<your-new-password>'
sudo sed -i -E '/^[[:space:]]*admin[[:space:]]*=/d' "$AMQ_CONF/users.properties"
echo "admin=$NEW_PW" | sudo tee -a "$AMQ_CONF/users.properties" >/dev/null
sudo sed -i -E '/^[[:space:]]*activemq\.admin\.password[[:space:]]*=/d' "$AMQ_CONF/credentials.properties"
echo "activemq.admin.password=$NEW_PW" | sudo tee -a "$AMQ_CONF/credentials.properties" >/dev/null
sudo systemctl restart activemq.service

Update /root/activemq-credentials.txt to match so the recorded value stays accurate. Verify the new password is accepted and that the console still rejects the old one before you rely on it.

Note that credentials.properties and users.properties as shipped by Apache do not always end with a newline. Always append with a leading newline, or use the sed and echo pattern above, or the new key can be concatenated onto the previous line and silently ignored.

Step 10: Service Management and Logs

systemctl show activemq.service -p Description -p ActiveState -p SubState -p UnitFileState
Description=Apache ActiveMQ Classic message broker
ActiveState=active
SubState=running
UnitFileState=enabled

For the full unit view including the current uptime and process tree, use systemctl status activemq.service.

Useful operations:

  • Restart the broker: sudo systemctl restart activemq.service
  • Stop the broker: sudo systemctl stop activemq.service
  • Broker log: sudo tail -f /var/lib/activemq/data/activemq.log
  • systemd journal: sudo journalctl -u activemq.service -f
  • Reverse proxy log: sudo tail -f /var/log/nginx/access.log

All three services are enabled at boot:

systemctl is-enabled activemq-firstboot.service activemq.service nginx.service
enabled
enabled
enabled

Step 11: Backup and Maintenance

The broker's durable state is the KahaDB store under /var/lib/activemq/kahadb, plus the broker configuration under /opt/activemq/current/conf.

For a consistent copy of the persistence store, stop the broker first, because KahaDB is an active append only store:

sudo systemctl stop activemq.service
sudo tar -czf /var/tmp/activemq-kahadb-$(date +%F).tar.gz -C /var/lib/activemq kahadb
sudo systemctl start activemq.service

For a point in time copy without downtime, take an EBS snapshot of the data volume instead. Snapshot the configuration separately, as it lives on the root volume:

sudo tar -czf /var/tmp/activemq-conf-$(date +%F).tar.gz -C /opt/activemq/current conf

Keep the operating system patched with sudo apt-get update && sudo apt-get upgrade. Broker upgrades within the 6.x series are done by extracting the new Apache distribution alongside the existing one, repointing the /opt/activemq/current symlink, carrying your conf changes across, and restarting the service. Review the Apache release notes before upgrading, and take a snapshot of the data volume first.

How First Boot Secures the Instance

The activemq-firstboot.service one shot unit runs once, before the broker starts. It generates a random 24 character password, writes it into the console realm file and into the broker credential file, and then verifies the result against a broker it starts itself:

  • The console must reject an unauthenticated request
  • The console must reject the stock admin / admin credential
  • The console must accept the newly generated password
  • A message must be produced and consumed successfully using the new credential
  • The broker must reject the stock admin / admin credential

Only when all five checks pass does the service write /root/activemq-credentials.txt, install the login banner, and create its completion sentinel at /var/lib/cloudimg/activemq-firstboot.done. If any check fails it exits without writing the sentinel, so the rotation runs again on the next boot; because activemq.service requires the first boot unit, the broker never starts with an unverified credential.

You can confirm this ran on your instance:

sudo journalctl -u activemq-firstboot.service --no-pager | grep -E 'PROOF|proofs passed' | sed 's/^.*activemq-firstboot: //'
PROOF 1/5 - console must reject an unauthenticated request
PROOF 2/5 - console must reject the stock default admin/admin
PROOF 3/5 - console must accept the per-instance password
PROOF 4/5 - broker must accept a produce+consume round trip with the new password
PROOF 5/5 - broker must reject the stock default admin/admin
All 5 rotation proofs passed

Troubleshooting

The console returns 502 Bad Gateway. The broker is still starting. A JVM broker typically needs one to two minutes on first boot. Check sudo systemctl status activemq.service and sudo tail -50 /var/lib/activemq/data/activemq.log.

The broker will not start and the log mentions an unresolved placeholder. The activemq.admin.password key is missing from conf/credentials.properties. This is the fail closed state: the broker deliberately refuses to run without a credential. Re-run first boot with sudo rm -f /var/lib/cloudimg/activemq-firstboot.done && sudo systemctl restart activemq-firstboot.service, then start the broker.

A client is rejected with a security exception. Broker authentication is enabled and anonymous access is disabled. Supply the admin username and the password from /root/activemq-credentials.txt in your client's connection factory.

The console is unreachable from a browser but works with curl on the instance. The security group is not allowing inbound port 80 from your network. The console is bound to loopback by design and reached only through nginx.

A queue is filling up and never drains. No consumer is attached. Check the Connections view in the console, and confirm your consumer is connecting to the right destination name; queue names are case sensitive.

Support

cloudimg provides 24/7 technical support for this image by email and live chat.

  • Email: support@cloudimg.co.uk
  • Live chat: available 24/7 on cloudimg.co.uk

Our engineers can help with broker deployment, connector and protocol configuration, queue and topic design, persistence tuning, network of brokers topologies, upgrades, and troubleshooting. Critical issues receive a one hour average response.

Apache, ActiveMQ and Apache ActiveMQ are trademarks of the Apache Software Foundation. All other product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.