RabbitMQ es un broker de mensajes que implementa AMQP 0-9-1 y permite que distintas partes de una aplicación se comuniquen de forma asíncrona a través de colas. En este tutorial instalarás RabbitMQ y la versión de Erlang que necesita desde los repositorios oficiales del equipo de RabbitMQ en Ubuntu 24.04, crearás un host virtual y usuarios con permisos mínimos, activarás la consola de gestión y enviarás y consumirás mensajes desde Python usando un exchange y colas quorum.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 GB de RAM.
  • Un usuario no root con privilegios sudo.
  • UFW activo con SSH permitido.
  • Conocer los conceptos básicos de productor, consumidor y cola.

Paso 1: Añadir los repositorios oficiales de RabbitMQ y Erlang

Ubuntu incluye un paquete rabbitmq-server, pero suele ser una versión antigua. El equipo de RabbitMQ publica sus propios repositorios con la última versión del servidor y un Erlang compatible con ella.

Instala las herramientas necesarias:

sudo apt update
sudo apt install curl gnupg apt-transport-https

Descarga la clave de firma del equipo de RabbitMQ en /etc/apt/keyrings:

sudo install -m 0755 -d /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

Crea el archivo de repositorios para Ubuntu 24.04 (noble):

sudo nano /etc/apt/sources.list.d/rabbitmq.list
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://deb1.rabbitmq.com/rabbitmq-server/ubuntu/noble noble main

Actualiza el índice de paquetes:

sudo apt update

La salida debe incluir líneas Get o Hit para deb1.rabbitmq.com sin errores de firma.

Paso 2: Instalar Erlang y RabbitMQ

Instala los paquetes de Erlang que RabbitMQ necesita. Instalarlos explícitamente evita que apt mezcle versiones de Erlang de Ubuntu y del repositorio de RabbitMQ:

sudo apt install 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

Instala el servidor:

sudo apt install rabbitmq-server --fix-missing

El paquete crea el usuario de sistema rabbitmq, habilita el servicio y lo arranca. Compruébalo:

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)

Consulta el estado del nodo y las versiones instaladas:

sudo rabbitmq-diagnostics status | head -n 20

La salida muestra la versión de RabbitMQ, la de Erlang, el uso de memoria y los listeners activos (AMQP en el puerto 5672).

Paso 3: Ajustar la configuración básica

RabbitMQ lee /etc/rabbitmq/rabbitmq.conf, que no existe tras la instalación. Créalo con los ajustes más relevantes:

sudo nano /etc/rabbitmq/rabbitmq.conf
# Puerto AMQP
listeners.tcp.default = 5672

# Consola de gestión (se activa en el paso 5)
management.tcp.port = 15672

# Bloquea a los publicadores cuando RabbitMQ usa el 60 % de la RAM
vm_memory_high_watermark.relative = 0.6

# Bloquea a los publicadores si quedan menos de 2 GB libres en disco
disk_free_limit.absolute = 2GB

# El usuario guest solo puede conectarse desde localhost (valor por defecto, explícito)
loopback_users.guest = true

Reinicia el servicio y confirma que arranca sin errores:

sudo systemctl restart rabbitmq-server
sudo rabbitmq-diagnostics check_running
Checking if RabbitMQ is running on node rabbit@your_hostname ...
RabbitMQ on node rabbit@your_hostname is fully booted and running

Si el servicio no arranca, revisa los errores con sudo journalctl -u rabbitmq-server -n 50. Los logs detallados están en /var/log/rabbitmq/.

Paso 4: Crear un host virtual y usuarios

Los hosts virtuales (vhosts) aíslan colas, exchanges y permisos. Crea uno para tu aplicación:

sudo rabbitmqctl add_vhost app

Crea un usuario administrador para la consola y otro para la aplicación. Sustituye las contraseñas por unas robustas:

sudo rabbitmqctl add_user admin 'your_admin_password'
sudo rabbitmqctl set_user_tags admin administrator
sudo rabbitmqctl set_permissions -p app admin ".*" ".*" ".*"
sudo rabbitmqctl add_user app_user 'your_app_password'
sudo rabbitmqctl set_permissions -p app app_user "^orders.*" "^orders.*" "^orders.*"

Los tres patrones de set_permissions son, en orden, los permisos de configurar, escribir y leer. Con ^orders.*, app_user solo puede declarar y usar exchanges y colas cuyo nombre empiece por orders.

Elimina el usuario guest, que tiene una contraseña conocida:

sudo rabbitmqctl delete_user guest

Verifica usuarios y permisos:

sudo rabbitmqctl list_users
sudo rabbitmqctl list_permissions -p app
Listing permissions for vhost "app" ...
user	configure	write	read
admin	.*	.*	.*
app_user	^orders.*	^orders.*	^orders.*

Paso 5: Activar la consola de gestión

El plugin de gestión añade una interfaz web y una API HTTP en el puerto 15672:

sudo rabbitmq-plugins enable rabbitmq_management

No expongas la consola a Internet. Accede a ella a través de un túnel SSH desde tu equipo:

ssh -L 15672:127.0.0.1:15672 your_user@your_server_ip

Con el túnel abierto, visita http://localhost:15672 en tu navegador e inicia sesión con el usuario admin. Verás la vista general con el nodo, las conexiones y las colas.

Abre el puerto AMQP solo a los servidores de aplicación que lo necesiten. Sustituye app_server_ip por la IP (idealmente privada) de cada cliente:

