Deployment guide

LavinMQ Ubuntu 24.04

Overview

LavinMQ is a fast, lightweight, open-source message queue and streaming server written in Crystal. It speaks AMQP 0.9.1 and is a drop-in replacement for RabbitMQ, so existing AMQP clients, tooling and the familiar HTTP management API work unchanged. It is built for high throughput and low memory use, which suits asynchronous messaging, task queues and event streaming.

This SecureAnyCloud image runs the official upstream cloudamqp/lavinmq:2.9.1 Docker image under a thin systemd wrapper. The broker binds AMQP on TCP :5672 and the built-in HTTP management console on TCP :15672. At first boot, a per-VM SecureAnyCloud administrator is created with a random password and the stock guest user is deleted entirely, so the running broker has no default login.

What you get:

  • LavinMQ 2.9.1 (Apache License 2.0) from the official cloudamqp/lavinmq:2.9.1 Docker image
  • A single static Crystal binary, with no Erlang runtime and no Erlang cookie to manage
  • A built-in web management console, enabled out of the box on :15672
  • An AMQP 0.9.1 listener on :5672, compatible with any RabbitMQ AMQP client
  • The bundled lavinmqctl and lavinmqperf CLI tools inside the container
  • Docker CE with the Docker Compose v2 plugin
  • A container named lavinmq with /data/lavinmq bind-mounted for durable broker storage
  • A per-VM SecureAnyCloud administrator password (32 hex chars) generated at first boot
  • The stock guest user deleted at first boot, so there is no default login
  • Two systemd units: lavinmq.service (a oneshot wrapper around docker compose up -d) and lavinmq-firstboot.service (the per-VM admin bootstrap)
  • 24/7 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key, and a VNet with a subnet.

Standard_B2s (4 GB RAM) is comfortable for production AMQP traffic.

Configure the network security group (NSG) to allow inbound 22/tcp from your management CIDR. Allow 5672/tcp (AMQP) only from the client CIDRs that need to publish or consume, never from any source. AMQP and the management console are both cleartext. Reach the console through an SSH tunnel (Step 7) rather than opening 15672/tcp.

Step 1 to 3 - Deploy and connect over SSH

Deploy the image from the Azure Marketplace, then connect over SSH as azureuser:

ssh azureuser@<vm-ip>
4

Check the service status and versions

Check the units, the container and the listening ports.

sudo systemctl is-active docker.service lavinmq.service lavinmq-firstboot.service
sudo docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
sudo ss -tln | grep -E ':5672 |:15672 '

The first command reports active for all three units. docker ps shows the single lavinmq container running cloudamqp/lavinmq:2.9.1 with a healthy status. The listeners on 0.0.0.0:5672 (AMQP) and 0.0.0.0:15672 (management console) confirm that the broker is bound and ready.

5

Read the per-VM credentials

Print the credentials file.

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

Note the values of LAVINMQ_AMQP_URL, LAVINMQ_MGMT_URL, LAVINMQ_ADMIN_USER and LAVINMQ_ADMIN_PASSWORD. The file is mode 0600, owned by root, and holds the unique administrator password generated for this VM at first boot.

6

Verify the management API and authentication

Call the management API with and without credentials.

PASS=$(sudo grep '^LAVINMQ_ADMIN_PASSWORD=' /stage/scripts/lavinmq-credentials.log | cut -d= -f2-)
echo "no credentials -> HTTP $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:15672/api/whoami)"
echo "sac creds -> HTTP $(curl -s -o /dev/null -w '%{http_code}' -u "sac:$PASS" http://127.0.0.1:15672/api/whoami)" curl -s -u "sac:$PASS" http://127.0.0.1:15672/api/users | jq -r '.[].name'

An unauthenticated request to the management API returns HTTP 401. The same request with the per-VM SecureAnyCloud credentials returns HTTP 200. The user list shows only SecureAnyCloud, because the stock guest account is deleted at first boot. There is no default login on the network.

Then query the overview and the current user:

PASS=$(sudo grep '^LAVINMQ_ADMIN_PASSWORD=' /stage/scripts/lavinmq-credentials.log | cut -d= -f2-)
curl -s -u "sac:$PASS" http://127.0.0.1:15672/api/overview | jq '{lavinmq_version, node}'
curl -s -u "sac:$PASS" http://127.0.0.1:15672/api/whoami | jq '{name, tags}'

/api/overview reports the LavinMQ version and node name. /api/whoami round-trips the management authentication and returns the SecureAnyCloud user with the administrator tag.

7

Log in to the management console

The AMQP listener and the management console are cleartext. The password and every message cross the network unencrypted. Allow 5672/tcp only from the client CIDRs that need it, never from any source. Do not use az vm open-port, which allows any source.

For the management console, 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

The console redirects to the login page. Log in as SecureAnyCloud with the password from Step 5.

8

Review the overview dashboard

After you log in, the Overview page shows the broker version, node uptime and live counters for connections, channels, consumers, exchanges, queues and bindings. It also charts queued messages, data rate and message rate.

On a freshly booted VM, the connection, queue and consumer counts are all zero. This is the baseline before any client connects.

9

Manage queues and streams

Select Queues to manage queues. The page lists every queue and provides an Add queue form, where you set the virtual host, name, durability and arguments. LavinMQ supports both classic queues and streams.

10

Inspect connections

Select Connections to see every AMQP client connected to the broker, with its virtual host, user, state, TLS status and protocol. Check this page first to confirm that a producer or consumer has connected.

11

Declare a queue and publish a message

