Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Deploying RabbitMQ With Docker

Below is a BASH script you can use to deploy your own RabbitMQ server using docker. There are many different ways to configure your deployment, but this is a broad generic method that will:

  • Deploy with the web interface to manage your server.
  • Specify a username and password for managing the server.
  • Use a volume to keep state across containers being created/destroyed.
  • Uses port 80 for the web interface so that you can just go to the hostname in your browser without having to enter a port number.

Server Requirements

#!/bin/bash

# Settings
CONTAINER_NAME="rabbitmq-container"
DEFAULT_USER="root"
DEFAULT_PASSWORD="myPassword"
CLUSTER_COOKIE="hello world"
HOSTNAME="rabbitmq.mydomain.com"

# Don't change below this line.
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
docker kill $CONTAINER_NAME
docker rm $CONTAINER_NAME

docker run -d \
  --restart=always \
  --hostname $HOSTNAME \
  --name $CONTAINER_NAME \
  -p 4369:4369 \
  -p 5671:5671 \
  -p 5672:5672 \
  -p 443:15671 \
  -p 80:15672 \
  -p 25672:25672 \
  -p 15691:15691 \
  -p 15692:15692 \
  -e RABBITMQ_ERLANG_COOKIE="$CLUSTER_COOKIE" \
  -e RABBITMQ_DEFAULT_USER="$DEFAULT_USER" \
  -e RABBITMQ_DEFAULT_PASS="$DEFAULT_PASSWORD" \
  -v $DIR/rabbitmq-state:/var/lib/rabbitmq \
  rabbitmq:3.13-management

Docker Compose

If you wish to deploy through Docker Compose, then here is an example file:

services:
  rabbitmq:
    image: rabbitmq:3.13-management
    hostname: ${HOSTNAME}
    container_name: rabbitmq
    restart: always
    ports:
      - "4369:4369" # empd - peer discovery service
      - "5671:5671" # TLS  AMQP 0-9-1 and AMQP 1.0 clients
      - "5672:5672" # Plain AMQP 0-9-1 and AMQP 1.0 clients
      - "443:15671" # management HTTPS port
      - "80:15672" # management HTTP port
      - "25672:25672" # used for inter-node and CLI tools communication (Erlang distribution server port)
      - "15691:15691" # prometheus metrics HTTPS port
      - "15692:15692" # prometheus metrics HTTP port
    volumes:
      - rabbitmq-data:/var/lib/rabbitmq
    environment:
      - RABBITMQ_ERLANG_COOKIE=${CLUSTER_COOKIE}
      - RABBITMQ_DEFAULT_USER=${DEFAULT_USER}
      - RABBITMQ_DEFAULT_PASS=${DEFAULT_PASSWORD}

volumes:
  rabbitmq-data:
    driver: local

Just be sure to create a .env file with the following variables (filling in the values).

COMPOSE_PROJECT_NAME="rabbitmq"

CLUSTER_COOKIE=""
DEFAULT_USER=""
DEFAULT_PASSWORD=""

Optional - Nginx Proxy Configuration

If you want to have an Nginx proxy handle the TLS certificate termination for your management UI, you can use the following config:

server {
    listen 80;
    server_name rabbitmq.mydomain.com;
    access_log  /var/log/nginx/access.log;
    return 302 https://rabbitmq.mydomain.com$request_uri;
}


server {
    listen 443 ssl;
    server_name rabbitmq.mydomain.com;

    access_log  /var/log/nginx/access.log;
    error_log   /var/log/nginx/error.log;

    ssl_certificate       /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key   /etc/nginx/ssl/privkey.pem;

    ssl_protocols               TLSv1.2 TLSv1.3;
    ssl_ciphers                 RC4:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers   on;
    keepalive_timeout           60;
    ssl_session_cache           shared:SSL:10m;
    ssl_session_timeout         10m;

    location / {
        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;
        real_ip_header X-Forwarded-For;
        proxy_pass  http://192.168.xxx.xxx;
    }
}

Make sure to update the IP address in the proxy_pass value, as well as update the server_name.

Optional - Adding TLS To RabbitMQ Management Interface

If you don't want to use a reverse proxy, and want to add TLS certificates to RabbitMQ's management interaface directly, one can do so by adding a configuration file to RabbitMQ that tells it that you wish to do this, and telling it where the certificates are.

Firstly, we need to create the relevant folders for our TLS/SSL certificates and the configuration file:

mkdir -p ./volumes/configs
mkdir -p ./volumes/ssl

Then copy/paste the certificate files into the ssl folder with the names:

  • chain.pem - the certificate authority file.
  • cert.pem - the site certificate file (on its own, not bundlded with the chain/ca).
  • privkey.pem - the private key

Finally, create the RabbitMQ configuration file:

editor ./volumes/configs/rabbitmq.conf

... and give it the following content:

## allow access to the guest user from anywhere on the network
## https://www.rabbitmq.com/access-control.html#loopback-users
## https://www.rabbitmq.com/production-checklist.html#users
loopback_users.guest = false

