Skip to content

RabbitMQ ​

UseImageStatus
RabbitMQrabbitmq:4.3.5-managementdefault

Pinned, as every compose file and Dockerfile writes them:

text
rabbitmq:4.3.5-management@sha256:57bddb6fbc3498b5d8b5a14dc6f4506073ebcf94c66ba2a7678c335faa8dd631

The tag and digest come from the approved images table; when they disagree, the table wins. RabbitMQ publishes no Debian variant: 4.3.5-management is Ubuntu 24.04, the glibc choice, for the same reason as the rest (see rule 4).

Local development ​

docker run
sh
docker run -d --name rabbitmq-dev --hostname rabbitmq-dev \
  -p 127.0.0.1:5672:5672 -p 127.0.0.1:15672:15672 \
  -e RABBITMQ_DEFAULT_USER=app -e RABBITMQ_DEFAULT_PASS=dev \
  -v rabbitmq-dev-data:/var/lib/rabbitmq \
  --health-cmd 'rabbitmq-diagnostics -q ping' \
  --health-interval 10s --health-timeout 10s --health-retries 12 \
  rabbitmq:4.3.5-management@sha256:57bddb6fbc3498b5d8b5a14dc6f4506073ebcf94c66ba2a7678c335faa8dd631
check docker run
sh
docker exec rabbitmq-dev rabbitmqctl list_users

Connect with amqp://app:dev@127.0.0.1:5672/; the management UI is on http://127.0.0.1:15672. Remove it, data included, with docker rm -f rabbitmq-dev && docker volume rm rabbitmq-dev-data.

On a server ​

Prepare the host once, next to the compose file. The user and password are in a config folder mounted read-only (see config mounts) and owned by the rabbitmq user. The folder replaces the image's own conf.d, so it carries the image's one setting worth keeping, logging to the console.

prepare the host
sh
mkdir -p rabbitmq
cat > rabbitmq/10-app.conf <<CONF
log.console = true
default_user = app
default_pass = $(openssl rand -hex 24)
CONF
sudo chown -R 999:999 rabbitmq
sudo chmod 0400 rabbitmq/10-app.conf
compose.yml
yaml
services:
  rabbitmq:
    image: rabbitmq:4.3.5-management@sha256:57bddb6fbc3498b5d8b5a14dc6f4506073ebcf94c66ba2a7678c335faa8dd631
    hostname: rabbitmq
    volumes:
      - ./rabbitmq:/etc/rabbitmq/conf.d:ro
      - rabbitmq-data:/var/lib/rabbitmq
    ports:
      - "127.0.0.1:5672:5672"
      - "127.0.0.1:15672:15672"
    read_only: true
    tmpfs:
      - /tmp:size=64m,mode=1777
    cap_drop: [ALL]
    cap_add: [CHOWN, SETGID, SETUID]
    security_opt:
      - no-new-privileges:true
    healthcheck:
      test: ["CMD", "setpriv", "--reuid=rabbitmq", "--regid=rabbitmq", "--init-groups", "rabbitmq-diagnostics", "-q", "ping"]
      interval: 10s
      timeout: 10s
      retries: 5
      start_period: 30s
    stop_grace_period: 1m
    restart: unless-stopped
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

volumes:
  rabbitmq-data: {}
check compose
sh
docker compose exec -u rabbitmq rabbitmq rabbitmqctl list_users

The service connects with the same password, from its own .env, as amqp://app:<password>@rabbitmq:5672/.

Why each line is there:

  • hostname: rabbitmq. RabbitMQ names its node rabbit@<hostname> and keeps its data under that name. Without a fixed hostname every new container is a new node, and the queues in the volume are not found.
  • default_user replaces guest. With it set, the guest user is never created; the image's own default lets guest in from anywhere.
  • The health check runs as rabbitmq. rabbitmq-diagnostics needs the Erlang cookie, which only the rabbitmq user can read once root has no DAC_OVERRIDE.
  • The capabilities. The entrypoint starts as root, fixes the data folder's owner and drops to the rabbitmq user (999); these three are what that needs.
  • read_only. RabbitMQ writes only to /var/lib/rabbitmq and /tmp.
  • Ports on 127.0.0.1. The management UI and AMQP are reached by the services over the compose network; the loopback ports are for a person on the host.

Upgrading from 3 ​

  • Upgrade from 3.13 only, with every stable feature flag enabled first (rabbitmqctl enable_feature_flag all). An older 3.x goes to 3.13 before 4.
  • Classic mirrored queues are gone in 4. Queues that relied on mirroring become quorum queues (x-queue-type: quorum).
  • A transient, non-exclusive queue declaration makes RabbitMQ 4 close the connection. A client that declares one on every reconnect loops forever. Check what each service declares before it moves: durable, or exclusive.