The management API is RabbitMQ-compatible, so you can declare a queue, publish a message and consume it end to end with curl:

PASS=$(sudo grep '^LAVINMQ_ADMIN_PASSWORD=' /stage/scripts/lavinmq-credentials.log | cut -d= -f2-)
curl -s -u "sac:$PASS" -H 'content-type: application/json' \
  -X PUT http://127.0.0.1:15672/api/queues/%2F/hello-world -d '{"durable":true}'
curl -s -u "sac:$PASS" -H 'content-type: application/json' \
  -X POST http://127.0.0.1:15672/api/exchanges/%2F/amq.default/publish \
  -d '{"properties":{},"routing_key":"hello-world","payload":"Hello from sac","payload_encoding":"string"}'
curl -s -u "sac:$PASS" -H 'content-type: application/json' \
  -X POST http://127.0.0.1:15672/api/queues/%2F/hello-world/get \
  -d '{"count":1,"ackmode":"ack_requeue_false","encoding":"auto"}' | jq '.[0].payload'

Declaring the queue returns HTTP 201, publishing returns {"routed":true}, and consuming returns the "Hello from SecureAnyCloud" payload.

The same workflow is available in the management console under Queues (declare a queue) and in each queue's publish and get message panels. The bundled lavinmqctl and lavinmqperf tools are also available with sudo docker exec lavinmq lavinmqctl <command>.

12

Connect from a client (Python pika example)

Publish a message from Python with the pika library.

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 the client with pip install pika.

The LAVINMQ_AMQP_URL from Step 5 also works directly with pika.URLParameters, kombu, aio-pika, Spring AMQP, the .NET RabbitMQ.Client and any other AMQP 0.9.1 library, because LavinMQ speaks the same protocol as RabbitMQ.

13

Manage users

List the broker users, and add or remove accounts, with the bundled lavinmqctl:

sudo docker exec lavinmq lavinmqctl list_users

The list shows only the per-VM SecureAnyCloud administrator. To add an application user, run sudo docker exec lavinmq lavinmqctl add_user <name> <password>, followed by sudo docker exec lavinmq lavinmqctl set_permissions -p / <name> ".*" ".*" ".*". You can also use the Users page in the management console. Grant the administrator tag only to accounts that manage the broker.

14

Add TLS with a domain and Let's Encrypt

Put nginx in front of the management console and obtain a certificate. Replace the values in angle brackets with your own domain and email address:

sudo apt-get update && sudo apt-get install -y nginx python3-certbot-nginx
sudo tee /etc/nginx/sites-available/lavinmq <<'EOF' server { listen 80; server_name <your-domain>; 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/lavinmq /etc/nginx/sites-enabled/lavinmq
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d <your-domain> -m <your-email> --agree-tos --non-interactive --redirect

Certbot adds the SSL server block and a :80 to :443 redirect, then reloads nginx. Renewal runs automatically through the certbot.timer systemd unit.

For TLS directly on the AMQP listener (5671/tcp), bind-mount a certificate into the container and enable the TLS listener in the LavinMQ configuration.

15

Back up the broker

Export the broker definitions (users, vhosts, exchanges, queues, bindings and policies) while the broker is running, and snapshot the data directory for message contents. Replace <backup-dir> with your own destination:

PASS=$(sudo grep '^LAVINMQ_ADMIN_PASSWORD=' /stage/scripts/lavinmq-credentials.log | cut -d= -f2-)
curl -s -u "sac:$PASS" http://127.0.0.1:15672/api/definitions > <backup-dir>/lavinmq-defs.json
sudo tar czf <backup-dir>/lavinmq-data.tgz -C /data lavinmq

Periodically copy the backup directory to Azure Blob Storage (az storage blob upload-batch) for off-VM retention.

To restore, send a POST of the definitions JSON to /api/definitions while the broker is running. Then untar the data directory back to /data/lavinmq while the broker is stopped.

16

Read logs and troubleshoot

View the container logs, the unit logs and the broker status.

sudo docker logs lavinmq --tail 80
sudo journalctl -u lavinmq.service --no-pager -n 50
sudo journalctl -u lavinmq-firstboot.service --no-pager -n 50
sudo docker exec lavinmq lavinmqctl status

Use docker logs --tail for a snapshot of the container logs, or docker logs lavinmq -f to follow them live. The systemd unit logs cover the wrapper service and the first-boot admin bootstrap. lavinmqctl status prints the broker node state.

Security

  • Per-VM administrator password. A SecureAnyCloud administrator password (32 hex chars from openssl rand) is generated at first boot.
  • No default login. The stock guest user is deleted at first boot, so there is no default login on the network.
  • Loopback-only default user. LavinMQ restricts its default user to loopback by default, so guest is never reachable over the network, even during the brief first-boot window before it is removed.
  • Restrict the listeners. The AMQP listener 5672/tcp and the management console 15672/tcp are bound on the host. Restrict them with the NSG to known client and management CIDRs.
  • Small attack surface. LavinMQ is a single Crystal binary with no Erlang runtime, which reduces the attack surface compared with brokers that ship a full language VM.
  • Optional TLS. You can add TLS to the management console with nginx and certbot (Step 14), and to the AMQP listener (5671/tcp).
  • Durable data. Broker data persists under /data/lavinmq, kept off the running container's writable layer.

Support

SecureAnyCloud provides 24/7/365 expert technical support. Guaranteed response within 24 hours, one hour average for critical issues. Contact sales@secureanycloud.com.

Deploy on Azure

Launch LavinMQ 2.9.1 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