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

# RabbitMQ

> Deploy RabbitMQ on Control Plane using the Template Catalog. A single-node message broker with the management plugin and a persistent volume, installed into an existing GVC. Covers the prerequisite credentials secret, connecting, backing up definitions, and upgrading from template version 1.1.1.

## Overview

RabbitMQ is a widely-used open-source message broker that queues, routes and delivers messages between services over AMQP 0-9-1. This template deploys a single-replica broker with the management plugin enabled, backed by a persistent volume so queues, messages and the user database survive a restart.

The broker's default user is not a template value. It comes from a dictionary secret you create before installing, so the credentials your producers and consumers connect with never pass through Helm and never land in the release. The broker is reachable from inside the GVC only; there is no public-access knob.

<Note>
  **This template does not create a GVC.** It deploys into a GVC you already have — every resource lands in the GVC you install into, so `cpln workload exec`, `cpln logs` and uninstalling all work against that GVC, and uninstalling can never delete it.
</Note>

### What Gets Created

| Resource | Name | Purpose | Optional |
| - | - | - | - |
| Workload | `RELEASE_NAME-rabbitmq` | RabbitMQ broker (stateful, 1 replica) on the official `rabbitmq:3-management` image: AMQP on `5672`, management UI on `15672`, Prometheus metrics on `15692` | — |
| Volume Set | `RELEASE_NAME-rabbitmq-vs` | Persistent storage at `/var/lib/rabbitmq` holding the message store, queue definitions, the user database and the Erlang cookie | — |
| Secret | `RELEASE_NAME-rabbitmq-config` | Opaque secret mounted as `/etc/rabbitmq/rabbitmq.conf`; carries only the AMQP listener port | — |
| Identity | `RELEASE_NAME-rabbitmq-identity` | Identity bound to the workload | — |
| Policy | `RELEASE_NAME-rabbitmq-policy` | Grants the identity `reveal` on exactly two secrets: the config secret and the credentials secret you created | — |

The template creates no credential secret of its own, and the Erlang cookie is never a value either: the broker generates it on first boot onto the volume set.

