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.