Laravel Reverb: Production WebSockets &amp; Scaling | 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 in Production: Scaling WebSockets, Auth Channels, and Presence at Load

 Laravel Reverb in Production: Scaling WebSockets, Auth Channels, and Presence at Load
======================================================================================

 Reverb ships as Laravel's first-party WebSocket server. This guide covers production deployment, horizontal scaling with Redis, private/presence channel auth, and the subtle gotchas that only appear under real traffic.

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

ShareCopy linkCopied

 ![Laravel Reverb in Production: Scaling WebSockets, Auth Channels, and Presence at Load](https://cdn.msaied.com/684/1c8fcd52449a6596e09ec043b245955f.png) 

  On this page +1. [Why Reverb Changes the WebSocket Story for Laravel](#why-reverb-changes-the-websocket-story-for-laravel)
2. [Deployment Architecture](#deployment-architecture)
3. [Horizontal Scaling with Redis](#horizontal-scaling-with-redis)
4. [Private and Presence Channel Auth](#private-and-presence-channel-auth)
5. [Connection Limits and Tuning](#connection-limits-and-tuning)
6. [Key Takeaways](#key-takeaways)

 Why Reverb Changes the WebSocket Story for Laravel
--------------------------------------------------

Before Reverb, running WebSockets in Laravel meant operating a separate Node.js process (Pusher-compatible servers like Soketi or Laravel Echo Server) alongside your PHP app. Reverb collapses that into a single PHP binary, shares your existing service container, and integrates natively with Laravel's broadcasting system. That simplicity is real — but production deployments surface a set of concerns that the getting-started docs gloss over.

---

Deployment Architecture
-----------------------

Reverb runs as a long-lived Ratchet/ReactPHP process. It is **not** a traditional PHP-FPM request; it is a persistent server. That changes how you deploy it.

```bash
# Start Reverb (production)
php artisan reverb:start --host=0.0.0.0 --port=8080 --env=production

```

Manage it with Supervisor so it restarts on failure:

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

```

Nginx proxies WebSocket upgrades to Reverb while your normal FPM traffic continues on port 80/443:

```nginx
location /app {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
    proxy_read_timeout 3600;
}

```

---

Horizontal Scaling with Redis
-----------------------------

A single Reverb process is bound to one machine. When you scale to multiple app servers, a client connected to server A won't receive events broadcast from server B. The fix is the Redis scaling driver, which uses Pub/Sub to fan out events across all Reverb nodes.

```php
// config/reverb.php
'scaling' => [
    'driver' => 'redis',
    'connection' => 'default', // your Redis connection from database.php
],

```

Each Reverb node subscribes to the same Redis channel. When your application fires a broadcast event, any node can pick it up and push it to the connected clients it owns. This requires **sticky sessions** at your load balancer (or a session-affinity cookie) so that the WebSocket handshake and subsequent frames always hit the same node.

> **Gotcha:** If you skip sticky sessions, the HTTP-based channel auth endpoint (`/broadcasting/auth`) may be handled by a different server than the one holding the WebSocket connection. The auth will succeed, but Reverb on the other node won't have the subscription registered. Always pair Redis scaling with L4/L7 sticky routing.

---

Private and Presence Channel Auth
---------------------------------

Reverb reuses Laravel's existing `BroadcastServiceProvider` and channel definitions:

```php
// routes/channels.php
Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
    return $user->can('view', Order::findOrFail($orderId));
});

Broadcast::channel('presence.team.{teamId}', function (User $user, int $teamId) {
    if ($user->belongsToTeam($teamId)) {
        return ['id' => $user->id, 'name' => $user->name];
    }
});

```

Presence channels return an array on success; that payload becomes the member data visible to all subscribers. Returning `false` or `null` denies access.

On the frontend with Echo:

```javascript
window.Echo.join(`presence.team.${teamId}`)
    .here(members => console.log('Online:', members))
    .joining(member => console.log('Joined:', member.name))
    .leaving(member => console.log('Left:', member.name));

```

---

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

Reverb exposes connection limits per application in `config/reverb.php`. Under load, the bottleneck is usually open file descriptors, not CPU. Raise the OS limit:

```bash
# /etc/security/limits.conf
www-data soft nofile 65535
www-data hard nofile 65535

```

Also tune the `max_connections` and `max_request_size` settings:

```php
'apps' => [[
    'id' => env('REVERB_APP_ID'),
    'key' => env('REVERB_APP_KEY'),
    'secret' => env('REVERB_APP_SECRET'),
    'options' => [
        'host' => env('REVERB_HOST', '0.0.0.0'),
        'port' => env('REVERB_PORT', 8080),
        'max_message_size' => 10_000, // bytes
    ],
]],

```

---

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

- Reverb is a persistent PHP process — manage it with Supervisor, not FPM.
- Use the Redis scaling driver for multi-node deployments; pair it with sticky sessions at the load balancer.
- Channel auth runs through your normal Laravel HTTP stack — policies and gates work as expected.
- Presence channel member data is the array returned from the channel callback, not a separate API call.
- Raise OS file descriptor limits before you hit connection ceilings in production.
- `max_message_size` is your first line of defense against oversized payloads crashing the event loop.

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

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

  Can Reverb replace Pusher entirely, including the client-side SDK?Yes. Reverb implements the Pusher protocol, so Laravel Echo works unchanged. You only update the broadcaster config to point at your Reverb host instead of Pusher's servers. No client-side code changes are required.

   Does Reverb support SSL termination directly?The recommended approach is to terminate TLS at Nginx or a load balancer and proxy plain WebSocket traffic to Reverb on a local port. Reverb can handle TLS natively via its `tls` options, but offloading to a reverse proxy is simpler to certificate-manage in production.

   What happens to connected clients during a Reverb restart or deployment?Existing WebSocket connections are dropped when the process restarts. Echo's reconnection logic will re-establish them automatically within a few seconds. For zero-downtime deployments, run two Reverb processes behind the load balancer and drain one before restarting it.

   ![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 articleFilament v4 Render Hooks: Injecting UI Into Any Panel Layer Without Hacks](https://www.msaied.com/public/articles/filament-v4-render-hooks-injecting-ui-into-any-panel-layer-without-hacks) [Next articleFilament v4.13.3 Released: Bug Fixes, MFA Improvements, and New Translations](https://www.msaied.com/public/articles/filament-v4133-released-bug-fixes-mfa-improvements-and-new-translations)  

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

1. [Why Reverb Changes the WebSocket Story for Laravel](#why-reverb-changes-the-websocket-story-for-laravel)
2. [Deployment Architecture](#deployment-architecture)
3. [Horizontal Scaling with Redis](#horizontal-scaling-with-redis)
4. [Private and Presence Channel Auth](#private-and-presence-channel-auth)
5. [Connection Limits and Tuning](#connection-limits-and-tuning)
6. [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)
