Real-Time Laravel: Deep Dive into Reverb and WebSockets

Real-Time Laravel: Deep Dive into Reverb and WebSockets

Abstract

With the release of Laravel 11, the ecosystem received a first-party WebSocket server: Reverb. Reverb replaces the need for third-party services like Pusher or Ably, allowing developers to host scalable, real-time applications entirely within their own infrastructure. This chapter provides a deep dive into the Reverb architecture, configuring it behind an Nginx reverse proxy, and scaling it with Supervisor.

The Reverb Architecture

Reverb is built on top of the ReactPHP loop (via ext-sockets), enabling synchronous PHP to handle thousands of concurrent WebSocket connections non-blocking. It integrates natively with Laravel’s broadcasting system, meaning events dispatched in Laravel (MessageSent) are instantly pushed to Reverb, which then broadcasts them to connected clients.

Production Deployment: Nginx Reverse Proxy

In a production environment, Reverb runs as a daemon on an internal port (default 8080). However, browsers require Secure WebSockets (WSS) over port 443 for HTTPS sites. Therefore, an Nginx reverse proxy is required to terminate SSL and forward traffic to Reverb.

Nginx Configuration Snippet:

server {
    server_name ws.app.com;
    
    location / {
        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_set_header X-Real-IP $remote_addr;
    }
}

The Upgrade and Connection headers are the standard mechanism for upgrading an HTTP connection to a WebSocket connection.

Process Management with Supervisor

Reverb is a long-running process. If it crashes, it must be restarted immediately. Supervisor is the standard tool for this on Linux servers.

Supervisor Config (/etc/supervisor/conf.d/reverb.conf):

[program:reverb]
command=php /var/www/html/artisan reverb:start
autostart=true
autorestart=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/reverb.log

This configuration ensures that Reverb starts on boot and restarts automatically if it fails.

Frontend Integration: Laravel Echo

On the client side, Laravel Echo is configured to connect to the custom Reverb server rather than the default Pusher endpoints.

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: 'ws.app.com',
    wsPort: 443, // Important: Connect via Nginx HTTPS port
    wssPort: 443,
    forceTLS: true,
    enabledTransports: ['ws', 'wss'],
});

Note that while Reverb listens on 8080 internally, the client must connect to port 443 (HTTPS) because Nginx is handling the traffic. Misconfiguring these ports is the most common deployment error.

Scaling Considerations

Reverb is designed for horizontal scaling using Redis. By configuring Reverb to use Redis as a pub/sub backend, multiple Reverb servers can be deployed behind a load balancer. When an event is broadcast, it is published to Redis, and all Reverb nodes pick it up and broadcast it to their respective connected clients.

Leave a Reply

Your email address will not be published. Required fields are marked *

Your Comment
Your Name
Your Email
Your Website