## Send all logs to stdout/TTY. Necessary to see logs when running via
## a container
log.console = true

# Specify the plain HTTP port for the management interface
management.tcp.port = 15672

# Specify the TLS port for the management interface
management.ssl.port = 15671

# A new style format snippet. This format is used by rabbitmq.conf files.
management.ssl.cacertfile           = /etc/rabbitmq/ssl/chain.pem
management.ssl.certfile             = /etc/rabbitmq/ssl/cert.pem
management.ssl.keyfile              = /etc/rabbitmq/ssl/privkey.pem

Then update your docker-compose file to be like so:

services:
  rabbitmq:
    image: rabbitmq:3.13-management
    hostname: ${HOSTNAME}
    container_name: rabbitmq
    restart: always
    ports:
      - "4369:4369" # empd - peer discovery service
      - "5671:5671" # TLS  AMQP 0-9-1 and AMQP 1.0 clients
      - "5672:5672" # Plain AMQP 0-9-1 and AMQP 1.0 clients
      - "443:15671" # management HTTPS port
      - "80:15672" # management HTTP port
      - "25672:25672" # used for inter-node and CLI tools communication (Erlang distribution server port)
      - "15691:15691" # prometheus metrics HTTPS port
      - "15692:15692" # prometheus metrics HTTP port
    volumes:
      - ./volumes/rabbitmq-data:/var/lib/rabbitmq
      - ./volumes/configs:/etc/rabbitmq/conf.d:ro
      - ./volumes/ssl:/etc/rabbitmq/ssl:ro
    environment:
      - RABBITMQ_ERLANG_COOKIE=${CLUSTER_COOKIE}
      - RABBITMQ_DEFAULT_USER=${DEFAULT_USER}
      - RABBITMQ_DEFAULT_PASS=${DEFAULT_PASSWORD}

volumes:
  rabbitmq-data:
    driver: local

Optional - Adding TLS For Prometheus Monitoring Connections

If you wish to add TLS to the AMQP connections, then you can simply add another configuration file like so:

editor ./volumes/configs/prometheus-tls.conf
prometheus.ssl.port       = 15691
prometheus.ssl.cacertfile = /etc/rabbitmq/ssl/chain.pem
prometheus.ssl.certfile   = /etc/rabbitmq/ssl/cert.pem
prometheus.ssl.keyfile    = /etc/rabbitmq/ssl/privkey.pem


# Comment out the line below if you still wish to allow non-encrypted connections
prometheus.tcp.listener = none


# Uncomment the lines below if you wish to use TLS peer verification
# whereby the client connecting must provide a TLS certificate signed
# by your certificate authority.
#
#prometheus.ssl.verify     = verify_peer
#prometheus.ssl.depth      = 2
#prometheus.ssl.fail_if_no_peer_cert = true

Optional - Adding TLS For AMQP Connections

If you wish to add TLS to the AMQP connections, then you can simply add another configuration file like so:

editor ./volumes/configs/amqp-tls.conf

... and give it the following content

# Specify the AMQP TLS port
listeners.ssl.default = 5671

# Specify certificate file locations
ssl_options.cacertfile         = /etc/rabbitmq/ssl/chain.pem
ssl_options.certfile             = /etc/rabbitmq/ssl/cert.pem
ssl_options.keyfile              = /etc/rabbitmq/ssl/privkey.pem

# Do not perform peer TLS verification
ssl_options.verify               = verify_none
ssl_options.fail_if_no_peer_cert = false

This assumes you are using the exact same set of certificate files. If you wish to use a different set, then change the filenames in the paths, and add that set of certificates to your ssl folder.

Strict Client Checking

The configuration above allows non-TLS connections to still occur. If you wish to disable that, and force the server to verify the clients connecting to the server, then use the following configuration content instead.

# disables non-TLS listeners, only TLS-enabled clients will be able to connect
listeners.tcp = none

# Specify the TLS port
listeners.ssl.default = 5671

# Specify certificate file locations
ssl_options.cacertfile           = /etc/rabbitmq/ssl/chain.pem
ssl_options.certfile             = /etc/rabbitmq/ssl/cert.pem
ssl_options.keyfile              = /etc/rabbitmq/ssl/privkey.pem

# Verify peer and fail if they do not have a valid certificate.
ssl_options.verify               = verify_peer
ssl_options.fail_if_no_peer_cert = true

Hostname Is Important

You will see that we specify the hostname in both the docker run commands and the docker compose files. This is because it is very important for the data persistence as RabbitMQ uses the hostname as part of the folder name in the mnesia directory.

References

Last updated: 9th July 2024
First published: 16th August 2018

This blog is created by Stuart Page

I'm a freelance web developer and technology consultant based in Surrey, UK, with over 10 years experience in web development, DevOps, Linux Administration, and IT solutions.

Need support with your infrastructure or web services?

Get in touch