sudo ufw allow from app_server_ip to any port 5672 proto tcp
sudo ufw status

Paso 6: Publicar y consumir mensajes con Python

Vas a crear un exchange de tipo topic llamado orders, dos colas y sus bindings, y a enviar mensajes con la librería pika, disponible como paquete de Ubuntu:

sudo apt install python3-pika

Crea el script del productor:

nano ~/producer.py
#!/usr/bin/env python3
import json
import pika

credentials = pika.PlainCredentials("app_user", "your_app_password")
params = pika.ConnectionParameters("127.0.0.1", 5672, "app", credentials)

connection = pika.BlockingConnection(params)
channel = connection.channel()

# Exchange de tipo topic que sobrevive a reinicios
channel.exchange_declare(exchange="orders", exchange_type="topic", durable=True)

# Colas quorum: replicadas y pensadas para no perder mensajes
for queue, key in (("orders.created", "order.created"), ("orders.all", "order.#")):
    channel.queue_declare(queue=queue, durable=True, arguments={"x-queue-type": "quorum"})
    channel.queue_bind(queue=queue, exchange="orders", routing_key=key)

# Confirmaciones del broker: basic_publish falla si el mensaje no se acepta
channel.confirm_delivery()

for order_id in range(1, 6):
    body = json.dumps({"order_id": order_id, "total": 19.90})
    channel.basic_publish(
        exchange="orders",
        routing_key="order.created",
        body=body,
        properties=pika.BasicProperties(delivery_mode=2,  # mensaje persistente
                                        content_type="application/json"),
    )
    print(f"Enviado pedido {order_id}")

connection.close()

Crea el consumidor, que confirma cada mensaje solo después de procesarlo:

nano ~/consumer.py
#!/usr/bin/env python3
import json
import pika

credentials = pika.PlainCredentials("app_user", "your_app_password")
params = pika.ConnectionParameters("127.0.0.1", 5672, "app", credentials)

connection = pika.BlockingConnection(params)
channel = connection.channel()

# Como máximo 10 mensajes sin confirmar por consumidor
channel.basic_qos(prefetch_count=10)


def handle(ch, method, properties, body):
    order = json.loads(body)
    print(f"Procesando pedido {order['order_id']}")
    ch.basic_ack(delivery_tag=method.delivery_tag)


channel.basic_consume(queue="orders.created", on_message_callback=handle)
print("Esperando mensajes. Pulsa Ctrl+C para salir.")
try:
    channel.start_consuming()
except KeyboardInterrupt:
    channel.stop_consuming()
connection.close()

Ejecuta el productor:

python3 ~/producer.py
Enviado pedido 1
Enviado pedido 2
Enviado pedido 3
Enviado pedido 4
Enviado pedido 5

Comprueba que los mensajes están en ambas colas, porque la routing key order.created coincide con los dos bindings:

sudo rabbitmqctl list_queues -p app name type messages
name	type	messages
orders.created	quorum	5
orders.all	quorum	5

Ejecuta el consumidor:

python3 ~/consumer.py
Esperando mensajes. Pulsa Ctrl+C para salir.
Procesando pedido 1
Procesando pedido 2
Procesando pedido 3
Procesando pedido 4
Procesando pedido 5

Pulsa Ctrl+C y vuelve a listar las colas: orders.created estará a 0 y orders.all seguirá con 5 mensajes, porque nadie la consume. También puedes revisar los bindings creados con sudo rabbitmqctl list_bindings -p app.

Paso 7: Limitar el tamaño de las colas con políticas

Una cola sin consumidores crece hasta agotar memoria o disco. Las políticas aplican límites a varias colas a la vez sin tocar el código. Esta limita las colas que empiezan por orders. a 100.000 mensajes y descarta los más antiguos al superarlo:

sudo rabbitmqctl set_policy -p app orders-limits "^orders\." \
  '{"max-length": 100000, "overflow": "drop-head"}' --apply-to queues

Comprueba que se aplica:

sudo rabbitmqctl list_policies -p app
sudo rabbitmqctl list_queues -p app name policy
name	policy
orders.created	orders-limits
orders.all	orders-limits

Si prefieres que los publicadores reciban un rechazo en vez de perder los mensajes más antiguos, usa "overflow": "reject-publish".

Solución de problemas

  • ACCESS_REFUSED - Login was refused: usuario o contraseña incorrectos, o intentas usar guest desde otra máquina. Crea un usuario propio como en el paso 4.
  • ACCESS_REFUSED ... access to queue ... refused: el nombre de la cola o del exchange no encaja con los patrones de set_permissions.
  • Los publicadores se quedan bloqueados: se ha disparado una alarma de memoria o de disco. Compruébalo con sudo rabbitmq-diagnostics alarms y libera espacio o ajusta los umbrales del paso 3.
  • El nodo no arranca tras cambiar el hostname: RabbitMQ guarda los datos bajo el nombre rabbit@hostname. Mantén el hostname estable en servidores con RabbitMQ.

Conclusión

Tienes RabbitMQ instalado desde el repositorio oficial, con un vhost aislado, usuarios con permisos mínimos, la consola web accesible por túnel SSH y un flujo de productor y consumidor con colas quorum y confirmaciones. Como siguientes pasos, configura TLS para las conexiones AMQP, añade una política de dead-lettering para los mensajes que fallen y, si necesitas alta disponibilidad, forma un clúster de tres nodos para que las colas quorum se repliquen.