> ## Documentation Index
> Fetch the complete documentation index at: https://docs.minimus.io/llms.txt
> Use this file to discover all available pages before exploring further.

# RabbitMQ TLS Tutorial

> A guide to setting up RabbitMQ and testing that it accepts TLS connections, enforces authentication, and allows secure read/write operations from a test client

The following guide deploys the Minimus RabbitMQ image together with custom self-signed, locally issued certificates generated with OpenSSL to help you get started. The tutorial is appropriate for local development, internal services, and private clusters.

## What this guide demonstrates

* TLS handshake validation
* Server certificate trust
* Basic auth and RabbitMQ DB operations
* Image compatibility

### Components

* **RabbitMQ image built by Minimus**: RabbitMQ configured for TLS on both the AMQP port (5671) and the management API port (15671).
* **certgen.sh script**: Dynamic certificate generation shell script that uses OpenSSL.
* **minidebug image**: A Minimus dev toolkit that provides a shell, OpenSSL, and other utilities used to generate the certificates.

### Directory Structure

```bash theme={null}
.
├── certgen.sh             # Certificate generation script
├── create-certs.yml       # Compose file to run certgen container
├── certs/                 # Generated certificates (created by certgen.sh)
│   ├── ca_certificate.pem
│   ├── server_certificate.pem
│   └── server_key.pem
├── rabbitmq.conf          # RabbitMQ config file for TLS
├── enabled_plugins        # Enables the management plugin
└── docker-compose.yml     # Compose file to run RabbitMQ
```

### 2 TLS listeners for 2 trust models

This setup configures two independent TLS listeners, each with a different trust requirement:

* **AMQP (`5671`)** — This is the protocol port your messaging clients connect to.

  `ssl_options.verify = verify_none` means the server presents its certificate for the client to trust, but never asks the client for one back. Hence, no client certificate is required.

* **Management API (`15671`)** — This is used by `rabbitmqadmin`, `curl`, and the management UI.

  `management.ssl.verify = verify_peer` means the server will validate a client certificate if one is presented, but `fail_if_no_peer_cert = false` makes presenting one optional.

For local development and testing, server-side trust is sufficient: the CA certificate alone (`--cacert` / `--ssl-ca-cert-file`) is all a client needs to establish the TLS connections, so this guide skips generating a client certificate. If you later move this setup toward a multi-tenant or zero-trust environment, you can require client certificates on either listener by switching `fail_if_no_peer_cert` to `true`.

## Deploy RabbitMQ with TLS certificates

### Step 1: Generate TLS certificates

