Apache RocketMQ 5.5.1
Overview
This guide covers launching and using the Apache RocketMQ 5.5.1 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud streaming and messaging listing on AWS Marketplace. You pick it as the software version when you subscribe and launch.
Apache RocketMQ is a distributed messaging and streaming platform. It provides topics with normal, ordered (FIFO), delayed and transactional messages, consumer groups with clustering and broadcast consumption, message filtering by tag or SQL92, retries and dead-letter queues, and message tracing. Its commit-log store is built for high throughput and low latency.
RocketMQ 5 adds a stateless gRPC proxy that the RocketMQ 5 client SDKs (Java, Python, Go, C++, C#, Node.js, Rust) connect to. The image also includes the RocketMQ Dashboard, a web console for clusters, topics, consumer groups and messages.
What you get from the SecureAnyCloud image:
- Authentication and authorization on. RocketMQ's ACL 2.0 is enabled on the broker and the proxy: every client signs its requests with an access key and secret, and every request is checked against that user's policies. Out of the box, RocketMQ accepts anyone who can reach it. This image accepts no anonymous client and ships no sample user (the distribution's sample
rocketmq2/12345678tools credentials are removed). - Users generated on your instance. At first boot each instance creates its own users with random 32-character secrets:
admin(a super user for administration on the instance),app(a least-privilege user that may publish to and subscribe from topics and may not administer anything) and the service identities of the proxy and the Dashboard. The Dashboard has its own, separate login. None of these secrets is in the image, and the first-start admin secret is removed from the broker's configuration as soon as the broker has created the user. - Clients over TLS only. The only RocketMQ port reachable from other machines is 8081, which is TLS 1.2 or 1.3 in front of the RocketMQ 5 gRPC proxy. The NameServer (9876), the broker (10911, 10909, 10912) and the proxy's own ports (18080, 18081) are reachable from the instance only. Every RocketMQ service runs with a kernel filter that drops any packet to or from an address that is not the loopback address, so even a security group that allowed those ports would not expose them. The NameServer in RocketMQ 5.5.1 has no authentication at all, which is why it is never reachable off the instance.
- HTTPS from the first boot. nginx serves the Dashboard on port 443, port 80 redirects to HTTPS, and requests for host names the instance does not serve are dropped. The same certificate secures port 8081. It is an end-entity certificate, so it can only vouch for this instance's own names and can never sign other certificates. Install your own CA-issued certificate with one command (Step 11). The boot-time renewal never replaces it.
- A guarded Dashboard. Its own login is required for every page and API call, including the proxy pages, which the upstream Dashboard leaves open. Logins are rate limited, a request carrying another site's
Originis refused, and so is every WebSocket upgrade. The Dashboard's read and refresh calls that fetch from a broker or proxy address only go through when the browser proves the request comes from the Dashboard itself. The session cookie isSecure,HttpOnlyandSameSite=Strict. The Spring Boot actuator and the Dashboard's demo test endpoint are not served. - Fail closed. Every RocketMQ service starts only after first boot has written its secrets, and a configuration check refuses to start a service with authentication or authorization switched off, a public address, topic auto-creation, an authentication whitelist, a missing secret or a Dashboard without its login.
- Hardened defaults. Every service is blocked from the instance metadata service. The one small service that reads the instance's own host names is allowed to reach nothing else. The AMI requires IMDSv2, and nginx hands RocketMQ the real client address and the configured host name, never values a client sends. The services run under systemd sandboxing as unprivileged users, topics are created by an administrator and never by a client, and no JVM writes a heap dump.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Apache RocketMQ 5.5.1 (the official Apache binary release, verified against its published SHA-512 digest and its release signature), RocketMQ Dashboard 2.1.0 (built by SecureAnyCloud from the signed Apache source release), OpenJDK 17 (from Ubuntu 24.04), nginx 1.24 with its stream module (from Ubuntu 24.04), 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 with a route to the internet (or a private route you use for management)
- A security group that allows TCP 22 (SSH) from your admin network, TCP 8081 (RocketMQ clients over TLS) from the networks your applications connect from, and TCP 443 (the Dashboard) from your admin network, plus TCP 80 if you want plain HTTP requests redirected to HTTPS
- A root volume sized for your retention, because the message store lives on the root volume
There is nothing to gain from opening 9876, 10909, 10911, 10912, 18080, 18081 or 8082, because the instance drops those connections.
The AMI's root volume is 8 GiB. For production, launch with a larger root volume (for example 50 GiB or more, sized for your retention). The root partition grows to the volume size at first boot.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, and then Continue to Configuration. Pick Apache RocketMQ 5.5.1 on Ubuntu 24.04 as the software version and select your Region. Then choose Launch through EC2.
Choose m5.large, your key pair, a security group as described above and the root volume size you need.
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> \
--block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=50,VolumeType=gp3}' \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=rocketmq}]'First boot takes about four minutes after the instance is running, because the first boot of a new volume also loads its blocks from the snapshot. The boot service generates the secrets and the certificate, and then the NameServer and the broker start. The broker creates the admin user, and a one-off bootstrap creates the other users and the self-test topics. Finally, the proxy, the Dashboard and nginx start.
Connect to your instance
Version SSH user
Apache RocketMQ 5.5.1 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
systemctl is-active rocketmq-metadata-names rocketmq-firstboot rocketmq-namesrv rocketmq-broker rocketmq-proxy rocketmq-dashboard nginx
sudo test -f /var/lib/sac/data/rocketmq-firstboot.done && echo FIRSTBOOT_DONEAll seven units are active and the first boot marker is present:
active active active active active active active FIRSTBOOT_DONEOnly SSH and nginx (80, 443 and 8081) accept connections from other machines. The NameServer, the broker and the Dashboard listen on the loopback address. RocketMQ cannot bind the broker's HA port or the proxy's ports to one address, so those three show *. The kernel filter on their services drops every packet that does not come from the instance itself:
sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0.5' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort*:10912 users:(("java")) *:18080 users:(("java")) *:18081 users:(("java")) 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")) 0.0.0.0:8081 users:(("nginx"),("nginx"),("nginx")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx")) [::]:8081 users:(("nginx"),("nginx"),("nginx")) [::ffff:127.0.0.1]:10909 users:(("java")) [::ffff:127.0.0.1]:10911 users:(("java")) [::ffff:127.0.0.1]:8082 users:(("java")) [::ffff:127.0.0.1]:9876 users:(("java"))Get your endpoint, users and certificate fingerprint
sudo cat /root/rocketmq-credentials.txtThe file is readable by root only:
# Apache RocketMQ 5.5.1 on Ubuntu 24.04 - generated on first boot by rocketmq-firstboot.service.
# Every secret below is unique to this instance; none was baked into the image. Keep this file secret.
# Clients connect over TLS ONLY, to ROCKETMQ_GRPC_ENDPOINT (the RocketMQ 5 gRPC proxy; the NameServer and broker
# ports are reachable from this instance only). Authentication and authorization (ACL 2.0) are on:
# app - a Normal user that may publish to and subscribe from topics (no administration): give it to applications
# admin - a Super user for administration on this instance:
sudo rocketmq-admin <mqadmin subcommand> ...
# The certificate is self signed (minted on this instance): check that the SHA-256 fingerprint your client sees
# matches ROCKETMQ_TLS_CERT_SHA256 below, then pin /etc/sac/rocketmq-broker.pem in that client's OWN trust # file - or install a CA-issued certificate with sudo rocketmq-install-cert <chain.pem> <key.pem> # The Dashboard (HTTPS) has its own login (ROCKETMQ_DASHBOARD_USER / _PASSWORD). # Change the served name:
sudo rocketmq-set-hostname <dns-name> Re-verify:
sudo rocketmq-selftest ROCKETMQ_GRPC_ENDPOINT=<public-dns>:8081 ROCKETMQ_TLS_CERT_SHA256=<sha256-fingerprint> ROCKETMQ_TLS_CERT_FILE=/etc/sac/rocketmq-broker.pem ROCKETMQ_APP_ACCESS_KEY=app ROCKETMQ_APP_SECRET_KEY=<ROCKETMQ_APP_SECRET_KEY> ROCKETMQ_ADMIN_ACCESS_KEY=admin ROCKETMQ_ADMIN_SECRET_KEY=<ROCKETMQ_ADMIN_SECRET_KEY> ROCKETMQ_DASHBOARD_URL=https://<public-dns>/ ROCKETMQ_DASHBOARD_USER=admin ROCKETMQ_DASHBOARD_PASSWORD=<ROCKETMQ_DASHBOARD_PASSWORD>
# User guide: https://secureanycloud.com/stacks/apache-rocketmq-5-5-1/The host is the instance's public DNS name from the EC2 instance metadata. If the instance has none, the host is the public IP address, and then the private address. The certificate also names the public and private IP addresses and the private DNS name, so clients may connect with any of them.
If you stop and start the instance without an Elastic IP, the boot service picks up the new names and issues a new certificate for them, unless you installed your own (Step 11). To use your own DNS name, see Step 11.
Print the certificate's SHA-256 fingerprint and its names:
sudo openssl x509 -in /etc/sac/rocketmq-broker.pem -noout -fingerprint -sha256 openssl x509 -in /etc/sac/rocketmq-broker.pem -noout -ext subjectAltName,basicConstraintssha256 Fingerprint=<sha256-fingerprint> X509v3 Subject Alternative Name: DNS:<public-dns>, IP Address:<public-ip>, IP Address:<private-ip>, DNS:ip-<private-ip-dashed>.ec2.internal, IP Address:127.0.0.1, DNS:localhost X509v3 Basic Constraints: critical CA:FALSEHow to trust this certificate. The certificate is self-signed and unique to this instance. Before a client trusts it, verify the SHA-256 fingerprint that client sees against ROCKETMQ_TLS_CERT_SHA256 in the credentials file (read over SSH, as above). Then pin it in that client's own trust file only, which is a certificate file that only this application uses, as in Step 8. Never add it to an operating-system, browser or JVM-wide trust store. For clients you cannot configure that way, install a certificate from a certificate authority instead (Step 11).
The RocketMQ Dashboard
Open https://<public-dns>/ in your browser. Your browser warns that the certificate is self-signed. Open the certificate details, check that its SHA-256 fingerprint matches the one in the credentials file, and only then continue to the site.
Log in as admin with ROCKETMQ_DASHBOARD_PASSWORD. After 10 failed logins a minute, the Dashboard answers 429 for a while.
The Cluster page (shown at the top of this guide) lists the broker with its version, throughput and today's message counts.
The Topic page lists the topics. Add / Update creates one, and each row has buttons for its status, routing, consumers, configuration, sending a test message, resetting consumer offsets and deleting it:
Status shows each queue of the topic with its offsets:
The Message page finds messages by topic and time range, by key or by message ID, and shows each message's properties and body:
The Consumer page lists the consumer groups with their clients, consumption mode and backlog:
Notes:
- The Dashboard acts on the broker as a super user. Anyone with the Dashboard login can create and delete topics, groups, users and policies, reset offsets and read messages, so share the login only with RocketMQ administrators.
- The Dashboard's ACL user list displays users' secrets, as does
mqadmin listUser. Do not take screenshots of that page or paste its contents anywhere. - nginx refuses (400) a URL whose path contains
;or an encoded/,.,\or NUL.
Administer RocketMQ with rocketmq-admin
rocketmq-admin runs Apache RocketMQ's mqadmin against this instance as the admin user (or with --as app, the app user). It reads the access key and secret from the credentials file and hands them to mqadmin in a file that exists only while the command runs, so no secret ever appears on a command line or in the process list. Every mqadmin subcommand works, and the NameServer address is set for you:
sudo rocketmq-admin clusterList | cut -c1-100#Cluster Name #Broker Name #BID #Addr #Version
# DefaultCluster broker-a 0 127.0.0.1:10911 V5_5_1Clients cannot create topics. An administrator creates each one. RocketMQ 5 clients need the topic's message type (NORMAL, FIFO, DELAY or TRANSACTION):
sudo rocketmq-admin updateTopic -b 127.0.0.1:10911 -t orders -r 4 -w 4 -a +message.type=NORMALcreate topic to 127.0.0.1:10911 success. TopicConfig [topicName=orders, readQueueNums=4, writeQueueNums=4, perm=RW-, topicFilterType=SINGLE_TAG, topicSysFlag=0, order=false, attributes={+message.type=NORMAL}]Give each application its own user with only the permissions it needs. Generate the secret on the instance into a file readable by root only. The --secret-file option puts it in place of the literal argument @SECRET@, so it never appears on a command line:
sudo bash -c 'umask 077; openssl rand -hex 16 > /root/orders-service.secret'
sudo rocketmq-admin --secret-file /root/orders-service.secret createUser -b 127.0.0.1:10911 -u orders-service -p @SECRET@ -t Normalcreate user to 127.0.0.1:10911 success.Allow it to publish to and subscribe from the orders topic only, with consumer groups whose names start with orders-:
sudo rocketmq-admin createAcl -b 127.0.0.1:10911 -s User:orders-service -r Topic:orders -a Pub,Sub -d Allow
sudo rocketmq-admin createAcl -b 127.0.0.1:10911 -s User:orders-service -r Group:orders-* -a Sub -d Allowcreate acl to 127.0.0.1:10911 success. create acl to 127.0.0.1:10911 success.List the policies. This output contains no secrets:
sudo rocketmq-admin listAcl -b 127.0.0.1:10911#Subject #PolicyType #Resource #Actions #SourceIp #Decision User:app Custom Topic:* [Pub, Sub] null Allow User:app Custom Group:* [Sub] null Allow User:app Custom Topic:sac-denied [Pub, Sub] null Deny User:orders-service Custom Topic:orders [Pub, Sub] null Allow User:orders-service Custom Group:orders-* [Sub] null AllowThe app user may publish and subscribe on every topic except sac-denied, a topic the self-test uses to prove that a denial works. It cannot administer anything:
sudo rocketmq-admin --as app updateTopic -b 127.0.0.1:10911 -t not-allowed 2>&1 | grep -o 'DESC: .*'DESC: User:app has no permission to access Topic:not-allowed from 127.0.0.1, no matched policies.Notes:
mqadmin listUserandgetUserprint users' secrets in clear, so never paste their output anywhere. To change a user's secret, write the new one to a root-only file and runsudo rocketmq-admin --secret-file <file> updateUser -b 127.0.0.1:10911 -u <user> -p @SECRET@. The proxy caches users for up to a minute.deleteUser,deleteAclandupdateAclmanage users and policies. Resources areTopic:<name>,Group:<name>, a prefix such asTopic:orders-*, or*, and actions arePub,Sub,Create,Update,Delete,Get,ListorAll. A policy can also be limited to source addresses with-i <cidr>, because the proxy sees each client's real address (Step 10).- Do not change the
admin,app,rocketmq-proxyorrocketmq-dashboardusers' type, and keeprocketmq-proxyandrocketmq-dashboardas super users, because the proxy and the Dashboard log in with them.
Send a test message
On the instance, /usr/local/lib/sac/rocketmq-grpc-probe.py sends one message over the same TLS port your clients use, as the app user. This is the self-test's client, and it uses the Python standard library only. It reads the secret from the credentials file:
H=$(sudo sed -n 's/^ROCKETMQ_GRPC_ENDPOINT=\(.*\):8081$/\1/p' /root/rocketmq-credentials.txt) printf '{"order": 1001, "status": "CREATED"}' > /tmp/order.json
sudo python3 -I /usr/local/lib/sac/rocketmq-grpc-probe.py send "$H" --addr 127.0.0.1 \
--creds /root/rocketmq-credentials.txt --topic orders --tag created --key order-1001 --body-file /tmp/order.json
sudo python3 -I /usr/local/lib/sac/rocketmq-grpc-probe.py route "$H" --addr 127.0.0.1 \
--creds /root/rocketmq-credentials.txt --topic sac-denied --expect-code 40100 rm -f /tmp/order.jsonGRPC send status=20000 message=OK message_id=<message-id> GRPC route status=40100 message=User:app has no permission to access Topic:sac-denied from 127.0.0.1, the decision is deny. queues=0The message is now on the Message page under the key order-1001.
Connect your applications over TLS
Applications connect with a RocketMQ 5 client SDK to ROCKETMQ_GRPC_ENDPOINT (<public-dns>:8081) with TLS on, using the app access key and secret (or a user of their own, Step 6). The proxy answers with routes for the same address and port, so it works with any name in the certificate, including your own DNS name (Step 11). Clients that use the older RocketMQ remoting protocol (DefaultMQProducer with a NameServer address) are not served off the instance, so use the RocketMQ 5 SDKs.
First, check the certificate. Copy the public certificate over SSH, then check its fingerprint against ROCKETMQ_TLS_CERT_SHA256 from the credentials file before you trust it:
scp -i <your-key.pem> ubuntu@<public-ip>:/etc/sac/rocketmq-broker.pem ./rocketmq-broker.pem openssl x509 -in rocketmq-broker.pem -noout -fingerprint -sha256 openssl s_client -connect <public-dns>:8081 -servername <public-dns> -alpn h2 </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256Both fingerprints must equal ROCKETMQ_TLS_CERT_SHA256. Put the endpoint and the credentials in a file readable only by the application's user, never on a command line or in the source code:
install -m 0600 /dev/null ~/rocketmq-client.env
# copy these lines from /root/rocketmq-credentials.txt on the instance:
# ROCKETMQ_GRPC_ENDPOINT=... ROCKETMQ_APP_ACCESS_KEY=... ROCKETMQ_APP_SECRET_KEY=...Python (the official SDK, pip install rocketmq-python-client==5.1.2). The SDK asks gRPC for its default trust roots; the example gives it this instance's certificate instead, so only this program trusts it. It publishes a message and consumes it back:
import os, sys, time, uuid creds = dict(l.strip().split("=", 1) for l in open(os.path.expanduser("~/rocketmq-client.env")) if "=" in l and not l.startswith("#")) import grpc pinned = open("rocketmq-broker.pem", "rb").read()
# this application's own trust file _creds = grpc.ssl_channel_credentials grpc.ssl_channel_credentials = lambda root_certificates=None, private_key=None, certificate_chain=None: \
_creds(pinned, private_key, certificate_chain) from rocketmq import ClientConfiguration, Credentials, FilterExpression, Message, Producer, SimpleConsumer config = ClientConfiguration(creds["ROCKETMQ_GRPC_ENDPOINT"], Credentials(creds["ROCKETMQ_APP_ACCESS_KEY"], creds["ROCKETMQ_APP_SECRET_KEY"])) body = ("hello from %s" % uuid.uuid4().hex[:8]).encode() producer = Producer(config, ("orders",), tls_enable=True) producer.startup() msg = Message(); msg.topic = "orders"; msg.tag = "example"; msg.body = body print("sent", producer.send(msg).message_id) producer.shutdown() consumer = SimpleConsumer(config, "orders-example", {"orders": FilterExpression("example")}, await_duration=5, tls_enable=True) consumer.startup() time.sleep(5) for m in consumer.receive(16, 15) or []: consumer.ack(m) print("received", m.body.decode()) consumer.shutdown()sent 0112FFCF6E1DB707820AF47E4E00000000 received hello from 85e9adcbWithout the pinned certificate, the same program refuses the server (failed to fetch topic route, with CERTIFICATE_VERIFY_FAILED in its log). A wrong secret is refused with check signature failed.
Java and other SDKs. Enable TLS in the client configuration (Java: ClientConfiguration.newBuilder().setEndpoints("<public-dns>:8081").enableSsl(true).setCredentialProvider(new StaticSessionCredentialsProvider(accessKey, secretKey)), reading the key and secret from your secret store).
Be aware that the RocketMQ 5 Java SDK does not verify the server certificate at all, because it uses an insecure trust manager. With it, TLS encrypts the traffic but does not prove which server you reached. Restrict TCP 8081 to your application networks, and check the fingerprint with openssl s_client as above.
Other SDKs that use gRPC's default trust roots behave like the Python SDK. Give them the pinned certificate, or install a CA-issued certificate (Step 11).
Security checks
rocketmq-selftest re-proves the whole appliance with this instance's credentials. It checks:
- The exact listening set and the loopback-only ports
- A TLS round trip as the app user, after which the message is found in the broker
- Refusal of a wrong secret, an anonymous client, the distribution's sample user and a denied topic
- Refusal of cleartext gRPC and of a client expecting another host name
- The broker's refusal of anonymous and sample-user administration
- The Dashboard's login wall and the redirect
- Refusal of other host names, foreign origins, WebSocket upgrades and
;paths - The cross-site guard, the instance metadata block, and the certificate on 443 and 8081
Run it with:
sudo rocketmq-selftestApache RocketMQ 5.5.1 appliance self-test (gRPC over TLS <public-dns>:8081, Dashboard https://<public-dns>/) [ok] listening set: 22, 80, 443, 8081 public; 9876, 10909, 10911, 8082 on 127.0.0.1; 10912/18080/18081 refuse <private-ip> (loopback control connects) [ok] TLS 8081: ALPN h2, the certificate pinned (SHA-256 = ROCKETMQ_TLS_CERT_SHA256), hostname <public-dns> checked [ok] app user QueryRoute over TLS: status 20000 (queues=4) [ok] wrong secret refused over TLS (40100, the signature check) [ok] anonymous request refused over TLS (40100, no username) [ok] the distribution's sample user rocketmq2 / 12345678 does not exist (40100) [ok] authorization: app denied Topic:sac-denied (40100; the proxy saw the client as <private-ip>, from the socket via the PROXY header) [ok] round trip: app SendMessage over TLS -> message <message-id> stored in the broker (found by key sac-st-<random> as admin) [ok] authorization: app SendMessage to Topic:sac-denied refused (40100, decision deny) [ok] cleartext gRPC on 8081 refused ((0 bytes back, no HTTP/2 frame)) [ok] the certificate is checked: a client expecting another host name refuses it [ok] remoting (127.0.0.1): admin clusterList OK; app cannot create a topic; anonymous and rocketmq2/12345678 refused by the broker [ok] Dashboard: anonymous API -> 302 to its login (/proxy/ too); wrong password refused; login OK (Secure session cookie); cluster listed; /actuator and /test/ 404 [ok] front door: plain HTTP -> 301 https://<public-dns>/; unknown Host -> 444; foreign Origin 403; WebSocket 403; ';' 400; CONNECT refused [ok] cross-site GET guard: 13/13 (/rocketmq/nsaddr.query) [ok] cross-site GET guard: 13/13 (/ops/homePage.query) [ok] cross-site GET guard: 13/13 (/cluster/list.query) [ok] cross-site GET guard: 13/13 (/topic/list.query) [ok] instance metadata refused inside the namesrv, broker, proxy, Dashboard and nginx cgroups (loopback control 200); the RocketMQ units reach nothing off-host [ok] TLS certificate: end-entity (CA:FALSE, serverAuth, no certificate signing), names <public-dns>; served on 443 and 8081; SHA-256 <sha256-fingerprint> SELFTEST OK - RocketMQ over TLS with ACL 2.0 (app round trip; wrong secret, anonymous, sample user and denied topic refused), loopback-only broker/NameServer/proxy, Dashboard login wall, origin and cross-site guards, exact listening set, metadata block verified.The instance metadata block and the loopback-only services
The NameServer, the broker, the proxy and the Dashboard may exchange packets with the loopback address only (IPAddressAllow=localhost, IPAddressDeny=any), so they can neither be reached from, nor reach, any other address, the instance metadata service (169.254.169.254) included. nginx and the boot service are denied the metadata service.
The only service allowed to reach the metadata service is rocketmq-metadata-names. It runs once at boot, reads the instance's four host names and addresses (no credentials) for the certificate and the endpoint, and can reach nothing else:
for u in rocketmq-namesrv rocketmq-broker rocketmq-proxy rocketmq-dashboard nginx rocketmq-firstboot rocketmq-metadata-names; do printf '%s: deny=%s allow=%s\n' $u "$(systemctl show -p IPAddressDeny --value $u.service)" "$(systemctl show -p IPAddressAllow --value $u.service)"; donerocketmq-namesrv: deny=::/0 0.0.0.0/0 allow=127.0.0.0/8 ::1/128 rocketmq-broker: deny=::/0 0.0.0.0/0 allow=127.0.0.0/8 ::1/128 rocketmq-proxy: deny=::/0 0.0.0.0/0 allow=127.0.0.0/8 ::1/128 rocketmq-dashboard: deny=::/0 0.0.0.0/0 allow=127.0.0.0/8 ::1/128 nginx: deny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128 allow= rocketmq-firstboot: deny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128 allow= rocketmq-metadata-names: deny=::/0 0.0.0.0/0 allow=169.254.169.254/32 fd00:ec2::254/128Clients reach the proxy through nginx, which terminates TLS on 8081 and passes the connection on with the client's real address in a PROXY protocol header. The proxy uses that address in its logs and in policies limited to source addresses (Step 6); a client cannot supply its own.
As a consequence of the block, RocketMQ cannot use the instance's IAM role, and nothing in this image needs it.
Your own DNS name and a CA-issued certificate
Point a DNS record at the instance, then tell the appliance to serve that name. This updates nginx, issues a new self-signed end-entity certificate naming it (for both 443 and 8081), accepts https://<name> as the Dashboard's origin, and updates the endpoint, URL and fingerprint in the credentials file:
sudo rocketmq-set-hostname rocketmq.<your-domain>The name is saved in /etc/sac/rocketmq-hostname and survives reboots.
For a certificate clients trust without pinning, install one from a certificate authority (your own CA, or Let's Encrypt). The chain file holds the server certificate first, followed by any intermediates. The key is PEM and unencrypted:
sudo rocketmq-install-cert /path/to/fullchain.pem /path/to/privkey.pem rocketmq.<your-domain>The rocketmq-install-cert command checks that the key matches the certificate and that the certificate covers the name. It then installs the certificate for nginx on 443 and 8081 and reloads nginx. The boot-time renewal never replaces a certificate installed this way, even if the instance's address changes. Running rocketmq-set-hostname <name> returns to a self-signed certificate.
Versions, configuration and file locations
ls /opt/rocketmq /opt/rocketmq-dashboard sha256sum /opt/rocketmq/current/LICENSE /opt/rocketmq-dashboard/2.1.0/LICENSE /usr/lib/jvm/java-17-openjdk-amd64/bin/java -version 2>&1 | head -1/opt/rocketmq: 5.5.1 current /opt/rocketmq-dashboard: 2.1.0 0bc6664f53f3cad2a55980d8b91871dd8ba4caaeea0f23225c076b417986a35b /opt/rocketmq/current/LICENSE 3c45d82fe86d0e6982bde4a940b936cb3141e160f9a0b7e69dc4bf10953ff657 /opt/rocketmq-dashboard/2.1.0/LICENSE openjdk version "17.0.20.1" 2026-08-18Path What it is
/var/lib/rocketmq/store/ the broker's store: commit log, consume queues, topic and group configuration, and the users and policies (config/users, config/acls)
/etc/rocketmq/broker.conf, /etc/rocketmq/namesrv.conf broker and NameServer configuration (restart the service after a change; the configuration check refuses unsafe values)
/etc/rocketmq/rmq-proxy.json the proxy's configuration, including its own user's secret (root and the rocketmq group only)
/etc/rocketmq-dashboard/application.yml, /var/lib/rocketmq-dashboard/data/users.properties the Dashboard's configuration (its ACL identity) and its login
/root/rocketmq-credentials.txt the endpoint, the app and admin users, the Dashboard login and the certificate fingerprint (root only)
/etc/sac/rocketmq-broker.pem the public certificate for clients to pin
/etc/nginx/rocketmq-stream.conf, /etc/nginx/sites-available/sac-rocketmq the TLS front doors (8081 and 443); certificate and key in /etc/nginx/ssl/
/var/lib/rocketmq/logs/rocketmqlogs/, journalctl -u rocketmq-broker broker, proxy and NameServer logs (also rocketmq-proxy, rocketmq-namesrv, rocketmq-dashboard, nginx)
Backup and maintenance
- Back up
/var/lib/rocketmq/storewith the broker stopped (sudo systemctl stop rocketmq-proxy rocketmq-broker), together with/etc/rocketmq,/etc/rocketmq-dashboard,/var/lib/rocketmq-dashboard/data,/etc/sac,/etc/nginx/ssland the credentials file. The users and their secrets are inside the store. - The broker removes commit log files older than 48 hours at 04:00 by default (
fileReservedTimeanddeleteWhenin/etc/rocketmq/broker.conf) and refuses new messages when the disk is nearly full. Size the root volume for your retention, or grow it. The file system grows with the volume after a reboot. - The JVMs are sized for an m5.large: NameServer 512 MB, broker 1 GB heap plus 1 GB direct memory, proxy 512 MB, Dashboard 512 MB. On a larger instance, raise
-Xms/-Xmxin a drop-in (sudo systemctl edit rocketmq-broker, overrideExecStart) and restart. - Ubuntu security updates install automatically (unattended-upgrades), including the OpenJDK runtime. RocketMQ itself lives in
/opt/rocketmq. To upgrade, launch the newer version from the listing and move your producers and consumers across.
Security recommendations
- Limit TCP 8081 in the security group to the networks your applications connect from, and TCP 443 and 22 to your admin network.
- Give each
application its own user with policies for its own topics and groups only (Step 6), instead of sharing app. Keepadminon the instance. - Serve RocketMQ under your own DNS name with a certificate from a trusted CA (Step 11). Until then, check the self-signed certificate's fingerprint (Step 4) and pin it per client (Step 8) rather than adding it to a trust store.
- Change the
appsecret if you hand the credentials file around (updateUser, Step 6), and give other people their own Dashboard logins only if they administer RocketMQ. - Keep the NameServer and the broker on the loopback address, because they have no TLS and the NameServer has no authentication.
Support and licensing
SecureAnyCloud provides 24/7 technical support for this image by email and live chat: sales@secureanycloud.com.
Apache RocketMQ and the RocketMQ Dashboard are licensed under the Apache License 2.0. Their LICENSE and NOTICE files are on the instance in /opt/rocketmq/current and /opt/rocketmq-dashboard/2.1.0. OpenJDK is licensed under the GNU General Public License version 2 with the Classpath Exception, and nginx under the 2-clause BSD licence.
Apache RocketMQ, RocketMQ and Apache are trademarks of the Apache Software Foundation. SecureAnyCloud is not affiliated with or endorsed by the Apache Software Foundation.
Deploy on AWS
Launch Apache RocketMQ 5.5.1 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