RabbitMQ is an open source message broker that speaks AMQP 0-9-1 and lets applications exchange messages through exchanges, queues and bindings instead of calling each other directly. In this tutorial you will install the current RabbitMQ release and a matching Erlang runtime on Ubuntu 24.04 from the repositories maintained by the RabbitMQ team, lock down the default account, create a dedicated virtual host and user, enable the management UI, and send and receive messages through a durable quorum queue with a small Python script.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS on x86_64 (amd64), for example a CubePath VPS. The Erlang packages in the RabbitMQ repository are built only for amd64.
- A non-root user with
sudoprivileges. - At least 2 GB of RAM and 10 GB of free disk space. RabbitMQ stops accepting messages when memory or disk runs low, so small instances fill up quickly.
- UFW enabled, or another firewall you manage.
- The IP address of the machine you will use to open the management UI (
your_admin_ipin this guide).
Step 1 - Adding the RabbitMQ and Erlang repositories
Ubuntu 24.04 ships an older RabbitMQ 3.12 in its archive. The RabbitMQ team publishes current RabbitMQ versions together with a compatible Erlang/OTP release, which avoids version mismatches between the broker and its runtime.
Install the tools needed to fetch and verify the repository key:
sudo apt update
sudo apt install -y curl gnupg
Download the RabbitMQ team signing key into a dedicated keyring:
sudo install -d -m 0755 /etc/apt/keyrings
curl -1sLf "https://keys.openpgp.org/vks/v1/by-fingerprint/0A9AF2115F4687BD29803A206B73A36E6026DFCA" | sudo gpg --dearmor -o /etc/apt/keyrings/com.rabbitmq.team.gpg
Create the repository file:
sudo nano /etc/apt/sources.list.d/rabbitmq.list
Add the Erlang and RabbitMQ repositories. Each one has two mirrors:
deb [arch=amd64 signed-by=/etc/apt/keyrings/com.rabbitmq.team.gpg] https://deb1.rabbitmq.com/rabbitmq-erlang/ubuntu/noble noble main
deb [arch=amd64 signed-by=/etc/apt/keyrings/com.rabbitmq.team.gpg] https://deb2.rabbitmq.com/rabbitmq-erlang/ubuntu/noble noble main
deb [arch=amd64 signed-by=/etc/apt/keyrings/com.rabbitmq.team.gpg] https://deb1.rabbitmq.com/rabbitmq-server/ubuntu/noble noble main
deb [arch=amd64 signed-by=/etc/apt/keyrings/com.rabbitmq.team.gpg] https://deb2.rabbitmq.com/rabbitmq-server/ubuntu/noble noble main
Save the file and refresh the package index:
sudo apt update
Confirm that APT now prefers the RabbitMQ repository over the Ubuntu archive:
apt policy rabbitmq-server
The candidate version should come from deb1.rabbitmq.com and be a 4.x release:
rabbitmq-server:
Installed: (none)
Candidate: 4.x.x-1
Version table:
4.x.x-1 500
500 https://deb1.rabbitmq.com/rabbitmq-server/ubuntu/noble noble/main amd64 Packages
Step 2 - Installing Erlang and RabbitMQ
Install the Erlang modules RabbitMQ needs. Installing them explicitly makes sure they come from the RabbitMQ Erlang repository and not from the older Ubuntu packages:
sudo apt install -y erlang-base \
erlang-asn1 erlang-crypto erlang-eldap erlang-ftp erlang-inets \
erlang-mnesia erlang-os-mon erlang-parsetools erlang-public-key \
erlang-runtime-tools erlang-snmp erlang-ssl \
erlang-syntax-tools erlang-tftp erlang-tools erlang-xmerl
Then install the broker:
sudo apt install -y rabbitmq-server
The package creates the rabbitmq-server systemd service and starts it. Enable it at boot and check its state:
sudo systemctl enable --now rabbitmq-server
sudo systemctl status rabbitmq-server --no-pager
● rabbitmq-server.service - RabbitMQ broker
Loaded: loaded (/usr/lib/systemd/system/rabbitmq-server.service; enabled; preset: enabled)
Active: active (running) since ...
Ask the node itself whether it is healthy:
sudo rabbitmq-diagnostics ping
Will ping rabbit@your_hostname. This only checks if the OS process is running and registered with epmd. Timeout: 60000 ms.
Ping succeeded
You can print the broker and Erlang versions with sudo rabbitmq-diagnostics server_version and sudo rabbitmq-diagnostics erlang_version.
Step 3 - Setting basic broker limits
RabbitMQ reads its main configuration from /etc/rabbitmq/rabbitmq.conf, which the package does not create. Create it to set explicit resource limits instead of relying on defaults:
sudo nano /etc/rabbitmq/rabbitmq.conf
# AMQP listener
listeners.tcp.default = 5672
# Management UI and HTTP API
management.tcp.port = 15672
# Block publishers when RabbitMQ uses more than 60% of system RAM
vm_memory_high_watermark.relative = 0.6
# Block publishers when free disk space drops below 2 GB
disk_free_limit.absolute = 2GB
# The default guest user can only connect from localhost
loopback_users.guest = true
The memory watermark and disk limit are flow-control thresholds: when either is crossed, RabbitMQ pauses publishing connections until consumers drain enough messages. Adjust disk_free_limit.absolute to your disk size, but keep it well above zero.
Restart RabbitMQ to apply the file:
sudo systemctl restart rabbitmq-server
Verify that the values were loaded:
sudo rabbitmq-diagnostics status | grep -i watermark
The output reports the memory watermark as 0.6 of available memory and the free disk watermark as 2.0 GB:
Memory high watermark setting: 0.6 of available memory, computed to: 2.4 gb
Low free disk space watermark: 2.0 gb
Step 4 - Creating an administrator, a virtual host and an application user
A fresh installation has a single guest account with the password guest. It only works from localhost, but you should replace it with named accounts anyway.
Create an administrator account. Replace your_strong_password with a long random password:
sudo rabbitmqctl add_user admin 'your_strong_password'
sudo rabbitmqctl set_user_tags admin administrator
Virtual hosts (vhosts) are isolated namespaces with their own exchanges, queues and permissions. Create one for your application:
sudo rabbitmqctl add_vhost app
Create an application user without management tags and give it permissions only inside the app vhost. The three patterns grant configure, write and read rights on every resource in that vhost:
sudo rabbitmqctl add_user appuser 'another_strong_password'
sudo rabbitmqctl set_permissions -p app appuser ".*" ".*" ".*"
Give the administrator access to the new vhost as well, so you can inspect it from the UI:
sudo rabbitmqctl set_permissions -p app admin ".*" ".*" ".*"
Once the new administrator works, delete the default account:
sudo rabbitmqctl delete_user guest
Check the result:
sudo rabbitmqctl list_users
sudo rabbitmqctl list_permissions -p app
Listing users ...
user tags
admin [administrator]
appuser []
Listing permissions for vhost "app" ...
user configure write read
admin .* .* .*
appuser .* .* .*
TipIn production, narrow the permission patterns. For example,
"^orders.*" "^orders.*" "^orders.*"lets a service touch only resources whose names start withorders.
Step 5 - Enabling the management UI
The management plugin provides a web UI and an HTTP API on port 15672 for browsing queues, connections and message rates. Enable it:
sudo rabbitmq-plugins enable rabbitmq_management
Enabling plugins on node rabbit@your_hostname:
rabbitmq_management
...
started 3 plugins.
The management UI should never be open to the whole internet. Allow it only from your own address, and allow AMQP only from the private network where your application servers live (replace 10.0.0.0/24 with your subnet):
sudo ufw allow from your_admin_ip to any port 15672 proto tcp
sudo ufw allow from 10.0.0.0/24 to any port 5672 proto tcp
sudo ufw status
Confirm that both ports are listening:
sudo ss -tlnp | grep -E ':5672|:15672'
Both lines should belong to the beam.smp process, which is the Erlang VM running RabbitMQ.
Open http://your_server_ip:15672 in a browser and log in as admin. The Overview tab shows the node, its memory and disk alarms, and message rates.
WarningThe UI and AMQP traffic in this guide are unencrypted. If clients connect over the public internet, configure TLS listeners (port 5671 for AMQP) or put the UI behind a reverse proxy with HTTPS.
Step 6 - Sending and receiving messages with Python
To see the pieces working together, you will declare a direct exchange, a durable quorum queue and a binding, then publish and consume messages. Quorum queues replicate data with the Raft protocol and are the recommended queue type for data that must not be lost; on a single node they still give you durable storage and publisher confirms.
Install the pika client library from the Ubuntu archive:
sudo apt install -y python3-pika
Create the producer:
nano ~/producer.py
import pika
credentials = pika.PlainCredentials("appuser", "another_strong_password")
params = pika.ConnectionParameters("localhost", 5672, "app", credentials)
connection = pika.BlockingConnection(params)
channel = connection.channel()
channel.confirm_delivery()
channel.exchange_declare(exchange="orders", exchange_type="direct", durable=True)
channel.queue_declare(
queue="orders.created",
durable=True,
arguments={"x-queue-type": "quorum"},
)
channel.queue_bind(queue="orders.created", exchange="orders", routing_key="created")
for i in range(1, 6):
body = f"order {i}"
channel.basic_publish(
exchange="orders",
routing_key="created",
body=body,
properties=pika.BasicProperties(delivery_mode=pika.DeliveryMode.Persistent),
)
print(f"sent: {body}")
connection.close()
The confirm_delivery() call makes each publish wait until the broker has accepted the message, and delivery_mode marks messages as persistent.
Run it:
python3 ~/producer.py
sent: order 1
sent: order 2
sent: order 3
sent: order 4
sent: order 5
Check that the messages are waiting in the queue:
sudo rabbitmqctl list_queues -p app name type messages
Timeout: 60.0 seconds ...
Listing queues for vhost app ...
name type messages
orders.created quorum 5
Now create the consumer:
nano ~/consumer.py
import pika
credentials = pika.PlainCredentials("appuser", "another_strong_password")
params = pika.ConnectionParameters("localhost", 5672, "app", credentials)
connection = pika.BlockingConnection(params)
channel = connection.channel()
channel.basic_qos(prefetch_count=10)
def handle(ch, method, properties, body):
print(f"received: {body.decode()}")
ch.basic_ack(delivery_tag=method.delivery_tag)
channel.basic_consume(queue="orders.created", on_message_callback=handle)
print("waiting for messages, press CTRL+C to exit")
try:
channel.start_consuming()
except KeyboardInterrupt:
channel.stop_consuming()
connection.close()
The consumer acknowledges each message only after handling it, so a crash before basic_ack returns the message to the queue. prefetch_count limits how many unacknowledged messages a consumer holds at once.
Run it:
python3 ~/consumer.py
waiting for messages, press CTRL+C to exit
received: order 1
received: order 2
received: order 3
received: order 4
received: order 5
Press CTRL+C, then confirm the queue is empty:
sudo rabbitmqctl list_queues -p app name messages
name messages
orders.created 0
Step 7 - Limiting queue length with a policy
Queues without limits can grow until they trigger the memory or disk alarm and block every publisher on the node. A policy applies settings to matching queues without changing application code. The following caps orders.created at 100,000 messages and rejects new publishes once it is full, so producers get an explicit error instead of silently losing old messages:
sudo rabbitmqctl set_policy -p app orders-limit "^orders\." \
'{"max-length": 100000, "overflow": "reject-publish"}' \
--apply-to queues
Verify the policy:
sudo rabbitmqctl list_policies -p app
vhost name pattern apply-to definition priority
app orders-limit ^orders\. queues {"max-length":100000,"overflow":"reject-publish"} 0
In the management UI, the queue now shows orders-limit in its Policy column.
Troubleshooting
apt installs Erlang from the Ubuntu archive or reports unmet dependencies. Run apt policy erlang-base and make sure the candidate comes from deb1.rabbitmq.com. If the repository file has a typo or the key is missing, APT falls back to Ubuntu's packages, which may not match the RabbitMQ version.
The service fails to start. Read the logs with sudo journalctl -u rabbitmq-server -n 50 and the node log in /var/log/rabbitmq/. A syntax error in rabbitmq.conf is the most common cause; the log names the offending line.
ACCESS_REFUSED - Login was refused. The user, password or vhost is wrong, or the user has no permissions in that vhost. Check with sudo rabbitmqctl list_permissions -p app. The guest user is also refused from any host other than localhost.
Publishers hang without errors. A resource alarm is active. Run sudo rabbitmq-diagnostics alarms and free disk space or memory, or consume the backlog.
Hostname changes break the node. RabbitMQ stores data under the node name rabbit@hostname. If you change the server hostname after installation, the node starts with an empty database. Set the final hostname before installing.
Conclusion
You now have a current RabbitMQ release running on Ubuntu 24.04 with a dedicated vhost and user, a firewalled management UI, a durable quorum queue, and a length-limit policy. From here, configure TLS for AMQP and the management UI, build a three-node cluster so quorum queues can survive a node failure, and add monitoring through the rabbitmq_prometheus plugin.
