Why RabbitMQ?
RabbitMQ is a fast, battle‑tested message broker that implements the AMQP protocol. It sits between producers (your apps that publish messages) and consumers (your apps that process messages), buffering bursts of work, smoothing traffic, and adding reliability with acknowledgements and durable queues.
How it works (in 90 seconds)
- Exchanges receive messages from producers and route them (by rules) to queues.
- Queues store messages until consumers are ready.
- Bindings connect exchanges to queues (e.g., by routing key).
- Consumers ack messages when processed; unacked messages can be re‑delivered.
- With durable queues and persistent messages, RabbitMQ survives broker restarts without data loss.
What RabbitMQ is great for
- Background jobs and task queues (e.g., image processing, email sends)
- Event‑driven microservices (decoupled services via pub/sub)
- Rate‑limiting and traffic smoothing for bursty workloads
- RPC‑style async workflows (request/response using reply queues)
If you need strict ordering across a partitioned, massive event stream, a log broker like Kafka may fit better—but for classic work queues, RPC, and general purpose messaging, RabbitMQ shines.
Prerequisites
Version & tag guidance (October 10, 2025): Use the latest RabbitMQ 4.1.x image with
-managementso you get the web UI (port 15672) and HTTP API out of the box. In Plesk’s Docker UI, if you only seerabbitmq:4.xwithout “management”, open the tag list and selectrabbitmq:4.1-managementorrabbitmq:4.1-management-alpine. We avoid 4.2 for now because it is in beta/RC status at the time of writing and changes the default metadata store (Khepri). When 4.2 is GA, it will be a fine choice; until then, stick to 4.1 for production stability.
- Plesk Obsidian on Linux with root SSH access
- Docker extension enabled in Plesk (Extensions → Docker). If Docker isn’t installed, Plesk will prompt to install it.
- Firewall control (Plesk Firewall or OS-level) to allow ports you plan to expose
Security tip: On public hosts, avoid exposing RabbitMQ ports directly to the Internet. Prefer a VPN, security groups, or reverse‑proxy with TLS and IP allow‑listing.
Option A — Launch via Plesk GUI (quick start)
- In Plesk: Extensions → Docker.
- Click + Add Container → search for
rabbitmqand open the tag list. - Choose:
rabbitmq:4.1-management(or4.1-management-alpinefor a smaller base image). The-managementtag enables the web UI and HTTP API. - Ports:
- Automatic port mapping (default): Plesk maps each exposed container port to a random high host port (for example, 32768). This is fine for quick tests but awkward for stable URLs and proxy rules.
- Manual mapping: Uncheck Automatic port mapping to choose fixed host ports for each exposed container port. By default, manual mappings bind to localhost (127.0.0.1) so they are not reachable from the Internet unless you deselect “Make the port inaccessible from the Internet.”
- Proxy rules note: If you plan to use Docker Proxy Rules (to serve the UI at a domain), you must disable Automatic port mapping and set a fixed host port first.
- For RabbitMQ, map container
5672(AMQP) and15672(Management UI).
- Volumes:
- Create named volume
rabbitmq_data→ mount to/var/lib/rabbitmq. - (Optional) Create
rabbitmq_conf→ mount to/etc/rabbitmqif you need a customrabbitmq.conf.
- Create named volume
- Environment: set
RABBITMQ_DEFAULT_USERandRABBITMQ_DEFAULT_PASSfor an initial admin user. - Automatic start: enable Automatic start after system reboot so the container comes up on host reboots.
- Click Run. Open
https://your-host:15672→ login with the credentials you set.
Enable management & metrics plugins (if the UI is missing)
If you accidentally pulled a non-*-management image (or the plugin was disabled), the web UI (15672/15671) won’t be available until you enable it inside the container.
|
1 2 3 4 5 6 7 8 9 10 |
# Enable Management UI docker exec -it <container_name> rabbitmq-plugins enable rabbitmq_management # (Optional) Enable Prometheus metrics on 15692 (HTTP) docker exec -it <container_name> rabbitmq-plugins enable rabbitmq_prometheus # Verify docker exec -it <container_name> rabbitmq-plugins list -e | egrep 'management|prometheus' docker exec -it <container_name> rabbitmq-diagnostics listeners |
You should see http on 15672 (or https on 15671 if you’ve configured TLS for management) and Prometheus on 15692. If not, check your mounted rabbitmq.conf for overrides.
Option B — docker-compose (recommended for repeatability)
Create a working directory on your Plesk server (as root or a deploy user):
|
1 2 |
mkdir -p /opt/rabbitmq && cd /opt/rabbitmq |
Create docker-compose.yml:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
services: rabbitmq: image: rabbitmq:4.1-management container_name: rabbitmq restart: unless-stopped ports: - "5672:5672" # AMQP - "15672:15672" # Management UI environment: RABBITMQ_DEFAULT_USER: rp_admin RABBITMQ_DEFAULT_PASS: change_me_now volumes: - rabbitmq_data:/var/lib/rabbitmq - ./conf:/etc/rabbitmq # mount custom config (optional) healthcheck: test: ["CMD", "rabbitmq-diagnostics", "ping"] interval: 30s timeout: 10s retries: 5 start_period: 30s volumes: rabbitmq_data: |
Bring it up:
|
1 2 |
docker compose up -d |
Check logs & health:
|
1 2 |
docker logs -f rabbitmq |
Open the UI at http(s)://your-hostname:15672/.
Hardening (don’t skip) (don’t skip)
Why choose *-management: The management image ships with the web UI (15672) and HTTP API enabled by default. This makes initial setup, monitoring, and user/vhost/permission management much easier on a Plesk host. You can still lock it down (bind to localhost, reverse‑proxy via Plesk, add TLS, and restrict by IP), but starting with the UI saves time and reduces mistakes.
Essential steps
- Create an admin user & remove/disable
guest:
Theguestuser is restricted to localhost in modern images, but remove it to be safe.
1234567docker exec -it rabbitmq bash -lc 'rabbitmqctl add_user admin "SuperSecret!"rabbitmqctl set_user_tags admin administratorrabbitmqctl set_permissions -p / admin ".*" ".*" ".*"rabbitmqctl delete_user guest || true' - Limit exposure: bind Management UI to localhost and reverse‑proxy via Plesk (see below), or restrict by firewall.
- Use TLS for AMQP and the Management UI (see TLS section).
- Set resource & connection limits: use policies (e.g., max length) and per‑vhost permissions.
- Backups: snapshot the volume and export definitions regularly.
TLS with Plesk Let’s Encrypt
(Works the same for RabbitMQ 4.1 and later.)
Use Plesk’s Let’s Encrypt certs for RabbitMQ. We’ll terminate TLS inside RabbitMQ for AMQP and (optionally) for the UI.
- Get the cert paths for your domain (after issuing a certificate in Plesk → Domains → yourdomain → SSL/TLS Certificates):
- Fullchain:
/etc/letsencrypt/live/yourdomain/fullchain.pem - Private key:
/etc/letsencrypt/live/yourdomain/privkey.pem
- Fullchain:
- Create config directory & files:
123456mkdir -p /opt/rabbitmq/conftouch /opt/rabbitmq/conf/rabbitmq.confmkdir -p /opt/rabbitmq/conf/certsln -sf /etc/letsencrypt/live/yourdomain/fullchain.pem /opt/rabbitmq/conf/certs/fullchain.pemln -sf /etc/letsencrypt/live/yourdomain/privkey.pem /opt/rabbitmq/conf/certs/privkey.pem rabbitmq.confminimal TLS config:
1234567891011listeners.tcp = nonelisteners.ssl.default = 5671ssl_options.cacertfile = /etc/rabbitmq/certs/fullchain.pemssl_options.certfile = /etc/rabbitmq/certs/fullchain.pemssl_options.keyfile = /etc/rabbitmq/certs/privkey.pemmanagement.listener.port = 15671management.listener.ssl = truemanagement.ssl.cacertfile = /etc/rabbitmq/certs/fullchain.pemmanagement.ssl.certfile = /etc/rabbitmq/certs/fullchain.pemmanagement.ssl.keyfile = /etc/rabbitmq/certs/privkey.pem- Adjust compose ports to expose 5671 and 15671 instead of 5672/15672.
- Restart:
12docker compose up -d --force-recreate
Renewals: Plesk auto‑renews Let’s Encrypt. Because we symlinked into the container’s mounted
conf/certs, RabbitMQ can pick up renewed certs after a container restart (or SIGHUP). Add a monthly restart via cron, or integrate with your existing LE renewal hooks.
Reverse‑proxy the UI through Plesk (nice URLs)
You can hide the container port and serve the Management UI at https://mq.yourdomain/ through Plesk’s nginx.
- In Plesk → Domains → mq.yourdomain → Apache & nginx Settings → Additional nginx directives:
12345678910location / {proxy_pass http://127.0.0.1:15672; # or 15671 if TLS upstreamproxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_set_header Host $host;proxy_set_header X-Forwarded-Proto $scheme;proxy_read_timeout 300s;} - Issue a Let’s Encrypt cert for the subdomain in Plesk.
This keeps 15672 closed to the world and gives you clean, HTTPS‑only access.
Exporting definitions (users, vhosts, queues)
Keep your RabbitMQ topology in source control for reproducible environments.
Export:
|
1 2 3 |
docker exec rabbitmq rabbitmqctl export_definitions /tmp/defs.json docker cp rabbitmq:/tmp/defs.json ./defs.json |
Import (on a new server):
|
1 2 3 |
docker cp ./defs.json rabbitmq:/tmp/defs.json docker exec rabbitmq rabbitmqctl import_definitions /tmp/defs.json |
You can also bind‑mount a definitions.json and set RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS to load at boot, but manual export/import is often simpler for small setups.
Backups of Docker volumes
Create a compressed snapshot of the rabbitmq_data volume:
|
1 2 3 4 5 6 7 |
BACKUP=/opt/backup mkdir -p "$BACKUP" docker run --rm \ -v rabbitmq_data:/data:ro \ -v $BACKUP:/backup \ alpine sh -c 'tar -C / -czf /backup/rabbitmq_data_$(date +%F).tgz data/var/lib/rabbitmq' |
Restore by creating a new empty volume and extracting into it, or stop the container and restore in place.
For small installations, this is usually sufficient. For busy brokers, schedule backups during low traffic and ensure consumers can reprocess messages after restore.
Connecting apps (PHP, Python, Node.js)
- PHP: use
php-amqplib/php-amqplib. DSN likeamqps://admin:password@mq.yourdomain/%2f?verify=peer. - Python:
pikalibrary. Example connection URL:amqps://admin:password@mq.yourdomain:5671/%2F. - Node.js:
amqplib. URL same pattern as above. Remember to enable TLS options if you terminate TLS at RabbitMQ.
Use separate vhosts per application, least‑privilege users, and separate queues for work types. Declare queues/exchanges on startup so apps self‑heal.
Smoke‑testing application connectivity (PHP example)
A quick end‑to‑end test you can run from the Plesk host or any PHP environment.
0) One‑time setup
|
1 2 3 4 |
cd /var/www/vhosts/<your-domain>/rabbitmq # or any working dir php -v # ensure PHP CLI is present composer require php-amqplib/php-amqplib:^3.5 |
1) Plain AMQP (port 5672)
Create rabbitmq_test.php with a publish→get round‑trip using php‑amqplib. It declares a durable queue, publishes a persistent message, reads one back, then deletes the queue.
2) AMQPS TLS (port 5671)
Create rabbitmq_test_tls.php that connects via AMQPSSLConnection with CA verification (point to your system CA bundle, e.g., /etc/ssl/certs/ca-certificates.crt).
For self‑signed tests only, you can disable verification temporarily, but keep verification on for production.
3) Run the tests
|
1 2 3 |
php rabbitmq_test.php php rabbitmq_test_tls.php |
You should see a ✅ message confirming publish+get success. Leave the queue undeleted if you want to inspect it in the UI.
Fast pre‑checks
|
1 2 3 4 5 6 7 |
# AMQP/AMQPS reachability (pick your port) nc -vz <broker-hostname> 5672 nc -vz <broker-hostname> 5671 # Broker aliveness via Management API (vhost `/`) curl -su admin:password http://127.0.0.1:15672/api/aliveness-test/%2F |
Expect {"status":"ok"} from the aliveness test. If not, check user/vhost/permissions.
Running multiple RabbitMQ containers on one Plesk host
You can run several independent RabbitMQ instances on the same server. The keys are distinct host port mappings, separate data volumes, and (optionally) unique node names. Avoid publishing Erlang clustering ports unless you truly need cross-host clustering.
Which ports do you actually need to publish?
| Purpose | Container port | Publish on host? | Notes |
|---|---|---|---|
| AMQP (plain) | 5672 | ✅ | Increment host port per instance (e.g., 5672, 5673, 5674…). |
| AMQPS (TLS) | 5671 | ✅ (if using TLS) | Use unique host ports (e.g., 5671, 5675…). Can proxy via nginx per hostname. |
| Management UI (HTTP) | 15672 | ✅ | Or proxy only; bind to 127.0.0.1 for security. |
| Management UI (HTTPS) | 15671 | ✅ (if using HTTPS UI) | Unique host ports; or proxy to 15671 with proxy_ssl. |
| Prometheus metrics (HTTP) | 15692 | ✅ (optional) | Unique host ports (e.g., 15692, 15693…). Bind to 127.0.0.1 and scrape locally or via proxy. |
| Prometheus metrics (HTTPS) | 15691 | ✅ (optional) | Same as above, if you enabled HTTPS metrics. |
| epmd (Erlang) | 4369 | ❌ (for single-host, non-clustered) | Do not publish unless clustering across hosts. Publishing causes port conflicts. |
| Erlang distribution | 25672 | ❌ (for single-host, non-clustered) | Do not publish unless clustering across hosts. |
TL;DR: Publish only 5672/5671, 15672/15671, and optionally 15692/15691. Do not publish 4369 or 25672 for independent instances on one host.
Strategy A — Fixed ports per instance
Use manual port mapping in Plesk (disable Automatic port mapping) and assign different host ports for each container while keeping the container ports the same:
- Instance A → host
5672:5672(AMQP),15672:15672(UI),15692:15692(metrics, optional) - Instance B → host
5673:5672(AMQP),15673:15672(UI),15693:15692(metrics, optional)
Keep each instance’s data in its own named volume (e.g., rabbitmq_a_data, rabbitmq_b_data). Optionally set a unique node name:
|
1 2 |
RABBITMQ_NODENAME=rabbit@rabbitmq-a |
Strategy B — Reverse proxy by hostname (cleaner URLs)
Bind each container’s ports to localhost with unique host ports, then publish them via Plesk’s nginx Proxy Rules or Additional nginx directives using different hostnames:
- Container A → 127.0.0.1:15672 →
https://mq-a.example.com/ - Container B → 127.0.0.1:15673 →
https://mq-b.example.com/
This avoids exposing ports publicly and keeps the firewall surface small.
Plesk GUI steps to avoid conflicts
- Docker → Container → Ports: Disable Automatic port mapping.
- Add mappings only for the ports you need (see table). For each additional instance, increment the host port while keeping the container port unchanged.
- For security, set each mapping to “Make the port inaccessible from the Internet” so it binds to 127.0.0.1, then front it with nginx per hostname.
- Do not publish 4369 or 25672 unless you’re clustering across hosts. If Plesk insists on showing them, set them to not accessible from the Internet and remove the host port if possible.
Compose example with two instances (no epmd/distribution published)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
services: rabbitmq_a: image: rabbitmq:4.1-management container_name: rabbitmq_a restart: unless-stopped ports: - "5672:5672" # AMQP A - "15672:15672" # UI A - "15692:15692" # metrics A (optional) environment: RABBITMQ_NODENAME: rabbit@rabbitmq-a volumes: - rabbitmq_a_data:/var/lib/rabbitmq rabbitmq_b: image: rabbitmq:4.1-management container_name: rabbitmq_b restart: unless-stopped ports: - "5673:5672" # AMQP B (different host port) - "15673:15672" # UI B (different host port) - "15693:15692" # metrics B (optional) environment: RABBITMQ_NODENAME: rabbit@rabbitmq-b volumes: - rabbitmq_b_data:/var/lib/rabbitmq volumes: rabbitmq_a_data: rabbitmq_b_data: |
Notes & gotchas
- Unique volumes: never share
/var/lib/rabbitmqbetween instances. - Erlang cookie: for independent instances, use different
RABBITMQ_ERLANG_COOKIEvalues; for clustering, the cookie must match. - Clustering on one host (advanced): if you cluster containers, you’ll also need the Erlang distribution ports (
4369,25672) open between nodes and consistent DNS/hostnames. - TLS: if using TLS in multiple instances, map distinct host ports (e.g.,
5671and5675) or terminate TLS in nginx per‑hostname.
Post‑upgrade warning: enable stable feature flags
After upgrading to 4.x you may see in the UI: “All stable feature flags must be enabled after completing an upgrade.” This is expected. Enable all stable feature flags once your node (or cluster) is healthy on the new version.
Single‑node (Docker on Plesk) — safe sequence
|
1 2 3 4 5 6 7 8 9 |
# Inspect current flags docker exec -it <container_name> rabbitmqctl list_feature_flags # Enable all stable flags introduced by your new version docker exec -it <container_name> rabbitmqctl enable_feature_flag all # Verify docker exec -it <container_name> rabbitmqctl list_feature_flags |
From the UI: Admin → Feature flags → enable all stable flags.
Heads‑up: Feature flags are part of cluster state. Once you enable new stable flags, older versions of RabbitMQ cannot join the cluster and rolling back becomes impractical. Only enable them after all nodes are upgraded and healthy.
Troubleshooting
- UI missing or 502/connection reset: ensure the management plugin is enabled:
123docker exec -it <container_name> rabbitmq-plugins enable rabbitmq_managementdocker exec -it <container_name> rabbitmq-diagnostics listeners
You should see 15672 (HTTP) or 15671 (HTTPS) in the listeners. - UI won’t load: check container logs, firewall, reverse‑proxy config, and that you’re using the correct port (15672 vs 15671 with TLS).
- Auth errors: confirm the user exists and has permissions on the vhost; try resetting the password.
- Can’t connect from app: verify DNS resolves to the Plesk host, port open, and TLS settings match the broker (AMQP vs AMQPS).
- Disk free alarm: RabbitMQ stops accepting publishes when disk alarms trigger. Increase disk, or tune
vm_memory_high_watermark/disk_free_limitinrabbitmq.conf.
Cleanup & upgrades
- Upgrade version:
123docker pull rabbitmq:3.13-managementdocker compose up -d
Data persists in the named volume. - Remove everything:
12docker compose down -v # WARNING: deletes volumes
Appendix — PHP test scripts for RabbitMQ
rabbitmq_test.php (AMQP over 5672)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<?php require __DIR__ . '/vendor/autoload.php'; use PhpAmqpLib\Connection\AMQPStreamConnection; use PhpAmqpLib\Message\AMQPMessage; $host = '127.0.0.1'; // or your hostname $port = 5672; // AMQP (non-TLS) $user = 'admin'; $pass = 'change_me_now'; $vhost = '/'; $queue = 'rp_test_queue_' . substr(bin2hex(random_bytes(3)), 0, 6); try { $conn = new AMQPStreamConnection($host, $port, $user, $pass, $vhost); $ch = $conn->channel(); // durable queue [$qName] = $ch->queue_declare($queue, false, true, false, false); $body = 'hello from PHP @ ' . date('c'); $msg = new AMQPMessage($body, ['delivery_mode' => 2]); $ch->basic_publish($msg, '', $qName); // read one back (auto-ack) $got = $ch->basic_get($qName, true); echo "Queue: {$qName} "; if ($got) { echo "✅ Published and received: {$got->body} "; } else { echo "⚠️ Published but nothing fetched (check the UI). "; } // cleanup (optional) $ch->queue_delete($qName); $ch->close(); $conn->close(); } catch (Throwable $e) { fwrite(STDERR, "❌ Test failed: " . $e->getMessage() . " "); exit(1); } |
rabbitmq_test_tls.php (AMQPS over 5671)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<?php require __DIR__ . '/vendor/autoload.php'; use PhpAmqpLib\Connection\AMQPSSLConnection; use PhpAmqpLib\Message\AMQPMessage; $host = 'rabbitmq.<your-domain>'; // your public host $port = 5671; // AMQPS (TLS) $user = 'admin'; $pass = 'change_me_now'; $vhost = '/'; $queue = 'rp_test_tls_' . substr(bin2hex(random_bytes(3)), 0, 6); $sslOptions = [ 'verify_peer' => true, 'verify_peer_name' => true, 'allow_self_signed'=> false, // Debian/Ubuntu CA bundle path: 'cafile' => '/etc/ssl/certs/ca-certificates.crt', ]; try { $conn = new AMQPSSLConnection($host, $port, $user, $pass, $vhost, $sslOptions); $ch = $conn->channel(); $ch->queue_declare($queue, false, true, false, false); $msg = new AMQPMessage('hello over TLS @ ' . date('c'), ['delivery_mode' => 2]); $ch->basic_publish($msg, '', $queue); $got = $ch->basic_get($queue, true); echo $got ? "✅ TLS publish+get OK: {$got->body} " : "⚠️ TLS publish OK; nothing fetched. "; $ch->queue_delete($queue); $ch->close(); $conn->close(); } catch (Throwable $e) { fwrite(STDERR, "❌ TLS test failed: " . $e->getMessage() . " "); exit(1); } |
Run with:
|
1 2 3 |
php rabbitmq_test.php php rabbitmq_test_tls.php |
Summary
Running RabbitMQ on a Plesk server is straightforward with Docker. Start fast with the Plesk GUI, then move to docker-compose for repeatable, versioned deployments. Choose a 4.1.x *-management tag for a stable, production‑ready setup with the UI enabled; when RabbitMQ 4.2 becomes GA, you can evaluate upgrading (it introduces Khepri as the default metadata store). Add TLS (via Plesk’s Let’s Encrypt), reverse‑proxy the UI, export definitions, and back up the data volume. With those pieces in place, you’ll have a reliable, secure message broker ready for your apps.




