Apache Qpid Broker-J 10.1.1
Overview
This guide shows you how to launch the Apache Qpid Broker-J 10.1.1 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one software version of the SecureAnyCloud streaming and messaging listing on AWS Marketplace. You choose it when you subscribe and launch.
Apache Qpid Broker-J is a pure Java message broker that speaks every version of AMQP: 0-8, 0-9, 0-9-1, 0-10 and 1.0. Applications built on RabbitMQ client libraries (AMQP 0-9-1), on Qpid JMS or Apache ActiveMQ Artemis clients (AMQP 1.0) and on the older Qpid clients (AMQP 0-10) can all share one broker. It keeps durable queues and messages in a Berkeley DB store. It supports exchanges and bindings, priority, LVQ and sorted queues, message groups, transactions and flow control. It also ships a web management console and a REST API for everything.
What you get:
- AMQP off the instance only over TLS. The only AMQP listener reachable from other machines is AMQPS on port 5671 (TLS 1.2 or 1.3). Plain AMQP on port 5672 listens on
127.0.0.1only, for tools on the instance itself. It refuses the clear-text PLAIN mechanism and accepts only SCRAM-SHA-256, so a password is never sent unencrypted. - No default login, no shared secret. The stock Broker-J configuration ships a
guest/guestuser. This image ships neither that user nor an anonymous login. The admin password, the keystore password and the TLS private key are generated on your instance at first boot. The image contains only a configuration template with empty fields, and the broker will not start until first boot has filled them in. - Passwords stored as SCRAM-SHA-256 hashes. The broker's single authentication provider is SCRAM-SHA-256. The admin password, and every user you add, is stored only as a salted hash (32768 iterations), never in clear text.
- HTTPS from the first boot. nginx serves the web management console and the REST API on port 443. Port 80 redirects to HTTPS, and requests for host names the instance does not serve are dropped. The same certificate secures AMQPS on 5671. It is an end-entity certificate, so it can vouch only for this instance's own names and can never sign other certificates. You can install your own CA-issued certificate with one command (Step 10), and the boot-time renewal never replaces it.
- A guarded console. A request carrying another site's
Originis refused, and so is every WebSocket upgrade. Console logins are rate-limited. Broker-J performs a few management actions on a plain GET request, such as logging out, restarting or shutting down the broker, and resetting statistics. These go through only when the browser proves the request comes from the console itself, so a link or hidden image on another site cannot trigger them with your login. The Prometheus/metricsendpoint, open by default in Broker-J, requires a login. - Fail closed. The broker starts only after the boot service has written your secrets. A configuration check refuses to start it with an unfilled template value, a clear-text password, a
guestuser, PLAIN allowed without TLS, or a plaintext AMQP port on a public address. - Hardened defaults. The broker, nginx and the boot service are blocked from the instance metadata service. The one small service that reads the instance's own host names may reach nothing else. The AMI requires IMDSv2. nginx hands the broker the real client address and the configured host name, never values a client sends. The broker runs under systemd sandboxing as an unprivileged user, and the JVM never writes a heap dump.
- Fully patched. Ubuntu 24.04 LTS is fully patched at build time, with unattended security upgrades switched on.
- On the image: Apache Qpid Broker-J 10.1.1 (the official Apache binary release, verified against its published SHA-512 digest and its release signature), OpenJDK 17 (from Ubuntu 24.04), nginx 1.24 (from Ubuntu 24.04), python3-pika 1.2.0 (an AMQP 0-9-1 client used by the self-test and the examples), cloud-init and the AWS Systems Manager agent.
- Default user:
ubuntu - Architecture: x86_64
- Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing
- An EC2 key pair
- 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 5671 (AMQPS) from the networks your applications connect from, and TCP 443 (the web management console and REST API) from your admin network
- Optionally, TCP 80, if you want plain HTTP requests redirected to HTTPS
Never open 5672 or 8080, because they listen on the loopback address only.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick Apache Qpid Broker-J 10.1.1 on Ubuntu 24.04 as the software version, choose your Region, then choose Launch through EC2. Select m5.large, your key pair and the security group described above.
Or launch with the AWS CLI. 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=qpid-broker-j}]'First boot takes under a minute after the instance is running. The boot service generates the secrets, the certificate and the keystore, and writes the broker configuration. Then the broker and nginx start.
Connect to your instance
Connect over SSH as the ubuntu user of the Apache Qpid Broker-J 10.1.1 on Ubuntu 24.04 image:
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
systemctl is-active qpid-metadata-names qpid-broker-j-firstboot qpid nginx
sudo test -f /var/lib/sac/data/qpid-broker-j-firstboot.done && echo FIRSTBOOT_DONEAll four units are active and the first boot marker is present:
active active active active FIRSTBOOT_DONEOnly SSH, nginx and AMQPS listen on network ports. Plain AMQP (5672) and the broker's own management port (8080) listen on the loopback address:
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*:5671 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")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx")) [::ffff:127.0.0.1]:5672 users:(("java")) [::ffff:127.0.0.1]:8080 users:(("java"))Get your URLs, admin password and certificate fingerprint
sudo cat /root/qpid-broker-j-credentials.txtThe file is readable by root only:
# Apache Qpid Broker-J 10.1.1 on Ubuntu 24.04 - generated on first boot by qpid-broker-j-firstboot.service.
# The admin password is unique to this instance; none was baked into the image. Keep this file secret.
# The broker stores it only as a salted SCRAM-SHA-256 hash. Clients: AMQPS (TLS) on port 5671 with SCRAM-SHA-256 or
# PLAIN; the web management console and REST API on https port 443. The certificate is self signed (minted on this
# instance): check that the SHA-256 fingerprint your client sees matches QPID_TLS_CERT_SHA256 below, then pin
# /etc/sac/qpid-broker.pem in that client's OWN truststore - or install a CA-issued certificate with # sudo qpid-install-cert <chain.pem> <key.pem> # Change the served name:
sudo qpid-broker-j-set-hostname <dns-name> Re-verify:
sudo qpid-broker-j-selftest QPID_ADMIN_USER=admin QPID_ADMIN_PASSWORD=<QPID_ADMIN_PASSWORD> QPID_CONSOLE_URL=https://<public-ip>/ QPID_AMQPS_URL=amqps://<public-ip>:5671 QPID_AMQPS_HOST=<public-ip> QPID_AMQPS_PORT=5671 QPID_VIRTUALHOST=default QPID_TLS_CERT_SHA256=<sha256-fingerprint> QPID_TLS_CERT_FILE=/etc/sac/qpid-broker.pem
# AMQP 127.0.0.1:5672 (plain TCP, on this instance only) accepts SCRAM-SHA-256 only, never PLAIN.
# curl config with the admin login for the REST API:
sudo curl -K /root/qpid-curl.conf https://<host>/api/latest/broker
# User guide: https://secureanycloud.com/stacks/apache-qpid-broker-j-10-1-1/The host is the instance's public IP address from the EC2 instance metadata (the private address when the instance has no public one). The certificate also names the public DNS name, the private IP address and the private DNS name. If you stop and start the instance without an Elastic IP, the boot service picks up the new address and issues a new certificate for it, unless you installed your own (Step 10). To use your own DNS name, see Step 10.
Print the certificate's SHA-256 fingerprint and its names:
sudo openssl x509 -in /etc/sac/qpid-broker.pem -noout -fingerprint -sha256 openssl x509 -in /etc/sac/qpid-broker.pem -noout -ext subjectAltName,basicConstraintssha256 Fingerprint=<sha256-fingerprint> X509v3 Subject Alternative Name: IP Address:<public-ip>, DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, 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, compare the SHA-256 fingerprint that the client sees with QPID_TLS_CERT_SHA256 in the credentials file (read over SSH, as above). Then pin it in that client's own truststore only: a CA file or truststore file that only this application uses, as in Step 7. 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 10).
The web management console
Open https://<public-ip>/ 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 QPID_ADMIN_PASSWORD. The console logs in with SCRAM-SHA-256, so your password never crosses the wire, even inside TLS.
The Broker tab (shown at the top of this guide) lists the virtual host default and the three ports. Double-click the virtual host to manage its exchanges, queues, connections and access control. Use Add Queue and Add Exchange to create them. To empty or remove a queue, select it and choose Clear Queue or Delete Queue:
Double-click a queue for its attributes, statistics, bindings and consumers, and to browse, move or delete its messages:
Under authenticationproviders, scramProvider lists the users. Choose Add User to create one. Its password is stored as a SCRAM-SHA-256 hash:
The REST API
Everything in the console is available through the REST API under /api/latest, with HTTP Basic authentication over HTTPS. Without a login it answers 401. On the instance, /root/qpid-curl.conf holds the admin login for curl (-K), so the password never appears on a command line. The --cacert option pins this broker's certificate:
curl -s -o /dev/null -w '%{http_code}\n' --cacert /etc/sac/qpid-broker.pem https://127.0.0.1/api/latest/broker
sudo curl -s --cacert /etc/sac/qpid-broker.pem -K /root/qpid-curl.conf https://127.0.0.1/api/latest/broker \
| jq -r '"\(.name) \(.productVersion) model \(.modelVersion)"'
sudo curl -s --cacert /etc/sac/qpid-broker.pem -K /root/qpid-curl.conf "https://127.0.0.1/api/latest/port?depth=0" \
| jq -r '.[] | "\(.name) port=\(.port) bind=\(.bindingAddress // "*") transports=\(.transports | join(","))"'
sudo curl -s --cacert /etc/sac/qpid-broker.pem -K /root/qpid-curl.conf https://127.0.0.1/api/latest/authenticationprovider \
| jq -r '.[] | "\(.name) type=\(.type) TLS-only=\(.secureOnlyMechanisms | join(","))"'401 sac 10.1.1 model 9.1 AMQPS port=5671 bind=* transports=SSL HTTP port=8080 bind=127.0.0.1 transports=TCP AMQP-LOCAL port=5672 bind=127.0.0.1 transports=TCP scramProvider type=SCRAM-SHA-256 TLS-only=PLAINTLS-only=PLAIN means the PLAIN mechanism is offered only on TLS connections. Create a durable queue, a direct exchange and a binding between them (201 created, 200 for the bind operation):
Q=(--cacert /etc/sac/qpid-broker.pem -K /root/qpid-curl.conf -s -o /dev/null -w '%{http_code}\n' -H 'Content-Type: application/json') B=https://127.0.0.1/api/latest
sudo curl "${Q[@]}" -X PUT -d '{"durable": true}' "$B/queue/default/default/orders"
sudo curl "${Q[@]}" -X PUT -d '{"type": "direct", "durable": true}' "$B/exchange/default/default/orders.events"
sudo curl "${Q[@]}" -X POST -d '{"destination": "orders", "bindingKey": "order.created"}' "$B/exchange/default/default/orders.events/bind"201 201 200Create an application user app1 with a password generated on the instance. The password goes into a file readable by root only and reaches the API in a request body file, never on a command line:
T=$(mktemp -d -p /dev/shm); chmod 700 "$T" openssl rand -hex 16 | tr -d '\n' > "$T/pw" python3 -c 'import json,sys; print(json.dumps({"name": "app1", "password": open(sys.argv[1]).read()}))' "$T/pw" > "$T/user.json"
sudo curl --cacert /etc/sac/qpid-broker.pem -K /root/qpid-curl.conf -s -o /dev/null -w '%{http_code}\n' \
-H 'Content-Type: application/json' -X POST -d @"$T/user.json" https://127.0.0.1/api/latest/user/scramProvider
sudo install -m 0600 "$T/pw" /root/qpid-app1-password.txt rm -rf "$T"
sudo curl -s --cacert /etc/sac/qpid-broker.pem -K /root/qpid-curl.conf https://127.0.0.1/api/latest/user/scramProvider | jq -r '.[].name'201 admin app1Notes:
- From another machine, use
https://<public-ip>/api/latest/...with your own login (curl -uputs the password on the command line, so prefer a curl config file such as/root/qpid-curl.conf). Pin the certificate with--cacert qpid-broker.pem. - State-changing management calls that Broker-J accepts as a plain GET (for example
/api/latest/broker/restart,/api/latest/broker/performGC,/api/latest/port/<name>/updateTLS, the BDB*Statistics?reset=trueoperations and/logout) need the headerSec-Fetch-Site: same-originwhen you call them outside a browser. Use POST for operations wherever the API allows it. - HTTP Basic requests are limited to 120 a minute per client address (burst 60), and console logins to 10 a minute. A request beyond that limit is answered with 429.
- nginx refuses (400) a URL whose path contains
;or an encoded/,.,\or NUL. A queue or exchange whose name contains/cannot be addressed through the console or REST API. Use other separators, such as..
To change the admin password, run the block below. It reads the new password without echoing it and sets it through the REST API, where the broker stores its SCRAM-SHA-256 hash. It also writes the password into the credentials file and the curl config. Everything goes through standard input, never the command line:
read -rsp 'New Broker-J admin password: ' P; echo printf '%s' "$P" | sudo python3 -I -c ' import base64, json, re, ssl, sys, urllib.request new = sys.stdin.read() cf = "/root/qpid-broker-j-credentials.txt"; c = open(cf).read() old = re.search(r"(?m)^QPID_ADMIN_PASSWORD=(.*)$", c).group(1) req = urllib.request.Request("https://127.0.0.1/api/latest/user/scramProvider/admin", method="PUT", data=json.dumps({"password": new}).encode(), headers={"Content-Type": "application/json", "Authorization": "Basic " + base64.b64encode(("admin:" + old).encode()).decode()}) urllib.request.urlopen(req, context=ssl.create_default_context(cafile="/etc/sac/qpid-broker.pem")) open(cf, "w").write(re.sub(r"(?m)^QPID_ADMIN_PASSWORD=.*$", lambda m: "QPID_ADMIN_PASSWORD=" + new, c)) k = "/root/qpid-curl.conf"; kc = open(k).read() open(k, "w").write(re.sub(r"(?m)^user = .*$", lambda m: "user = \"admin:" + new + "\"", kc)) print("admin password changed")' unset PConnect an AMQP client over AMQPS
On the instance, python3-pika is installed. This example publishes three JSON messages to the orders.events exchange and consumes them from the orders queue over AMQPS. It reads the password from the credentials file (never the command line), trusts only this broker's certificate and checks the host name:
sudo python3 - <<'PY' import json, ssl, pika creds = dict(l.strip().split("=", 1) for l in open("/root/qpid-broker-j-credentials.txt") if "=" in l and not l.startswith("#")) host = creds["QPID_AMQPS_HOST"] tls = ssl.create_default_context(cafile=creds["QPID_TLS_CERT_FILE"])
# trust THIS broker's certificate only params = pika.ConnectionParameters("127.0.0.1", 5671, "default", pika.PlainCredentials("admin", creds["QPID_ADMIN_PASSWORD"]), ssl_options=pika.SSLOptions(tls, host)) conn = pika.BlockingConnection(params) ch = conn.channel() for i in range(1, 4): ch.basic_publish("orders.events", "order.created", json.dumps({"order": 1000 + i, "status": "CREATED"}).encode(), pika.BasicProperties(content_type="application/json", delivery_mode=2)) print("published 3 messages to exchange orders.events (routing key order.created)") while True: method, props, body = ch.basic_get("orders", auto_ack=True) if method is None: break print("consumed from orders:", body.decode()) conn.close() PYpublished 3 messages to exchange orders.events (routing key order.created) consumed from orders: {"order": 1001, "status": "CREATED"} consumed from orders: {"order": 1002, "status": "CREATED"} consumed from orders: {"order": 1003, "status": "CREATED"}The new user app1 connects over AMQPS. The same password with PLAIN on the plaintext loopback port is refused, because the broker offers PLAIN only inside TLS:
sudo python3 - <<'PY' import ssl, pika creds = dict(l.strip().split("=", 1) for l in open("/root/qpid-broker-j-credentials.txt") if "=" in l and not l.startswith("#")) host, pw = creds["QPID_AMQPS_HOST"], open("/root/qpid-app1-password.txt").read().strip() tls = ssl.create_default_context(cafile=creds["QPID_TLS_CERT_FILE"]) conn = pika.BlockingConnection(pika.ConnectionParameters("127.0.0.1", 5671, "default", pika.PlainCredentials("app1", pw), ssl_options=pika.SSLOptions(tls, host))) print("app1 over AMQPS 5671:", "connected" if conn.is_open else "closed"); conn.close() try: pika.BlockingConnection(pika.ConnectionParameters("127.0.0.1", 5672, "default", pika.PlainCredentials("app1", pw))) except pika.exceptions.AuthenticationError as e: print("app1 with PLAIN on plaintext 127.0.0.1:5672: refused (" + repr(e).split(": ", 1)[1] + ")") PYapp1 over AMQPS 5671: connected app1 with PLAIN on plaintext 127.0.0.1:5672: refused (Server and client could not negotiate use of the PLAIN authentication mechanism)From your own machine. Copy the public certificate over SSH, then check its fingerprint against QPID_TLS_CERT_SHA256 from the credentials file before you trust it:
scp -i <your-key.pem> ubuntu@<public-ip>:/etc/sac/qpid-broker.pem ./qpid-broker.pem openssl x509 -in qpid-broker.pem -noout -fingerprint -sha256 openssl s_client -connect <public-ip>:5671 -servername <public-ip> </dev/null 2>/dev/null | openssl x509 -noout -fingerprint -sha256Both fingerprints must equal QPID_TLS_CERT_SHA256. Then pin the file in the client's own trust configuration:
- Python, AMQP 0-9-1 (pika):
ssl.create_default_context(cafile="qpid-broker.pem")andpika.SSLOptions(context, "<public-ip>"), connecting to<public-ip>:5671, virtual hostdefault, as in the example above. - Python, AMQP 1.0 (python-qpid-proton):
SSLDomain(SSLDomain.MODE_CLIENT)withset_trusted_ca_db("qpid-broker.pem")andset_peer_authentication(SSLDomain.VERIFY_PEER_NAME), URLamqps://<public-dns-name>:5671. Use the instance's public DNS name, which is in the certificate, because proton's host name check does not match IP addresses. - Java, Qpid JMS (AMQP 1.0): import the certificate into a truststore file used by that application only, then reference it in the connection URL. Read the truststore password from your secret store rather than typing it on the command line:
keytool -importcert -noprompt -alias qpid-broker -file qpid-broker.pem \
-keystore qpid-client-truststore.p12 -storetype PKCS12 -storepass:env QPID_TRUSTSTORE_PASSWORDamqps://<public-dns-name>:5671?transport.trustStoreLocation=/path/to/qpid-client-truststore.p12&transport.trustStorePassword=${QPID_TRUSTSTORE_PASSWORD}&amqp.vhost=defaultQpid JMS logs in with SCRAM-SHA-256 when the broker offers it. The truststore pins this broker's certificate for that application only. Never import it into the JVM's cacerts. With a CA-issued certificate (Step 10) none of this is needed.
Security checks
qpid-broker-j-selftest re-proves the whole appliance with this instance's credentials: the exact listening set, an AMQPS round trip with the pinned certificate, refusal of a wrong password, refusal of PLAIN on the plaintext loopback port and the mechanisms each port offers, the REST API's refusal of anonymous requests and wrong passwords, /metrics requiring a login, the redirect, refusal of other host names, cross-origin requests, WebSocket upgrades and ; path parameters, the metadata block inside the broker and nginx, that the certificate served on 443 and 5671 is this instance's end-entity certificate, and the cross-site guard on the state-changing GET routes (a same-origin request passes; cross-site, same-site, links opened from outside the browser and requests with no browser signal at all are refused):
sudo qpid-broker-j-selftestApache Qpid Broker-J appliance self-test (https://<public-ip>/ amqps://<public-ip>:5671) [ok] listening set: 22, 80, 443, 5671 public; AMQP 5672 and management 8080 on 127.0.0.1 only [ok] AMQPS_RT_OK queue sac.selftest.84edb42e7b message sac-rt-1acad857 via TLS 127.0.0.1:5671 (certificate pinned, hostname <public-ip> checked) [ok] AMQPS_WRONGPW_REFUSED (broker reply code 530: the authentication was refused) [ok] PLAIN_REFUSED_ON_5672 (the broker offers no PLAIN on a non-TLS port) [ok] MECHS_5672 SCRAM-SHA-256 (127.0.0.1:5672) [ok] MECHS_5671 PLAIN SCRAM-SHA-256 (TLS) [ok] HTTPS console/REST: anonymous 401, wrong password 401, admin 200 (Broker-J 10.1.1, certificate pinned); /metrics 401; console login SCRAM-SHA-256 [ok] front door: plain HTTP -> 301 https://<public-ip>/; unknown Host -> 444; foreign Origin 403 (own origin 200); WebSocket 403; ';' 400; CONNECT refused [ok] instance metadata refused inside the qpid and nginx cgroups (loopback control 200) [ok] TLS certificate: end-entity (CA:FALSE, serverAuth, no certificate signing), names <public-ip>; served on 443 and 5671; SHA-256 <sha256-fingerprint> [ok] cross-site GET guard: 13/13 (/logout) [ok] cross-site GET guard: 13/13 (/api/latest/broker/performGC) [ok] cross-site GET guard: 13/13 (/api/latest/broker/compactMemory) [ok] cross-site GET guard: 13/13 (/api/latest/broker/getThreadStackTraces) [ok] cross-site GET guard: 13/13 (/api/latest/port/AMQPS/updateTLS) [ok] cross-site GET guard: 13/13 (/api/latest/virtualhost/default/default/environmentStatistics) [ok] cross-site GET guard: 13/13 (/api/latest/virtualhost/default/default/transactionStatistics) SELFTEST OK - AMQPS round trip with the pinned certificate, wrong password and plaintext PLAIN refused, HTTPS console/REST auth wall, origin and cross-site guards, exact listening set, metadata block verified.The instance metadata block
The broker, nginx and the boot service are denied the instance metadata service (169.254.169.254) by a systemd IPAddressDeny rule, so nothing a client sends to the broker or the console can ever reach the instance's credentials. The only service allowed to reach the metadata service is qpid-metadata-names, which runs once at boot, reads the instance's four host names and addresses (no credentials) for the certificate, and may reach nothing else:
for u in qpid nginx qpid-broker-j-firstboot qpid-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)"; doneqpid: deny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 allow= nginx: deny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 allow= qpid-broker-j-firstboot: deny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 allow= qpid-metadata-names: deny=0.0.0.0/0 ::/0 allow=fd00:ec2::254/128 169.254.169.254/32Consequence: the broker cannot use the instance's IAM role. Broker-J does not need it for anything in this image.
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 that names it, and rebuilds the broker's keystore so AMQPS on 5671 presents it too. It also accepts https://<name> as the console's origin and updates the URLs and the fingerprint in the credentials file. The broker restarts to pick up the new certificate:
sudo qpid-broker-j-set-hostname qpid.<your-domain>The name is saved in /etc/sac/qpid-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, then any intermediates; the key is PEM and unencrypted:
sudo qpid-install-cert /path/to/fullchain.pem /path/to/privkey.pem qpid.<your-domain>qpid-install-cert checks that the key matches the certificate and that the certificate covers the name, installs it for nginx (443) and rebuilds the broker's PKCS#12 keystore from it (5671) with this instance's keystore password, then restarts the broker and reloads nginx. The boot-time renewal never replaces a certificate installed this way, even if the instance's address changes. Running qpid-broker-j-set-hostname again goes back to a self-signed certificate. Renew a CA certificate by running qpid-install-cert again with the new files.
Versions, configuration and file locations
ls /opt/qpid/qpid-broker sha256sum /opt/qpid/current/LICENSE /usr/lib/jvm/java-17-openjdk-amd64/bin/java -version 2>&1 | head -1 grep -o 'QPID_JAVA_MEM=.*' /etc/default/qpid10.1.1 ec0fe3860f124961a235cf05710947277a97de6c18243e867b3b18501317a3f0 /opt/qpid/current/LICENSE openjdk version "17.0.20.1" 2026-08-18 QPID_JAVA_MEM="-Xms256m -Xmx1536m -XX:MaxDirectMemorySize=1536m"Key files and commands:
- /var/lib/qpid/config.json is the broker's live configuration (users as SCRAM-SHA-256 hashes, ports, virtual hosts). Change it through the console or REST API, not by hand.
- /var/lib/qpid/default/ is the BDB message store of the default virtual host.
- /var/lib/qpid/etc/initial-config.json is the configuration that first boot rendered from the template. It is used only to create config.json.
- /var/lib/qpid/etc/keystore.p12 and /etc/qpid/keystore-password are the broker's TLS keystore for AMQPS and its password (root only).
- /root/qpid-broker-j-credentials.txt and /root/qpid-curl.conf hold the URLs, admin password and fingerprint, and the curl login (root only).
- /etc/sac/qpid-broker.pem is the public certificate for clients to pin.
- /etc/default/qpid holds the Java heap and direct memory settings.
- /etc/nginx/sites-available/sac-qpid is the HTTPS front door. The certificate and key are in /etc/nginx/ssl/.
- /var/lib/qpid/log/qpid.log and journalctl -u qpid show the broker's log. Use journalctl with nginx or qpid-broker-j-firstboot for the other services.
Backup and maintenance
- Back up
/var/lib/qpid(configuration, users and the message store) with the broker stopped (sudo systemctl stop qpid). Also back up/etc/qpid,/etc/sacand/etc/nginx/ssl. The keystore password in/etc/qpid/keystore-passwordmust stay with the keystore. - Ubuntu security updates install automatically (unattended-upgrades), including the OpenJDK runtime. Broker-J itself lives in
/opt/qpid; to upgrade, launch the newer version from the listing and move your queues and configuration across (the console's Download on the virtual host exports its configuration). - The broker runs with a 1.5 GB Java heap and 1.5 GB of direct memory, sized for an m5.large. On a larger instance raise
QPID_JAVA_MEMin/etc/default/qpidand runsudo systemctl restart qpid.
Security recommendations
- Limit TCP 5671 in the security group to the networks your applications connect from, and TCP 443 and 22 to your admin network. The console can create, purge and delete queues and users; treat it as an administrative interface.
- Give each application its own user (Step 6) instead of sharing
admin, and restrict what each may do with a virtual host access control provider in the console. - Serve the broker under your own DNS name with a certificate from a trusted CA (Step 10). Until then, check the self-signed certificate's fingerprint (Step 4) and pin it per client (Step 7) rather than adding it to a trust store.
- Change the admin password if you share the credentials file (the block at the end of Step 6), and give other people their own users.
- Keep plain AMQP on
127.0.0.1. If you add a port in the console, make it TLS (transport SSL withbrokerKeystore).
Support and licensing
SecureAnyCloud provides 24/7 technical support for this image by email and live chat: sales@secureanycloud.com. Apache Qpid Broker-J is licensed under the Apache License 2.0 (its LICENSE and NOTICE files are on the instance in /opt/qpid/current), OpenJDK under the GNU General Public License version 2 with the Classpath Exception, nginx under the 2-clause BSD licence and pika under the BSD 3-clause licence. Apache, Apache Qpid and Qpid are trademarks of the Apache Software Foundation; SecureAnyCloud is not affiliated with or endorsed by the Apache Software Foundation.
Deploy on AWS
Launch Apache Qpid Broker-J 10.1.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