Laravel Reverb with Docker: Production Guide

3 min readUpdated on

Reverb is a long-running WebSocket server, not a development terminal command promoted to production. Install and publish its configuration, then make the public and internal addresses explicit in config/reverb.php and the REVERB_* environment values.

env
REVERB_APP_ID=app-id
REVERB_APP_KEY=app-key
REVERB_APP_SECRET=app-secret
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8080
REVERB_HOST=ws.example.com
REVERB_PORT=443
REVERB_SCHEME=https

The SERVER_* values describe the process binding inside Docker; the public values describe what Echo and clients reach through TLS. Proxy WebSocket upgrade headers, expose WSS only, and restrict allowed origins to real application origins. Keep credentials server-side except the public key needed by the client build.

Make public and internal addresses separate

Publish config/reverb.php and keep the bind address distinct from the address Echo reaches. The process listens on Docker's private network; browsers use the TLS endpoint through Nginx. Build-time VITE_ variables are public metadata, never application secrets.

env
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8080
REVERB_HOST=ws.example.com
REVERB_PORT=443
REVERB_SCHEME=https
VITE_REVERB_APP_KEY=${REVERB_APP_KEY}
VITE_REVERB_HOST=ws.example.com
VITE_REVERB_PORT=443
VITE_REVERB_SCHEME=https
nginx
location /app/ {
    proxy_pass http://reverb: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 60s;
}

Prove the whole broadcast path

An event, its channel authorization and the browser listener form one feature. Keep queue workers running: queued broadcasts do not appear merely because the WebSocket process is healthy.

php
<?php

declare(strict_types=1);

namespace App\\Events;

use App\\Models\\Order;
use Illuminate\\Broadcasting\\PrivateChannel;
use Illuminate\\Contracts\\Broadcasting\\ShouldBroadcast;

final class OrderStatusChanged implements ShouldBroadcast
{
    public function __construct(public Order $order) {}

    public function broadcastOn(): array
    {
        return [new PrivateChannel("orders.{$this->order->getKey()}")];
    }
}
typescript
window.Echo.private(`orders.${orderId}`).listen('OrderStatusChanged', (event: { order: { status: string } }) => {
    setStatus(event.order.status);
});

Scaling is a shared-state decision

One instance is a valid first production deployment. Multiple Reverb instances require the documented horizontal-scaling path and a shared backend so every node can see broadcasts and channel state; a load balancer alone cannot make isolated processes coherent. Use a Redis broadcasting path where appropriate, deploy configuration consistently, and test two connections routed to different instances before claiming scale-out works.

Supervise php artisan reverb:start with a container restart policy or process manager, give it a health signal, collect structured logs and drain/restart deliberately during deployments. Monitor connections, reconnects, event latency, CPU, file descriptors and 4xx/5xx proxy responses.

Production failures to rehearse

Check WSS from a browser, private-channel authorization, queue latency and a reconnect during a rolling restart. Monitor connection count, memory, file descriptors, Nginx upgrade failures and Redis connectivity. One node is a sound starting point; before adding replicas, use the documented shared Redis scaling path and prove two clients routed to different instances receive the event.

When not to use Reverb

Do not use WebSockets for a page that can refresh on demand or poll cheaply. Do not expose the internal port directly to the internet. For a globally distributed, managed-reliability requirement, a hosted compatible broadcaster can be a better operational trade-off than owning Reverb capacity and incident response.

Related articles

Existing system support

Need help with a live application?

I help companies improve live systems, clean up delivery workflows, and ship new features without adding avoidable complexity.

Comments (0)
Sign in to leave a comment

You need to be signed in to add a comment.

Login

Need someone to take responsibility for the next step?

Let’s talk about your project and define a scope that actually makes sense for your goals.