<Steps>
  <Step title="Save script that generates TLS certificates">
    Save the following script to a file named `certgen.sh`. The script is used to generate the self-signed CA and server certificates and store them in a `certs` folder in a Docker volume.

    ```bash certgen.sh expandable lines theme={null}
    #!/bin/sh
    set -e
    cd /certs

    cat > openssl.cnf <<EOF
    [req]
    distinguished_name = req_distinguished_name
    req_extensions = v3_req
    prompt = no

    [req_distinguished_name]
    CN = rabbitmq

    [v3_req]
    keyUsage = keyEncipherment, dataEncipherment
    extendedKeyUsage = serverAuth, clientAuth
    subjectAltName = @alt_names

    [alt_names]
    DNS.1 = rabbitmq
    DNS.2 = localhost
    IP.1 = 127.0.0.1
    IP.2 = 192.168.20.0
    IP.3 = 192.168.20.2
    IP.4 = 192.168.20.3

    [v3_ca]
    subjectKeyIdentifier=hash
    authorityKeyIdentifier=keyid:always,issuer
    basicConstraints = critical, CA:true
    keyUsage = critical, keyCertSign, cRLSign
    EOF

    # Generate CA
    openssl genrsa -out ca-key.pem 2048
    openssl req -x509 -new -nodes -key ca-key.pem -sha256 -days 365 \
      -out ca_certificate.pem \
      -subj "/CN=Test CA" -extensions v3_ca -config openssl.cnf

    # Generate server cert
    openssl genrsa -out server_key.pem 2048
    openssl req -new -key server_key.pem -out server.csr -config openssl.cnf -extensions v3_req
    openssl x509 -req -in server.csr -CA ca_certificate.pem -CAkey ca-key.pem -CAcreateserial \
      -out server_certificate.pem -days 365 -sha256 -extfile openssl.cnf -extensions v3_req

    chmod 600 *.pem
    chown -R 1000:1000 /certs/*.pem
    chmod 644 /certs/*.pem
    ```
  </Step>

  <Step title="Save Docker Compose configuration">
    Save the following YAML configuration to a file named `create-certs.yml`. The configuration uses the [**Minimus minidebug image**](https://images.minimus.io/gallery/images/minidebug/quick-start?__hstc=180987128.11065ee83c8bdcec1851176c12d849d3.1762436227738.1762436227738.1762436227738.1&__hssc=180987128.1.1762436227739&__hsfp=2666866004) to generate the certificates with the `certgen.sh` shell script. Minidebug is a Minimus dev toolkit that provides a shell, OpenSSL, and other utilities.

    ```yaml create-certs.yml theme={null}
    services:
      create_certs:
        image: reg.mini.dev/minidebug:latest
        container_name: rabbit_certs
        volumes:
        - ./certs:/certs
        - ./certgen.sh:/certgen.sh:ro
        entrypoint:
        - /bin/sh
        - /certgen.sh
        network_mode: none
    ```
  </Step>

  <Step title="Generate certificates">
    Run the following to generate the certificates:

    <CodeGroup>
      ```shellscript Run command theme={null}
      docker compose -f create-certs.yml up
      ```

      ```shellscript Expected output theme={null}
      WARN[0000] No services to build
      [+] up 1/1
       ✔ Container rabbit_certs Created                                                                        0.2s
      Attaching to rabbit_certs
      rabbit_certs  | Certificate request self-signature ok
      rabbit_certs  | subject=CN=rabbitmq
      rabbit_certs exited with code 0
      ```
    </CodeGroup>
  </Step>
</Steps>

Congrats! You have just generated the following self-signed certificates:

* CA certificate (`ca_certificate.pem`)
* Server certificate and key (`server_certificate.pem`, `server_key.pem`) valid for `rabbitmq`, `localhost`, `127.0.0.1`, `192.168.20.0`, `192.168.20.2`, and `192.168.20.3`

The setup ensures:

* Proper SANs for `rabbitmq` and `localhost`
* Server cert with both `serverAuth` and `clientAuth` extended key usage

In the next steps, you will mount these certificates into the RabbitMQ container.

### Step 2: Deploy RabbitMQ server

<Steps>
  <Step title="Save the configuration file">
    Save the configuration to a file named `rabbitmq.conf`.

    ```bash rabbitmq.conf theme={null}
    ## AMQP TLS listener
    listeners.ssl.default = 5671

    ssl_options.cacertfile = /certs/ca_certificate.pem
    ssl_options.certfile   = /certs/server_certificate.pem
    ssl_options.keyfile    = /certs/server_key.pem
    ssl_options.verify     = verify_none
    ssl_options.fail_if_no_peer_cert = false

    ## Allow remote login for non-guest users
    loopback_users.guest = false

    ## Management API over HTTPS
    management.ssl.port = 15671
    management.ssl.cacertfile = /certs/ca_certificate.pem
    management.ssl.certfile   = /certs/server_certificate.pem
    management.ssl.keyfile    = /certs/server_key.pem
    management.ssl.verify     = verify_peer
    management.ssl.fail_if_no_peer_cert = false
    ```
  </Step>

  <Step title="Save the enabled plugins">
    Save the enabled plugins file.

    ```bash enabled_plugins theme={null}
    [rabbitmq_management].
    ```
  </Step>

  <Step title="Save Docker Compose script">
    Save the following Docker Compose script to a file named `docker-compose.yml`. This script sets up the RabbitMQ service with a healthcheck, mounts a volume with the certificates, maps ports 15671 and 5671.

    ```yaml docker-compose.yml expandable theme={null}
    services:
      rabbitmq:
        image: reg.mini.dev/rabbitmq:latest-dev
        container_name: rabbitmq-lts
        volumes:
          - ./certs:/certs:ro
          - ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro
          - ./enabled_plugins:/etc/rabbitmq/enabled_plugins:ro
        environment:
          RABBITMQ_DEFAULT_USER: testuser
          RABBITMQ_DEFAULT_PASS: testpass
        ports:
          - "5671:5671"     # AMQP over TLS
          - "15671:15671"   # Management UI over TLS
    ```
  </Step>

  <Step title="Run RabbitMQ">
    Start the RabbitMQ container:

    <CodeGroup>
      ```text Run command theme={null}
      docker compose -f docker-compose.yml up -d
      ```

      ```shellscript Expected output theme={null}
       ✔ Image reg.mini.dev/rabbitmq:latest-dev Pulled                                                        15.1s
      ...
       ✔ Network rabbitmq-test_default          Created                                                        0.1s
       ✔ Container rabbitmq-lts                 Created   
      ```
    </CodeGroup>
  </Step>
</Steps>

### Step 3: Test your RabbitMQ server

We will use `rabbitmqadmin`, the RabbitMQ CLI, to connect over TLS and run tests. For example, here are a few commands you can try out:

1. Check db health:

   <CodeGroup>
     ```bash Check status theme={null}
     docker exec -it rabbitmq-lts rabbitmqctl status
     curl -u testuser:testpass https://localhost:15671/api/healthchecks/node \
       --cacert ./certs/ca_certificate.pem
     ```

     ```yaml Expected output theme={null}
     Runtime

     OS PID: 13
     OS: Linux
     Uptime (seconds): 356
     Is under maintenance?: false
     RabbitMQ version: ...
     RabbitMQ release series support status: see https://www.rabbitmq.com/release-information
     Node name: rabbit@...
     Erlang configuration: ...
     Crypto library: OpenSSL ...
     Erlang processes: 411 used, 1048576 limit
     Scheduler run queue: 1
     Cluster heartbeat timeout (net_ticktime): 60

     Plugins

     Enabled plugin file: /etc/rabbitmq/enabled_plugins
     Enabled plugins:

      * rabbitmq_management
      * rabbitmq_management_agent
      * rabbitmq_web_dispatch
      * amqp_client
      * cowboy
      * oauth2_client
     ...

     Listeners

     Interface: [::], port: 15671, protocol: https, purpose: HTTP API over TLS (HTTPS)
     Interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
     Interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
     Interface: [::], port: 5671, protocol: amqp/ssl, purpose: AMQP 0-9-1 and AMQP 1.0 over TLS
     ```
   </CodeGroup>
2. Verify the AMQP TLS listener itself (port `5671`) with `openssl s_client`. This confirms the handshake and certificate the broker presents to actual messaging clients, independent of the management API tested in the next step:

   <CodeGroup>
     ```bash Check AMQP TLS handshake theme={null}
     echo | openssl s_client -connect localhost:5671 -CAfile ./certs/ca_certificate.pem
     ```

     ```text Expected output theme={null}
     CONNECTED(00000003)
     depth=1 CN = Test CA
     verify return:1
     depth=0 CN = rabbitmq
     verify return:1
     ---
     Certificate chain
      0 s:CN = rabbitmq
        i:CN = Test CA
      1 s:CN = Test CA
        i:CN = Test CA
     ---
     ...
     subject=CN = rabbitmq
     issuer=CN = Test CA
     ---
     Verification: OK
     ---
     New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
     ...
     Verify return code: 0 (ok)
     ---
     DONE
     ```
   </CodeGroup>

   <Info>
     `openssl s_client` runs on your host machine, not inside the container, so the verify result depends on the OpenSSL build installed there. You may see either `Verify return code: 0 (ok)` or `19 (self-signed certificate in certificate chain)` — both mean the handshake succeeded using the certificate signed by your CA. Messaging client libraries (`pika`, `amqplib`, etc.) that trust the CA connect the same way regardless.
   </Info>
3. Test connectivity using `rabbitmqadmin`. Note that `rabbitmqadmin` talks to the management HTTP API, so it connects on port `15671` (the TLS management port), not the AMQP port `5671`:

   <CodeGroup>
     ```bash Test connectivity theme={null}
     rabbitmqadmin \
       --host=localhost \
       --port=15671 \
       --username=testuser \
       --password=testpass \
       --ssl \
       --ssl-ca-cert-file=./certs/ca_certificate.pem \
       list queues
     ```

     ```text Expected output theme={null}
     No items
     ```
   </CodeGroup>
4. Create a test vhost (for example `test_vhost`). A vhost is RabbitMQ's equivalent of a database — a logically separate group of queues, exchanges, and permissions:

   <CodeGroup>
     ```bash Create vhost theme={null}
     rabbitmqadmin \
       --host=localhost \
       --port=15671 \
       --username=testuser \
       --password=testpass \
       --ssl \
       --ssl-ca-cert-file=./certs/ca_certificate.pem \
       declare vhost name=test_vhost
     ```

     ```bash Expected response theme={null}
     vhost declared
     ```
   </CodeGroup>
5. List all vhosts.

   <CodeGroup>
     ```bash List all vhosts theme={null}
     rabbitmqadmin \
       --host=localhost \
       --port=15671 \
       --username=testuser \
       --password=testpass \
       --ssl \
       --ssl-ca-cert-file=./certs/ca_certificate.pem \
       list vhosts
     ```

     ```text Expected output theme={null}
     +------------+----------+
     |    name    | messages |
     +------------+----------+
     | /          |          |
     | test_vhost |          |
     +------------+----------+
     ```
   </CodeGroup>
6. Declare a durable queue named `docs` in `test_vhost` (the equivalent of creating a collection):

   ```bash theme={null}
   rabbitmqadmin \
     --host=localhost \
     --port=15671 \
     --username=testuser \
     --password=testpass \
     --ssl \
     --ssl-ca-cert-file=./certs/ca_certificate.pem \
     --vhost=test_vhost \
     declare queue name=docs durable=true
   ```

   Then publish a message to it:

   ```bash theme={null}
   rabbitmqadmin \
     --host=localhost \
     --port=15671 \
     --username=testuser \
     --password=testpass \
     --ssl \
     --ssl-ca-cert-file=./certs/ca_certificate.pem \
     --vhost=test_vhost \
     publish exchange=amq.default routing_key=docs payload="Welcome to TLS RabbitMQ running on a Minimus image"
   ```
7. Create a user (for example, `appuser` with read/write/configure permissions on `test_vhost`), get the user's permission details, and delete the user:

   <CodeGroup>
     ```bash Create user theme={null}
     rabbitmqadmin \
       --host=localhost \
       --port=15671 \
       --username=testuser \
       --password=testpass \
       --ssl \
       --ssl-ca-cert-file=./certs/ca_certificate.pem \
       declare user name=appuser password=apppass tags=management

     rabbitmqadmin \
       --host=localhost \
       --port=15671 \
       --username=testuser \
       --password=testpass \
       --ssl \
       --ssl-ca-cert-file=./certs/ca_certificate.pem \
       declare permission vhost=test_vhost user=appuser configure=.* write=.* read=.*
     ```

     ```bash Get user details theme={null}
     docker exec -it rabbitmq-lts rabbitmqctl list_user_permissions appuser
     ```

     ```text Expected output theme={null}
     Listing permissions for user "appuser" ...
     vhost   configure       write   read
     test_vhost      .*      .*      .*
     ```

     ```bash Delete user theme={null}
     rabbitmqadmin \
       --host=localhost \
       --port=15671 \
       --username=testuser \
       --password=testpass \
       --ssl \
       --ssl-ca-cert-file=./certs/ca_certificate.pem \
       delete user name=appuser
     ```
   </CodeGroup>
8. Publish a new message to the queue:

   <CodeGroup>
     ```bash Publish message theme={null}
     rabbitmqadmin \
       --host=localhost \
       --port=15671 \
       --username=testuser \
       --password=testpass \
       --ssl \
       --ssl-ca-cert-file=./certs/ca_certificate.pem \
       --vhost=test_vhost \
       publish exchange=amq.default routing_key=docs payload="Welcome to TLS RabbitMQ running Minimus image"
     ```

     ```bash Expected response theme={null}
     Message published
     ```
   </CodeGroup>
9. Get all messages from the queue:
   ```bash theme={null}
   rabbitmqadmin \
     --host=localhost \
     --port=15671 \
     --username=testuser \
     --password=testpass \
     --ssl \
     --ssl-ca-cert-file=./certs/ca_certificate.pem \
     --vhost=test_vhost \
     get queue=docs count=10 ackmode=ack_requeue_false
   ```
10. Delete the vhost:

    <CodeGroup>
      ```bash Delete vhost theme={null}
      rabbitmqadmin \
        --host=localhost \
        --port=15671 \
        --username=testuser \
        --password=testpass \
        --ssl \
        --ssl-ca-cert-file=./certs/ca_certificate.pem \
        delete vhost name=test_vhost
      ```

      ```bash Expected response theme={null}
      vhost deleted
      ```
    </CodeGroup>
