RabbitMQ’s virtual hosts (vhosts) are the fundamental building blocks for isolating different applications or tenants within a single RabbitMQ cluster, and they do so by acting as completely separate virtual RabbitMQ servers.
Let’s see this in action. Imagine we have two distinct applications, app1 and app2, that we want to run on the same RabbitMQ instance but keep their queues and exchanges entirely separate.
First, we create the vhosts:
rabbitmqadmin declare vhost name=app1
rabbitmqadmin declare vhost name=app2
Now, if we declare a queue named my_queue in the app1 vhost:
rabbitmqadmin declare queue name=my_queue vhost=app1
And then try to access my_queue in the app2 vhost, it won’t exist:
rabbitmqadmin get queue=my_queue vhost=app2
# This will return an empty list or an error indicating the queue doesn't exist.
This isolation extends to users. We can create a user and grant them permissions only within a specific vhost.
# Create a user for app1
rabbitmqadmin declare user name=user_app1 password=password_app1 tags=user
# Grant permissions to user_app1 on vhost app1
rabbitmqadmin declare permission \
vhost=app1 \
user=user_app1 \
configure='.*' \
write='.*' \
read='.*'
Now, user_app1 can only publish, consume, and configure resources within the app1 vhost. If they attempt to access app2, they will be denied.
The core problem vhosts solve is multi-tenancy. Without them, a single RabbitMQ instance would mean all applications share the same queues, exchanges, and bindings. This leads to message collisions (one app consuming another’s messages), naming conflicts, and a complete lack of security between tenants. Vhosts provide logical separation, allowing each tenant or application to have its own independent messaging environment.
Internally, each vhost has its own set of queues, exchanges, bindings, and permissions. When you connect to RabbitMQ, you specify which vhost you want to operate within. RabbitMQ then routes all your operations – declaring queues, publishing messages, consuming messages – to the resources within that specific vhost. This creates the illusion of separate RabbitMQ servers, even though they are all running on the same underlying Erlang VM and hardware.
Think of vhosts as separate file systems within a single hard drive. You can have /home/user1 and /home/user2 directories, and files within one are completely inaccessible from the other, even though they reside on the same physical disk. Similarly, queues and exchanges declared in /app1 are invisible and inaccessible from /app2.
The exact levers you control are the vhost names themselves, the users, and the permissions granted to those users per vhost. This granular control is what enables secure multi-tenancy. You can define default permissions for all users within a vhost, or grant specific permissions for particular users. The configure, write, and read permission parameters are crucial here, allowing you to restrict what actions users can perform on exchanges and queues within their assigned vhost.
A common pitfall is forgetting to grant the vhost_access permission. Without it, even if a user is created and assigned to a vhost, they won’t be able to perform any operations on that vhost itself, such as declaring queues or exchanges, even if they have configure, write, and read permissions for specific resources.
Once you have multiple vhosts set up and have secured access via users and permissions, the next logical step is to consider how to manage resource quotas within each vhost to prevent one tenant from impacting others through excessive resource consumption.