Deployment guide

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-management Docker 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_mqtt and rabbitmq_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 rabbitmq with the named volume /data/rabbitmq for 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 around docker compose up -d) and rabbitmq-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/tcp from your management CIDR. Allow 5672/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/tcp stays inside the Docker bridge network and is never exposed on the host.

Step 1-3: Deploy + SSH (standard pattern)

ssh azureuser@<vm-ip>
4

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_version

The 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.

5

Read Per-VM Credentials

sudo cat /stage/scripts/rabbitmq-credentials.log

Note 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.

6

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.

7

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 5672

Log in as SecureAnyCloud with the password from Step 5.

8

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.

9

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.

10

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_false

You 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.

11

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.

12

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 -E

rabbitmq-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.

13

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.service

Then 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.

14

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 --redirect

Certbot 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.

15

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.service

Periodically 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.

16

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 15672

Use 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 rabbitmqctl or rabbitmq-diagnostics invocation requires it.
  • The AMQP listener 5672/tcp and the management UI 15672/tcp are bound on the host and are cleartext. Allow 5672 only from known client CIDRs (never any source), and reach 15672 through an SSH tunnel.
  • The Erlang distribution port 25672/tcp is bound only inside the Docker bridge network. It is never reachable from the host or the public IP.
  • The container runs as the upstream rabbitmq user (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/tcp listener 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

Deploy on Azure