RabbitMQ 4
Overview
RabbitMQ is a widely used open-source message broker. It is an AMQP 0-9-1 implementation with first-class support for MQTT, STOMP, federation, shovel and management plugins. The SecureAnyCloud image runs the official upstream rabbitmq:4.3.0-management Docker image (with Erlang 27 included) under a thin systemd wrapper. It has a per-VM SecureAnyCloud administrator user, a per-VM Erlang cookie, and the management UI bound on TCP :15672. AMQP listeners are bound on TCP :5672. The default guest user is never created. First boot imports the definitions into an empty mnesia database, so only SecureAnyCloud has access to the broker.
What you get:
- RabbitMQ 4.3.0 (Mozilla Public License 2.0) from the official
rabbitmq:4.3.0-managementDocker image. - Erlang 27 included in the upstream image, so there is no host-level Erlang install.
- The management UI plugin, enabled out of the box.
- Additional plugins available on demand:
rabbitmq_shovel,rabbitmq_federation,rabbitmq_mqttandrabbitmq_stomp. - definitions.json provisioning. The broker boots with the SecureAnyCloud administrator only and no default guest user.
- Docker CE 29.4.2 and the Docker Compose v2 plugin v5.1.3.
- A container named
rabbitmqwith the named volume/data/rabbitmqfor mnesia, queue data and the Erlang cookie. - A per-VM SecureAnyCloud administrator password (32 hex characters) and Erlang cookie (32 hex characters), rotated at first boot.
- Two systemd units:
rabbitmq.service(a oneshot wrapper arounddocker compose up -d) andrabbitmq-firstboot.service(Before=rabbitmq.service). - 24/7 SecureAnyCloud support.
Prerequisites
- An active Azure subscription, an SSH key, and a VNet with a subnet.
- Standard_B2s (4 GB RAM) is comfortable for production AMQP traffic up to a few thousand sustained messages per second per node.
- NSG inbound rules: allow
22/tcpfrom your management CIDR. Allow5672/tcp(AMQP) only from the client CIDRs that need to publish or consume, and never from any source. - Both AMQP and the management UI are cleartext. Reach the UI through an SSH tunnel (Step 7) rather than opening
15672/tcp. - The Erlang distribution port
25672/tcpstays inside the Docker bridge network and is never exposed on the host.
Step 1-3: Deploy + SSH (standard pattern)
ssh azureuser@<vm-ip>Service Status + Versions
sudo systemctl is-active docker.service rabbitmq.service rabbitmq-firstboot.service
sudo docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
sudo docker exec rabbitmq rabbitmq-diagnostics server_versionThe first command reports active for all three units. docker ps shows the single rabbitmq container running rabbitmq:4.3.0-management. rabbitmq-diagnostics server_version reports 4.3.0, which proves that the broker process inside the container has finished starting.
Read Per-VM Credentials
sudo cat /stage/scripts/rabbitmq-credentials.logNote RABBITMQ_AMQP_URL, RABBITMQ_MGMT_URL, RABBITMQ_ADMIN_USER and RABBITMQ_ADMIN_PASSWORD. The same file also contains the per-VM RABBITMQ_ERLANG_COOKIE. You need the cookie only if you cluster this node with another RabbitMQ node.
API Aliveness + Health
PASS=$(sudo grep '^RABBITMQ_ADMIN_PASSWORD=' /stage/scripts/rabbitmq-credentials.log | cut -d= -f2-)
curl -sf -u "sac:$PASS" 'http://127.0.0.1:15672/api/aliveness-test/%2F' | jq
curl -sf -u "sac:$PASS" http://127.0.0.1:15672/api/whoami | jq/api/aliveness-test/%2F declares a temporary queue, publishes a message to it, consumes the message and deletes the queue. This proves that the AMQP listener and mnesia are healthy end to end. /api/whoami round-trips the management authentication and returns the SecureAnyCloud user with the administrator tag.
Login to Management UI
The AMQP listener and the management UI are cleartext. The password and every message cross the network unencrypted. Allow 5672/tcp only from the client CIDRs that need it, and never from any source. Do not use az vm open-port, because it allows any source. For the management UI, use an SSH tunnel rather than opening 15672/tcp:
ssh -N -L 15672:127.0.0.1:15672 azureuser@<vm-public-ip>Then browse to http://127.0.0.1:15672/. If you must open a port, scope the rule to your own CIDR:
az network nsg rule create --resource-group <your-rg> --nsg-name <your-vm-nsg> \
--name amqp-5672-clients --priority 910 --direction Inbound --access Allow --protocol Tcp \
--source-address-prefixes <your-client-cidr> --destination-port-ranges 5672Log in as SecureAnyCloud with the password from Step 5.
Management Overview Dashboard
After you log in, the Overview tab shows the broker version, the Erlang/OTP version, node uptime, and live counters for connections, channels, queues, exchanges, consumers and message rates. On a freshly booted VM, the queue, connection and channel counts are all zero. This is the baseline before any client connects.
Admin Users Tab
Select Admin and then Users. The list shows the per-VM SecureAnyCloud user with the administrator tag and full permissions on the default vhost /. Add more users from this page or with rabbitmqctl add_user. The default upstream guest user is intentionally absent.
Create a Queue and Publish a Message
PASS=$(sudo grep '^RABBITMQ_ADMIN_PASSWORD=' /stage/scripts/rabbitmq-credentials.log | cut -d= -f2-) sudo docker exec rabbitmq rabbitmqctl set_permissions -p / sac ".*" ".*" ".*"
sudo docker exec rabbitmq rabbitmqadmin --username=sac --password="$PASS" --non-interactive \
declare queue --name hello-world --type classic --durable true
sudo docker exec rabbitmq rabbitmqadmin --username=sac --password="$PASS" --non-interactive \
publish message --routing-key hello-world --payload "Hello from sac"
sudo docker exec rabbitmq rabbitmqadmin --username=sac --password="$PASS" --non-interactive \
get messages --queue hello-world --ack-mode ack_requeue_falseYou can follow the same workflow in the management UI. Declare a queue under Queues and Streams, then use the queue's Publish message and Get messages sections. The bundled rabbitmqadmin v2 (Rust) ships with the upstream rabbitmq:4.3.0-management image and uses subcommand-style flags, for example --name and --routing-key.
Connect from a Client (Python pika example)
import pika VM_IP = '<vm-ip>' PASS = '<password-from-step-5>' creds = pika.PlainCredentials('sac', PASS) conn = pika.BlockingConnection( pika.ConnectionParameters(host=VM_IP, port=5672, virtual_host='/', credentials=creds) ) ch = conn.channel() ch.queue_declare(queue='hello', durable=True) ch.basic_publish(exchange='', routing_key='hello', body='Hello World!') print('published') conn.close()Install pika with pip install pika. The RABBITMQ_AMQP_URL from Step 5 works directly with pika.URLParameters, kombu, aio-pika, Spring AMQP, .NET RabbitMQ.Client and any other AMQP 0-9-1 library.
Enable Additional Plugins
sudo docker exec rabbitmq rabbitmq-plugins enable \
rabbitmq_shovel rabbitmq_shovel_management \
rabbitmq_federation rabbitmq_federation_management \
rabbitmq_mqtt rabbitmq_stomp
sudo docker exec rabbitmq rabbitmq-plugins list -Erabbitmq-plugins enable is idempotent and applies live, so shovel, federation, MQTT and STOMP need no broker restart. The MQTT listener binds on 1883/tcp and STOMP on 61613/tcp. Open the matching NSG rules to expose them.
Add Your Domain
Edit /etc/rabbitmq/rabbitmq.conf and set cluster_name to a stable identifier:
sudo sed -i 's/^cluster_name = .*/cluster_name = rabbit-prod-1/' /etc/rabbitmq/rabbitmq.conf
sudo systemctl restart rabbitmq.serviceThen allow your client CIDR (never any source) on 5672/tcp (AMQP). Keep reaching the management UI through the SSH tunnel from Step 7. Both are cleartext. The Erlang distribution port 25672/tcp is bound only inside the Docker bridge, so leave it closed on the NSG.
Install Let's Encrypt SSL for the Management UI
Install nginx and certbot, and then put nginx in front of the management UI:
sudo apt-get update && sudo apt-get install -y nginx python3-certbot-nginx
sudo tee /etc/nginx/sites-available/rabbitmq <<'EOF' server { listen 80; server_name rabbit.example.com; location / { proxy_pass http://127.0.0.1:15672; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } EOF
sudo ln -sf /etc/nginx/sites-available/rabbitmq /etc/nginx/sites-enabled/rabbitmq
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d rabbit.example.com -m you@example.com --agree-tos --non-interactive --redirectCertbot edits the nginx site to add the SSL server block and a :80 → :443 redirect, and then reloads nginx. The certbot.timer systemd unit handles renewal and runs twice daily. For TLS on the AMQP listener (5671/tcp), follow the upstream RabbitMQ TLS guide. It requires bind-mounting the certificate PEM into the container and adding listeners.ssl.default = 5671 to /etc/rabbitmq/rabbitmq.conf.
Backups
Export the broker definitions (users, vhosts, exchanges, queues, bindings and policies) while the broker is running. Also snapshot the mnesia data directory to capture queue contents:
sudo docker exec rabbitmq rabbitmqctl export_definitions /tmp/defs.json
sudo docker cp rabbitmq:/tmp/defs.json /var/backups/rabbitmq-defs-$(date +%F).json
sudo systemctl stop rabbitmq.service
sudo tar czf /var/backups/rabbitmq-data-$(date +%F).tgz -C /data rabbitmq
sudo systemctl start rabbitmq.servicePeriodically copy /var/backups to Azure Blob Storage (az storage blob upload-batch) for off-VM retention. To restore, run import_definitions /tmp/defs.json with the broker running, and untar the data directory back to /data/rabbitmq with the broker stopped.
Logs and Troubleshooting
sudo docker logs rabbitmq --tail 80
sudo journalctl -u rabbitmq.service --no-pager -n 50
sudo journalctl -u rabbitmq-firstboot.service --no-pager -n 50
sudo docker exec rabbitmq rabbitmq-diagnostics check_running
sudo docker exec rabbitmq rabbitmq-diagnostics check_local_alarms
sudo docker exec rabbitmq rabbitmq-diagnostics check_port_listener 5672
sudo docker exec rabbitmq rabbitmq-diagnostics check_port_listener 15672Use docker logs --tail for a snapshot of the container logs, or docker logs rabbitmq -f for a live, interactive follow. The systemd unit logs cover the wrapper service (start, stop and dependency failures). rabbitmq-diagnostics gives focused health probes. check_local_alarms returns non-zero on memory or disk-space pressure, and check_port_listener confirms that the AMQP and management listeners are bound. rabbitmq-diagnostics status, run interactively, prints the full broker state.
Security
- The per-VM SecureAnyCloud administrator password (32 hex characters from openssl rand) is rotated at first boot.
- The default upstream guest user is intentionally never created. definitions.json imports the SecureAnyCloud user only on an empty mnesia database.
- The per-VM Erlang cookie (32 hex characters) is rotated at first boot. Any
rabbitmqctlorrabbitmq-diagnosticsinvocation requires it. - The AMQP listener
5672/tcpand the management UI15672/tcpare bound on the host and are cleartext. Allow5672only from known client CIDRs (never any source), and reach15672through an SSH tunnel. - The Erlang distribution port
25672/tcpis bound only inside the Docker bridge network. It is never reachable from the host or the public IP. - The container runs as the upstream
rabbitmquser (uid 999), not root. - TLS on the management UI is optional through nginx and certbot (Step 14). TLS on AMQP is optional through the
5671/tcplistener configuration.
Support
SecureAnyCloud provides 24/7/365 expert technical support. Guaranteed response within 24 hours, with a one-hour average for critical issues. Contact sales@secureanycloud.com.
Deploy on Azure
Launch RabbitMQ 4.3.0 Message Broker on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
RabbitMQ is a widely used open-source message broker that implements the AMQP protocol. This image provides RabbitMQ 4.3.0 with Erlang/OTP 27, the management web interface, and a dedicated data volume for queue persistence. First boot generates a unique admin password and Erlang cookie.
Prerequisites
- An AWS account with an EC2 key pair.
- A security group that allows TCP 22 (SSH), 5672 (AMQP) and 15672 (management UI).
- The instance ships with a 20 GiB EBS data volume mounted at
/var/lib/rabbitmq.
Connecting via SSH
ssh -i /path/to/your-key.pem ubuntu@<instance-public-ip>The default login user is ubuntu.
Retrieve credentials
On first boot, the instance generates a unique admin password and Erlang cookie and writes them to /root/rabbitmq-credentials.txt. Only the root user can read this file.
sudo cat /root/rabbitmq-credentials.txtExpected output:
# RabbitMQ 4 -- Per-VM Credentials
# Generated: Wed May 27 19:50:54 UTC 2026 rabbitmq.admin.user=admin rabbitmq.admin.password=bs23dAET6VIH768vJ9mb rabbitmq.management.url=http://172.31.84.6:15672 rabbitmq.amqp.url=amqp://admin:bs23dAET6VIH768vJ9mb@172.31.84.6:5672The credentials file contains:
Key Description
rabbitmq.admin.user Management UI and AMQP username (always admin)
rabbitmq.admin.password Per-instance generated password
rabbitmq.management.url Management API and UI base URL
rabbitmq.amqp.url AMQP connection URL for client libraries
Service status
systemctl status rabbitmq.serviceExpected output:
● rabbitmq.service - RabbitMQ 4 Message Broker (sac) Loaded: loaded (/etc/systemd/system/rabbitmq.service; enabled; preset: enabled) Active: active (running) since Wed 2026-05-27 19:50:54 UTC; 2min 18s ago Main PID: 33742 (docker) Tasks: 15 (limit: 4586) Memory: 16.2M (peak: 17.4M) CPU: 130ms CGroup: /system.slice/rabbitmq.service ├─33742 /usr/bin/docker compose -f /opt/rabbitmq/docker-compose.yml up └─33764 /usr/libexec/docker/cli-plugins/docker-compose compose -f /opt/rabbitmq/docker-compose.yml upCheck that the rabbitmq container is running:
sudo docker psExpected output:
NAMES IMAGE STATUS PORTS rabbitmq rabbitmq:4.3.0-management Up 36 seconds 4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, [::]:5672->5672/tcp, 15671/tcp, 15691-15692/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp, [::]:15672->15672/tcpRabbitMQ diagnostics
sudo docker exec rabbitmq rabbitmq-diagnostics status | head -20Expected output:
Status of node rabbit@rabbitmq ... Runtime OS PID: 1 OS: Linux Uptime (seconds): 153 Is under maintenance?: false RabbitMQ version: 4.3.0 RabbitMQ release series support status: see https://www.rabbitmq.com/release-information Node name: rabbit@rabbitmq Erlang configuration: Erlang/OTP 27 [erts-15.2.7.8] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit:ns] Crypto library: OpenSSL 3.5.6 7 Apr 2026 Erlang processes: 401 used, 1048576 limit Scheduler run queue: 1 Cluster heartbeat timeout (net_ticktime): 60Management console (web UI)
Browse to http://<instance-public-ip>:15672 and sign in with the admin user name and the password from the credentials file.
The Overview tab shows real-time message rates, connection counts and cluster status.
The Queues and Streams tab lists all queues with their message counts and rates.
Check the aliveness API
Verify that the broker is healthy by calling the aliveness-test endpoint:
PASS=$(sudo grep '^rabbitmq.admin.password=' /root/rabbitmq-credentials.txt | cut -d= -f2-)
curl -su "admin:${PASS}" http://127.0.0.1:15672/api/aliveness-test/%2FExpected output:
{"status":"ok"}Creating a queue via the API
PASS=$(sudo grep '^rabbitmq.admin.password=' /root/rabbitmq-credentials.txt | cut -d= -f2-)
curl -s -X PUT -u "admin:${PASS}" http://127.0.0.1:15672/api/queues/%2F/my-queue \
-H "Content-Type: application/json" \
-d '{"auto_delete":false,"durable":true}'Expected output:
{}An empty JSON object indicates that the queue was created.
Publishing a message
PASS=$(sudo grep '^rabbitmq.admin.password=' /root/rabbitmq-credentials.txt | cut -d= -f2-)
curl -s -X POST -u "admin:${PASS}" http://127.0.0.1:15672/api/exchanges/%2F/amq.default/publish \
-H "Content-Type: application/json" \
-d '{"properties":{},"routing_key":"my-queue","payload":"Hello RabbitMQ","payload_encoding":"string"}'Expected output:
{"routed":true}Listing queues
PASS=$(sudo grep '^rabbitmq.admin.password=' /root/rabbitmq-credentials.txt | cut -d= -f2-)
curl -s -u "admin:${PASS}" http://127.0.0.1:15672/api/queues/%2F | python3 -c \
"import sys,json; [print(f\"{q['name']}: {q.get('messages',0)} messages\") for q in json.load(sys.stdin)]"Expected output:
my-queue: 1 messagesConsuming a message
PASS=$(sudo grep '^rabbitmq.admin.password=' /root/rabbitmq-credentials.txt | cut -d= -f2-)
curl -s -X POST -u "admin:${PASS}" http://127.0.0.1:15672/api/queues/%2F/my-queue/get \
-H "Content-Type: application/json" \
-d '{"count":1,"encoding":"auto","ackmode":"ack_requeue_false"}' | python3 -c \
"import sys,json; msgs=json.load(sys.stdin); print(msgs[0]['payload'])"Expected output:
Hello RabbitMQConnecting with an AMQP client (Python example)
Install the pika client library:
pip install pikaPublish a message:
import pika conn = pika.BlockingConnection( pika.URLParameters("amqp://admin:<RABBITMQ_ADMIN_PASSWORD>@<instance-ip>:5672/")) ch = conn.channel() ch.queue_declare(queue="orders", durable=True) ch.basic_publish(exchange="", routing_key="orders", body="order-12345") conn.close()Restarting the service
sudo systemctl restart rabbitmq.serviceData persistence
Queue data, Erlang mnesia and the node identity are stored on /var/lib/rabbitmq, which is a separate 20 GiB EBS volume. This volume survives instance stop and start cycles. You can resize it independently of the OS disk in the EC2 console.
Log access
sudo docker logs rabbitmq --tail 50Or via journald:
journalctl -u rabbitmq.service --no-pager -n 50First-boot log
sudo cat /var/log/sac/sac-firstboot.logSecurity notes
- Access ports 5672 and 15672 only from trusted networks. Use AWS security group rules to restrict inbound access.
- The management UI shares the admin credentials with the AMQP broker. Rotate the password through the management API or
rabbitmqctlwhen needed. - To enable TLS, mount a certificate bundle into the container and update
/etc/rabbitmq/rabbitmq.conf.
Support
For technical support, email sales@secureanycloud.com or visit secureanycloud.com.
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com