Scaling Laravel Reverb Horizontally in Production | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. Laravel Reverb WebSocket Scaling: Channels, Presence, and Horizontal Deployment

 Laravel Reverb WebSocket Scaling: Channels, Presence, and Horizontal Deployment
================================================================================

 Move beyond a single Reverb node. Learn how to scale Laravel Reverb horizontally with Redis pub/sub, configure presence channels correctly, and avoid the subtle pitfalls that only appear under real production load.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 11 Jul 2026 · Updated 11 Jul 2026 · 4 min read

ShareCopy linkCopied

 ![Laravel Reverb WebSocket Scaling: Channels, Presence, and Horizontal Deployment](https://cdn.msaied.com/410/2698f47a7daff990e9807996fe0f493c.png) 

  On this page +1. [Why a Single Reverb Node Breaks Under Load](#why-a-single-reverb-node-breaks-under-load)
2. [The Redis Pub/Sub Bridge](#the-redis-pubsub-bridge)
3. [Presence Channel State Across Nodes](#presence-channel-state-across-nodes)
4. [Load Balancer Configuration](#load-balancer-configuration)
5. [Supervisor and Process Management](#supervisor-and-process-management)
6. [Health Checks and Observability](#health-checks-and-observability)
7. [Key Takeaways](#key-takeaways)

 Why a Single Reverb Node Breaks Under Load
------------------------------------------

Laravel Reverb is a first-party WebSocket server that integrates tightly with Laravel's broadcasting system. A single node works perfectly in development and handles modest traffic, but the moment you add a second application server — or run Reverb behind a load balancer — you hit a fundamental problem: **WebSocket connections are stateful and sticky to one process**.

Client A connects to node 1. Client B connects to node 2. When your application broadcasts an event, only the node that received the HTTP request knows about it. Without a shared message bus, half your users miss the event.

The Redis Pub/Sub Bridge
------------------------

Reverb ships with a Redis scaling driver that solves this with a publish/subscribe bus. Every Reverb node subscribes to the same Redis channel. When any node receives a broadcast, it publishes to Redis; every other node picks it up and pushes it to its own connected clients.

Enable it in `config/reverb.php`:

```php
'scaling' => [
    'driver' => 'redis',
    'connection' => env('REVERB_SCALING_CONNECTION', 'default'),
],

```

Then make sure your `redis` connection in `config/database.php` points at the same Redis instance (or cluster) that all Reverb nodes share. A dedicated Redis database index keeps Reverb traffic isolated:

```php
'reverb_scaling' => [
    'url' => env('REDIS_URL'),
    'host' => env('REDIS_HOST', '127.0.0.1'),
    'password' => env('REDIS_PASSWORD'),
    'port' => env('REDIS_PORT', '6379'),
    'database' => env('REVERB_REDIS_DB', '1'),
],

```

Reference it: `REVERB_SCALING_CONNECTION=reverb_scaling`.

Presence Channel State Across Nodes
-----------------------------------

Presence channels track *who is online*. In a single-node setup, that state lives in memory. Across nodes, each node only knows about its own connections — so `channel:here` events become inconsistent.

Reverb stores presence membership in Redis when the scaling driver is active. The key pattern is `reverb:presence:{channel}`. You should **never** query this key directly; instead rely on the `here`, `joining`, and `leaving` client events. What you *do* need to ensure is that your Redis instance has enough memory and that you set a sensible TTL policy — presence keys are cleaned up on disconnect, but a crashed node can leave orphaned entries until the key expires.

Force a short key TTL in your Reverb config:

```php
'presence' => [
    'timeout' => 120, // seconds before a stale member is evicted
],

```

Load Balancer Configuration
---------------------------

WebSocket connections require HTTP Upgrade. Most load balancers need explicit configuration:

```nginx
upstream reverb {
    least_conn;
    server reverb1:8080;
    server reverb2:8080;
}

server {
    listen 443 ssl;

    location /app/ {
        proxy_pass http://reverb;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 3600s;
    }
}

```

Note `least_conn` rather than round-robin. WebSocket connections are long-lived, so round-robin will pile connections onto whichever node happened to be first. `least_conn` distributes active connections more evenly.

Supervisor and Process Management
---------------------------------

Each Reverb node should run under Supervisor with restart-on-failure:

```ini
[program:reverb]
command=php /var/www/artisan reverb:start --host=0.0.0.0 --port=8080
autostart=true
autorestart=true
stopwaitsecs=10
stdout_logfile=/var/log/reverb.log

```

Set `stopwaitsecs` high enough for in-flight connections to drain gracefully. Reverb sends a close frame to clients on SIGTERM; clients with reconnect logic will re-connect to another node transparently.

Health Checks and Observability
-------------------------------

Reverb exposes a `/apps/{appId}/channels` REST endpoint (authenticated with your app secret) that returns active channel counts. Wire this into your uptime monitor or Prometheus scraper to alert on node divergence — if two nodes report wildly different channel counts, your Redis pub/sub bridge may have silently failed.

Key Takeaways
-------------

- Enable the Redis scaling driver so all Reverb nodes share a pub/sub bus.
- Use a dedicated Redis database index to isolate Reverb traffic.
- Presence channel state is stored in Redis automatically; set a `presence.timeout` to evict stale members from crashed nodes.
- Configure your load balancer with `Upgrade` headers and `least_conn` balancing.
- Run each node under Supervisor with graceful shutdown via `stopwaitsecs`.
- Monitor channel counts per node via the Reverb REST API to catch pub/sub failures early.

- [laravel](https://www.msaied.com/public/articles?search=laravel)
- [reverb](https://www.msaied.com/public/articles?search=reverb)
- [websockets](https://www.msaied.com/public/articles?search=websockets)
- [redis](https://www.msaied.com/public/articles?search=redis)
- [broadcasting](https://www.msaied.com/public/articles?search=broadcasting)

 Frequently asked questions 
---------------------------

  Do I need a Redis cluster, or will a single Redis instance work for Reverb scaling?A single Redis instance is sufficient for most deployments. Redis pub/sub is extremely fast and the message volume from WebSocket broadcasts is typically low. Only move to a Redis cluster if your Redis instance itself becomes a bottleneck, which is rare before thousands of concurrent connections.

   What happens to connected clients when a Reverb node restarts?Reverb sends a WebSocket close frame on SIGTERM. Laravel Echo and Pusher-compatible clients have built-in reconnect logic, so clients will automatically reconnect to another available node within a few seconds. The presence channel will emit a `leaving` event for the disconnected client and a `joining` event when they reconnect.

   Can I run Reverb behind AWS ALB or Cloudflare?Yes. AWS ALB supports WebSocket upgrades natively — enable sticky sessions only if you cannot use the Redis scaling driver. Cloudflare proxies WebSockets on paid plans; ensure your Cloudflare timeout settings exceed your expected connection duration, as the default 100-second idle timeout will drop long-lived connections.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

[Mohamed Said](https://www.msaied.com/public#person)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleLaravel Enum Casts, Backed Enums, and Value Semantics in PHP 8.3](https://www.msaied.com/public/articles/laravel-enum-casts-backed-enums-and-value-semantics-in-php-83) [Next articlePractical RAG in Laravel: pgvector, Embeddings, and Retrieval Pipelines](https://www.msaied.com/public/articles/practical-rag-in-laravel-pgvector-embeddings-and-retrieval-pipelines-1)  

   On this page
-------------

1. [Why a Single Reverb Node Breaks Under Load](#why-a-single-reverb-node-breaks-under-load)
2. [The Redis Pub/Sub Bridge](#the-redis-pubsub-bridge)
3. [Presence Channel State Across Nodes](#presence-channel-state-across-nodes)
4. [Load Balancer Configuration](#load-balancer-configuration)
5. [Supervisor and Process Management](#supervisor-and-process-management)
6. [Health Checks and Observability](#health-checks-and-observability)
7. [Key Takeaways](#key-takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