<Warning>
  **Template version 1.2.0 is a breaking change** for anyone on 1.1.1 or earlier: the default-user values, the `firewall` block and `diskCapacity` were removed, and an upgrade that still sets them is refused at render. Read [Upgrading From Earlier Versions](#upgrading-from-earlier-versions) before you touch an existing release.
</Warning>

## Prerequisites

**One secret must exist before you install.** It holds the RabbitMQ default user — the management-UI login **and** the AMQP credentials every producer and consumer puts in its connection string. Secrets are org-level, so no GVC flag is involved.

<Steps>
  <Step title="Create the credentials secret">
    A [dictionary secret](/guides/create-secret/dictionary) holding exactly two keys, `username` and `password`:

    ```bash theme={null}
    cpln secret create-dictionary --name SECRET_NAME \
      --entry username=rabbitmq \
      --entry password='YOUR-STRONG-PASSWORD'
    ```

    Set `credentialsSecretName` to this name. Nothing else is required for a default install.
  </Step>

  <Step title="Read the credentials back when you need them">
    The `-o yaml` is required — a bare `cpln secret reveal` prints only a summary table:

    ```bash theme={null}
    cpln secret reveal SECRET_NAME -o yaml
    ```
  </Step>
</Steps>

<Warning>
  **Create the secret before installing.** The template refuses to render when `credentialsSecretName` is blank, but a name pointing at a secret that does not exist installs "successfully" and then wedges silently: every resource is reported created, the workload never becomes ready, and **`cpln logs` returns zero lines** because no container ever starts. The only place the missing secret is named is `status.versions[].message`:

  ```bash theme={null}
  cpln workload get-deployments RELEASE_NAME-rabbitmq --gvc GVC_NAME -o yaml
  ```

  It is `get-deployments` — plain `cpln workload get` has no `versions` key. Once the secret exists the workload recovers on its own after several minutes, or immediately if you force a redeployment:

  ```bash theme={null}
  cpln workload force-redeployment RELEASE_NAME-rabbitmq --gvc GVC_NAME
  ```
</Warning>

## Installation

Install with the credentials secret name as the only required value:

```bash theme={null}
cpln helm install RELEASE_NAME oci://ghcr.io/controlplane-com/templates/rabbitmq \
  --version 1.2.0 --gvc GVC_NAME \
  --set credentialsSecretName=SECRET_NAME
```

To install using another method, follow the instructions for it:

<CardGroup cols={2}>
  <Card title="UI" href="/template-catalog/install-manage/ui" icon="laptop">
    Browse, install, and manage templates visually
  </Card>

  <Card title="CLI" href="/template-catalog/install-manage/cli" icon="terminal">
    Manage templates from your terminal
  </Card>

  <Card title="Terraform" href="/template-catalog/install-manage/terraform" icon={<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><g fill-rule="evenodd"><path d="M77.941 44.5v36.836L46.324 62.918V26.082zm0 0" fill="#5c4ee5"/><path d="M81.41 81.336l31.633-18.418V26.082L81.41 44.5zm0 0" fill="#4040b2"/><path d="M11.242 42.36L42.86 60.776V23.941L11.242 5.523zm0 0M77.941 85.375L46.324 66.957v36.82l31.617 18.418zm0 0" fill="#5c4ee5"/></g></svg>}>
    Declare templates in your Terraform configurations
  </Card>

  <Card
    title="Pulumi"
    href="/template-catalog/install-manage/pulumi"
    icon={<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" id="Pulumi-Icon--Streamline-Svg-Logos" height="24" width="24">
    <desc>
        Pulumi Icon Streamline Icon: https://streamlinehq.com
    </desc>
    <path fill="#f26e7e" d="M4.683025 13.3318c0.869125 -0.5018 0.870575 -2.1264 0.003225 -3.62865s-2.27504 -2.313275 -3.1441725 -1.811475C0.672945 8.3935 0.6715 10.0181 1.53885 11.52035c0.86735 1.502275 2.27505 2.313275 3.144175 1.81145Zm0.0052 3.2167c0.86735 1.502275 0.865925 3.126875 -0.003225 3.628675 -0.86915 0.5018 -2.2768275 -0.309225 -3.144175 -1.81145 -0.8673525 -1.50225 -0.8659075 -3.126875 0.003225 -3.628675 0.8691325 -0.5018 2.276825 0.309225 3.144175 1.81145Zm5.922875 3.4243c0.86735 1.50225 0.8659 3.126775 -0.003225 3.62875 -0.869125 0.501775 -2.27685 -0.309325 -3.1442 -1.81155 -0.867325 -1.50225 -0.865875 -3.12685 0.00325 -3.628675 0.869125 -0.5018 2.276825 0.309225 3.144175 1.811475Zm-0.001925 -6.845275c0.86735 1.50225 0.8659 3.12685 -0.003225 3.628675 -0.869125 0.5018 -2.276825 -0.309225 -3.144175 -1.811475 -0.86735 -1.50225 -0.8659 -3.12685 0.003225 -3.62865 0.869125 -0.501825 2.276825 0.3092 3.144175 1.81145Z" stroke-width="0.25"></path>
    <path fill="#8a3391" d="M22.45775 11.524125c0.86725 -1.502225 0.865925 -3.12685 -0.003225 -3.62865 -0.869125 -0.501825 -2.276825 0.3092 -3.144175 1.811475 -0.86735 1.50225 -0.8659 3.126825 0.003225 3.62865 0.869125 0.501825 2.276825 -0.3092 3.144175 -1.811475Zm0.000175 3.2151c0.869075 0.5018 0.870625 2.1264 0.003225 3.62865 -0.86735 1.50225 -2.27505 2.313275 -3.144175 1.81145 -0.869125 -0.5018 -0.870575 -2.126425 -0.003225 -3.62865 0.86735 -1.50225 2.27505 -2.313275 3.144175 -1.81145ZM16.536225 18.157875c0.86915 0.501825 0.8706 2.126425 0.00325 3.628675 -0.86735 1.502125 -2.275075 2.313225 -3.1442 1.81145 -0.869125 -0.50175 -0.870575 -2.126425 -0.003225 -3.62865 0.867375 -1.502275 2.27505 -2.3133 3.144175 -1.811475Zm-0.003325 -6.843775c0.869125 0.5018 0.870575 2.126425 0.003225 3.628675s-2.27505 2.313275 -3.1442 1.811475c-0.869125 -0.501825 -0.870575 -2.126425 -0.003225 -3.628675 0.86735 -1.502275 2.27505 -2.313275 3.1442 -1.811475Z" stroke-width="0.25"></path>
    <path fill="#f7bf2a" d="M15.138225 2.06721c0 1.003615 -1.40625 1.817215 -3.14095 1.817215 -1.7347 0 -3.14095 -0.8136 -3.14095 -1.817215C8.856325 1.06359 10.262575 0.25 11.997275 0.25c1.7347 0 3.14095 0.81359 3.14095 1.81721ZM9.2166 5.482375c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172s1.40625 -1.817225 3.14095 -1.817225c1.7347 0 3.14095 0.8136 3.14095 1.817225Zm8.71005 1.8172c1.7347 0 3.14095 -0.813575 3.14095 -1.8172s-1.40625 -1.817225 -3.14095 -1.817225c-1.7347 0 -3.14095 0.8136 -3.14095 1.817225s1.40625 1.8172 3.14095 1.8172Zm-2.788425 1.605625c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172 0 -1.0036 1.40625 -1.8172 3.14095 -1.8172 1.7347 0 3.14095 0.8136 3.14095 1.8172Z" stroke-width="0.25"></path>
    </svg>}
  >
    Declare templates in your Pulumi programs
  </Card>
</CardGroup>

## Configuration

### Credentials

Names the prerequisite dictionary secret holding the `username` and `password` keys (see [Prerequisites](#prerequisites)):

```yaml theme={null}
credentialsSecretName: my-rabbitmq-credentials
```

<Note>
  The default user is written into the RabbitMQ database on **first boot only**. Changing the secret afterwards does not change a running broker's credentials — see [Rotating the Default User](#rotating-the-default-user).
</Note>

### Image

The tag is part of the value. `3-management` is a floating tag, so a fresh install picks up the current 3.x management-enabled image:

```yaml theme={null}
image:
  repository: rabbitmq:3-management
```

### Resources

CPU and memory limits for the broker, and the inbound request timeout applied to the workload:

```yaml theme={null}
memory: 250Mi
cpu: 200m

timeoutSeconds: 30 # inbound request timeout in seconds
```

### Internal Access

Which workloads may reach the broker. External inbound is always closed; there is no public-access knob:

```yaml theme={null}
internalAccess:
  type: same-gvc # options: none, same-gvc (recommended), same-org
```

| Value | Description |
| - | - |
| `none` | No workload may connect |
| `same-gvc` | Allow access from all workloads in the same GVC (recommended) |
| `same-org` | Allow access from all workloads in the same org |

A change to `internalAccess.type` can take several minutes to take effect. Re-test with a real AMQP client connection — not a bare TCP port check — before concluding the change did not apply.

### RabbitMQ Configuration

The AMQP listener port is rendered into `/etc/rabbitmq/rabbitmq.conf`; it is the only setting that file carries. The credentials are delivered separately, as the `RABBITMQ_DEFAULT_USER` and `RABBITMQ_DEFAULT_PASS` environment variables resolved from your secret:

```yaml theme={null}
rabbitmq_conf:
  listeners_tcp_default: 5672 # AMQP listener port

env:
  RABBITMQ_CONFIG_FILE: /etc/rabbitmq/rabbitmq.conf
```

### Storage

The persistent volume backing `/var/lib/rabbitmq`. Snapshots are kept for 7 days and a final snapshot is taken when the volume set is deleted:

```yaml theme={null}
volumeset:
  volume:
      initialCapacity: 10 # In Gigabytes. For high-throughput-ssd minimum is '1000'
      fileSystemType: ext4 # ext4 / xfs
      performanceClass: general-purpose-ssd # high-throughput-ssd / general-purpose-ssd
```

## Connecting

The broker is reachable from inside the GVC only. The `username` and `password` come from your credentials secret (`cpln secret reveal SECRET_NAME -o yaml`).

| What | Address | Notes |
| - | - | - |
| AMQP | `amqp://USERNAME:PASSWORD@RELEASE_NAME-rabbitmq.GVC_NAME.cpln.local:5672/` | Port follows `rabbitmq_conf.listeners_tcp_default` |
| Management UI and HTTP API | `http://RELEASE_NAME-rabbitmq.GVC_NAME.cpln.local:15672` | Same credentials; the HTTP API lives under `/api/` |
| Prometheus metrics | `http://RELEASE_NAME-rabbitmq.GVC_NAME.cpln.local:15692/metrics` | No credentials |
| Public endpoint | Not exposed | External inbound is always closed |

To reach the management UI from a browser, or to verify the broker is serving, tunnel to it from your machine:

```bash theme={null}
cpln port-forward RELEASE_NAME-rabbitmq 15672:15672 --gvc GVC_NAME
```

Then open `http://localhost:15672` and log in with the secret's `username` and `password`, or check the HTTP API from another terminal:

```bash theme={null}
curl -u USERNAME:PASSWORD http://localhost:15672/api/overview
```

A `200` with a JSON body means the broker is up and your credentials are the ones it was bootstrapped with; any other password is rejected with `401`.

## Operations

### Backing Up

RabbitMQ separates **definitions** (users, vhosts, queues, exchanges, bindings, policies) from **messages**, and the two are backed up differently.

**Definitions** can be exported from a running broker at any time. `rabbitmqctl export_definitions -` writes the JSON to standard output, so pipe it straight to a local file:

```bash theme={null}
cpln workload exec RELEASE_NAME-rabbitmq --gvc GVC_NAME --quiet -- rabbitmqctl export_definitions - > definitions.json
```

The export contains every user's password hash, so store the file as carefully as the credentials secret itself.

**Messages** cannot be exported from a running node — RabbitMQ requires the node to be stopped before its message store is copied, and the template does not offer a scheduled message backup. The volume set keeps 7 days of snapshots and takes a final snapshot when it is deleted; a snapshot of a running broker captures the disk at that moment, but restoring one into a new release has not been verified for this template.

### Restoring a Backup

Definitions are restored by importing the file into a broker. `rabbitmqctl import_definitions -` reads standard input, so pass the file in with `--stdin`:

```bash theme={null}
cpln workload exec RELEASE_NAME-rabbitmq --gvc GVC_NAME --stdin -- rabbitmqctl import_definitions - < definitions.json
```

Importing recreates the topology — users, vhosts, permissions, policies, queues, exchanges and bindings — on the target broker. It does not restore messages, and it does not replace the default user the broker was bootstrapped with. This procedure follows the chart's configuration and RabbitMQ's own definitions documentation; it has not been exercised against a live install of this template, so rehearse it on a throwaway release before relying on it.

### Rotating the Default User

The default user is created on first boot only, so changing the credentials secret does nothing to a running broker. Rotate the password inside the broker:

```bash theme={null}
cpln workload exec RELEASE_NAME-rabbitmq --gvc GVC_NAME -- rabbitmqctl change_password USERNAME 'NEW-STRONG-PASSWORD'
```

Then update the dictionary secret to match, so the value your team reads back with `cpln secret reveal` is the one that works. The broker never re-reads the secret, so updating it alone changes nothing. The alternative is to uninstall and reinstall, which deletes the volume set and every message on it.

### Upgrading From Earlier Versions

Template version 1.1.1 and earlier took the RabbitMQ default user as plain Helm values, with a working default username and password published in the public template repository, and wrote them in plaintext into the mounted `rabbitmq.conf` secret. Version 1.2.0 moves them to the prerequisite secret and cleans up three other values:

| | 1.1.1 and earlier | 1.2.0 |
| - | - | - |
| Default user | `rabbitmq_conf.default_user` and `rabbitmq_conf.default_pass` values | `credentialsSecretName` → a dictionary secret you create |
| How it reaches the broker | Written into the mounted `rabbitmq.conf` | `RABBITMQ_DEFAULT_USER` and `RABBITMQ_DEFAULT_PASS` environment variables, resolved from the secret |
| Internal firewall | `firewall.internal_inboundAllowType` | `internalAccess.type` |
| Volume size | `diskCapacity` — read by nothing, so setting it had no effect | `volumeset.volume.initialCapacity` |
| Request timeout | `timeoutSeconds` — read by nothing; the workload used a fixed 5 seconds | `timeoutSeconds`, now applied as set |

The `firewall` block was replaced for clarity only: external inbound was closed before and remains closed. The security fix in this release is the credential move.

<Warning>
  **Treat a pre-1.2.0 broker's credentials as compromised, not merely outdated.** Upgrading moves them out of Helm values but changes neither the values nor the broker: the default user is written into the RabbitMQ database on **first boot only**, so an existing broker keeps whatever user it was bootstrapped with. After upgrading, rotate it in place as described in [Rotating the Default User](#rotating-the-default-user), or uninstall and reinstall — which deletes the volume set and every message on it.
</Warning>

<Warning>
  **Carrying old values forward stops the upgrade.** These conditions are rejected at render time, so the upgrade fails and the existing release is left untouched and running:

  | Value you set | Result |
  | - | - |
  | `rabbitmq_conf.default_user` | `was REMOVED in rabbitmq 1.2.0 … create a dictionary secret holding the keys username and password, and set credentialsSecretName to its name` |
  | `rabbitmq_conf.default_pass` | the same message |
  | `credentialsSecretName` empty | `credentialsSecretName is required — it names the dictionary secret holding the username and password keys` |
  | any `firewall.*` key | `The firewall block was REPLACED in rabbitmq 1.2.0 by internalAccess. Set internalAccess.type to none, same-gvc or same-org` |
  | `diskCapacity` | `was REMOVED in rabbitmq 1.2.0 — it was never read by any template and setting it had no effect on disk size. Use volumeset.volume.initialCapacity instead` |
  | `internalAccess.type` unset | `internalAccess.type is required — set it to none, same-gvc or same-org` |
  | `internalAccess.type` not one of the three | `internalAccess.type must be one of: none, same-gvc, same-org` |
</Warning>

To upgrade, create the credentials secret first ([Prerequisites](#prerequisites)), then run the upgrade with `credentialsSecretName` set and the removed keys dropped from your values. The volume set — and with it every queue, message and user — is kept across the upgrade.

### Scaling and Availability

This template runs one broker node with one replica; there is no clustering or replicas knob. Any upgrade or reschedule restarts the broker — including the first upgrade after an install, even when no value changed — so every connected client sees a short outage. Give your producers and consumers a reconnect policy. Queues, messages and the user database live on the volume set and survive a restart; uninstalling the release deletes them.

### Troubleshooting

<AccordionGroup>
  <Accordion title="Workload never becomes ready and cpln logs returns nothing">
    **Symptom:** the install reports every resource created, the workload stays not ready, and `cpln logs` prints zero lines.

    **Cause:** the credentials secret named by `credentialsSecretName` does not exist, so the container never starts.

    **Fix:** read the deployment message — it is the only place the missing secret is named:

    ```bash theme={null}
    cpln workload get-deployments RELEASE_NAME-rabbitmq --gvc GVC_NAME -o yaml
    ```

    Look for `The secret <name> no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed.` under `status.versions[].message`. Create the secret with that exact name ([Prerequisites](#prerequisites)); the workload recovers on its own after several minutes, or force a redeployment to skip the wait.
  </Accordion>

  <Accordion title="I changed the secret but the old password still works">
    **Symptom:** the credentials secret was updated (or the release was redeployed with a new secret), yet the broker still accepts the old username and password and rejects the new ones with `401`.

    **Cause:** RabbitMQ writes the default user into its database on first boot only; the user database lives on the volume set and is never overwritten from the secret.

    **Fix:** rotate inside the broker with `rabbitmqctl change_password` ([Rotating the Default User](#rotating-the-default-user)), or uninstall and reinstall to start from an empty volume set.
  </Accordion>

  <Accordion title="Upgrade fails at render with 'was REMOVED in rabbitmq 1.2.0'">
    **Symptom:** `cpln helm upgrade` exits before touching any resource, printing one of the messages in [Upgrading From Earlier Versions](#upgrading-from-earlier-versions).

    **Cause:** your values still carry a key from 1.1.1 or earlier — `rabbitmq_conf.default_user`, `rabbitmq_conf.default_pass`, any `firewall.*` key or `diskCapacity` — or `credentialsSecretName` / `internalAccess.type` is missing.

    **Fix:** remove the old keys, create the credentials secret, set `credentialsSecretName` and `internalAccess.type`, and run the upgrade again. The running release is unaffected until the render succeeds.
  </Accordion>

  <Accordion title="Clients in the GVC cannot connect">
    **Symptom:** a producer or consumer in the same GVC fails to open an AMQP connection, or a workload in another GVC of the same org is refused.

    **Cause:** `internalAccess.type` is `none`, or it is `same-gvc` while the client runs in a different GVC; a recent change to the value may also still be taking effect.

    **Fix:** set `internalAccess.type` to `same-gvc` or `same-org` as needed, wait several minutes, and test with a real AMQP client rather than a bare TCP port check. Confirm the client uses the fully qualified host `RELEASE_NAME-rabbitmq.GVC_NAME.cpln.local` and the port in `rabbitmq_conf.listeners_tcp_default`.
  </Accordion>

  <Accordion title="Management UI login is rejected">
    **Symptom:** `http://localhost:15672` over a port-forward loads, but the login is refused, or the HTTP API returns `401`.

    **Cause:** the username and password are not the ones the broker was bootstrapped with. The management UI uses the same default user as AMQP.

    **Fix:** read the values back with `cpln secret reveal SECRET_NAME -o yaml`. If the secret was changed after the first boot, the broker still holds the original credentials — see the previous entry.
  </Accordion>
</AccordionGroup>

## Important Notes

* Create the credentials secret **before** you install; without it the workload wedges with no log output, and only `status.versions[].message` names the missing secret.
* The default user is written on first boot only — rotate with `rabbitmqctl change_password`, not by editing the secret.
* The broker is GVC-internal only. Use `cpln port-forward` for the management UI; there is no public endpoint.
* Single node, single replica: every upgrade or reschedule is a short outage, so give clients a reconnect policy.
* Definitions can be exported at any time; messages cannot be backed up from a running node, and uninstalling the release deletes the volume set and every message on it.
* On 1.1.1 or earlier, treat the broker's credentials as compromised and rotate them after upgrading to 1.2.0.

## External References

<CardGroup cols={2}>
  <Card title="RabbitMQ Documentation" icon="book" href="https://www.rabbitmq.com/docs">
    Official RabbitMQ documentation
  </Card>

  <Card title="Configuration Reference" icon="sliders" href="https://www.rabbitmq.com/docs/configure">
    How rabbitmq.conf and the environment variables are read
  </Card>

  <Card title="Management Plugin" icon="gauge" href="https://www.rabbitmq.com/docs/management">
    The management UI and HTTP API
  </Card>

  <Card title="Definitions Export and Import" icon="file-export" href="https://www.rabbitmq.com/docs/definitions">
    Backing up and restoring users, vhosts, queues, exchanges and bindings
  </Card>

  <Card title="RabbitMQ Template" icon="github" href="https://github.com/controlplane-com/templates/tree/main/rabbitmq">
    View the source files, default values, and chart definition
  </Card>
</CardGroup>
