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

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

Menu
----

Close 

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

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

 1. [Home](https://msaied.com/public)
2. /
3. [Articles](https://msaied.com/public/articles)
4. /
5. Laravel WebSocket Broadcasting with Reverb: Scaling Beyond a Single Worker

 Laravel WebSocket Broadcasting with Reverb: Scaling Beyond a Single Worker
===========================================================================

 Reverb ships with a single-process model by default. Learn how to scale it horizontally with Redis pub/sub, tune connection limits, and keep broadcast delivery reliable under real production load.

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

ShareCopy linkCopied

 ![Laravel WebSocket Broadcasting with Reverb: Scaling Beyond a Single Worker](https://cdn.msaied.com/335/b2461babce9e90ae5fe8dc789cd7046c.png) 

  On this page +1. [The Single-Worker Problem](#the-single-worker-problem)
2. [Enabling Redis Pub/Sub in Reverb](#enabling-redis-pubsub-in-reverb)
3. [Running Multiple Reverb Workers](#running-multiple-reverb-workers)
4. [Nginx WebSocket Proxy](#nginx-websocket-proxy)
5. [Tuning Connection Limits](#tuning-connection-limits)
6. [Keeping Broadcasts Reliable](#keeping-broadcasts-reliable)
7. [Health Checks](#health-checks)
8. [Takeaways](#takeaways)

 The Single-Worker Problem
-------------------------

Laravel Reverb is a first-party WebSocket server written in PHP using ReactPHP. Out of the box it runs as a single process, which is fine for development and low-traffic apps. The moment you deploy multiple application servers — or your connection count climbs past a few thousand — you hit a wall: clients connected to server A never receive events published from server B.

The fix is a shared pub/sub backend. Reverb supports Redis as a message bus so every worker node subscribes to the same channel stream.

Enabling Redis Pub/Sub in Reverb
--------------------------------

In `config/reverb.php`, switch the `scaling` driver:

```php
'servers' => [
    'reverb' => [
        // ...
        'scaling' => [
            'enabled' => true,
            'driver'  => 'redis',
            'connection' => 'default', // your redis connection name
        ],
    ],
],

```

Reverb uses a dedicated Redis Pub/Sub connection (not the cache or queue connection) so it never blocks your job workers. Make sure the `redis` extension or `predis/predis` is available and that your Redis instance allows enough concurrent clients.

Running Multiple Reverb Workers
-------------------------------

Each node starts its own Reverb process. Supervisor is the standard approach:

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

```

Behind a load balancer, every node listens on the same port. The load balancer must support **sticky sessions** (IP hash or cookie-based) for the WebSocket upgrade handshake, but once the connection is established the Redis layer handles cross-node delivery transparently.

### Nginx WebSocket Proxy

```nginx
upstream reverb {
    ip_hash; # sticky sessions for WS upgrade
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
}

server {
    listen 443 ssl;
    server_name ws.example.com;

    location / {
        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;
    }
}

```

Tuning Connection Limits
------------------------

ReactPHP uses a non-blocking event loop, so a single Reverb process can hold thousands of open file descriptors. The OS default `ulimit -n` is often 1024 — far too low.

Set it in Supervisor:

```ini
[program:reverb-worker]
; ...
minfds=65536

```

Or in your systemd unit:

```ini
[Service]
LimitNOFILE=65536

```

Also raise `max_connections` in `config/reverb.php`:

```php
'options' => [
    'tls' => [],
    'max_request_size' => 10_000,
],

```

Reverb itself does not hard-cap connections by default, but you can add application-level guards via the `Reverb\Contracts\ServerFactory` if you need per-channel or per-app limits.

Keeping Broadcasts Reliable
---------------------------

Broadcasting from a queued job is the safest pattern. Never broadcast synchronously inside a request when you expect high throughput:

```php
broadcast(new OrderShipped($order))->via('reverb');
// or inside a queued job:
public function handle(): void
{
    broadcast(new OrderShipped($this->order));
}

```

If the Reverb server is temporarily unreachable, the queued job will retry according to your queue configuration rather than silently dropping the event.

### Health Checks

Reverb exposes a simple HTTP health endpoint when started with `--debug` or via a custom route. Wire it into your load balancer's health check so unhealthy nodes are removed automatically:

```bash
curl -f http://10.0.0.1:8080/apps/{app_id}/health

```

Takeaways
---------

- Enable the `redis` scaling driver in `config/reverb.php` to share state across nodes.
- Use IP-hash sticky sessions at the load balancer only for the WebSocket upgrade; post-handshake routing is handled by Redis.
- Raise `ulimit -n` (via Supervisor `minfds` or systemd `LimitNOFILE`) to at least 65 536 per node.
- Always broadcast from queued jobs so delivery survives transient Reverb restarts.
- Monitor the Redis pub/sub channel count alongside your application metrics — runaway subscriptions are a common memory leak vector.

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

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

  Do I need sticky sessions on my load balancer when running multiple Reverb nodes?Yes, but only for the initial WebSocket upgrade handshake. Once the connection is established, the Redis pub/sub layer ensures events published on any node are delivered to all connected clients regardless of which node they are on.

   Can Reverb replace Pusher entirely in a high-traffic production app?Yes. With Redis scaling enabled, proper ulimit tuning, and broadcasts dispatched through queued jobs, Reverb handles the same workload as a managed Pusher cluster while keeping all traffic within your own infrastructure.

   What happens to in-flight WebSocket connections when I restart a Reverb worker?Clients are disconnected and must reconnect. Laravel Echo retries automatically with exponential back-off. Use Supervisor's stopwaitsecs to allow the process to drain gracefully, and deploy rolling restarts across nodes to minimise the visible impact.

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

[Mohamed Said](https://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://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 articleProfiling Laravel with Blackfire and Xdebug: Finding Real Bottlenecks](https://msaied.com/public/articles/profiling-laravel-with-blackfire-and-xdebug-finding-real-bottlenecks) [Next articleLaravel API Resources: Sparse Fieldsets, Conditional Relationships, and Versioning](https://msaied.com/public/articles/laravel-api-resources-sparse-fieldsets-conditional-relationships-and-versioning)  

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

1. [The Single-Worker Problem](#the-single-worker-problem)
2. [Enabling Redis Pub/Sub in Reverb](#enabling-redis-pubsub-in-reverb)
3. [Running Multiple Reverb Workers](#running-multiple-reverb-workers)
4. [Nginx WebSocket Proxy](#nginx-websocket-proxy)
5. [Tuning Connection Limits](#tuning-connection-limits)
6. [Keeping Broadcasts Reliable](#keeping-broadcasts-reliable)
7. [Health Checks](#health-checks)
8. [Takeaways](#takeaways)

 ###  Have a technical challenge?

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

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

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

 [ ![](https://cdn.msaied.com/745/8744e1be5136b430da52e9fca3ed3964.png)  · 3 min read### Service Container Deep Dive: Contextual Binding, Tagging, and Method Injection

6 Oct 2026 ](https://msaied.com/public/articles/service-container-deep-dive-contextual-binding-tagging-and-method-injection-1) [ ![](https://cdn.msaied.com/743/8998fac3a41451ab3fe1588194e17a43.png) Filament · 3 min read### Securing Filament Plugins with Plumb: Automated Security Scoring for PHP Packages

5 Oct 2026 ](https://msaied.com/public/articles/securing-filament-plugins-with-plumb-automated-security-scoring-for-php-packages) [ ![](https://cdn.msaied.com/742/2d02018669cdeedccb5de2efb898f0ee.png) Filament · 3 min read### Filament v3.3.56 Released: File Hash Names and Livewire Upload Fix

5 Oct 2026 ](https://msaied.com/public/articles/filament-v3356-released-file-hash-names-and-livewire-upload-fix) 

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

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

 [Discuss your project ↗](https://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://msaied.com/public)
- [Articles](https://msaied.com/public/articles)
- [Certificates](https://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://msaied.com/public/sitemap.xml)
