Skip to content

Reverb WebSocket Configuration & Troubleshooting ​

Laravel Reverb provides real-time WebSocket communication for the project. This document covers key configuration points and troubleshooting methods for common issues.

Configuration Overview ​

Environment Variables (.env) ​

dotenv
BROADCAST_CONNECTION=reverb

REVERB_APP_ID=your_app_id
REVERB_APP_KEY=your_app_key
REVERB_APP_SECRET=your_app_secret
REVERB_HOST=www.innoshop.cn
REVERB_PORT=8081
REVERB_SCHEME=https

# Production (with nginx reverse proxy): set to empty, frontend uses port 443 via nginx proxy
# Local development (no reverse proxy): do not set this variable, automatically uses REVERB_PORT for direct connection
REVERB_FRONTEND_PORT=

QUEUE_CONNECTION=redis

Reverb relies on a Redis-driven queue to dispatch broadcast events. QUEUE_CONNECTION must be set to redis.

Nginx Reverse Proxy ​

The Reverb service listens on an internal port (e.g., 8081) and needs to be exposed externally via Nginx reverse proxy for WebSocket connections:

nginx
# WebSocket proxy for Reverb
location /app {
    proxy_pass http://127.0.0.1:8081;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 86400;
}

Key points:

  • proxy_http_version 1.1 — WebSocket upgrade requires HTTP/1.1
  • Upgrade / Connection headers — Trigger the WebSocket handshake
  • proxy_read_timeout 86400 — Keep long connections alive for 24 hours to prevent Nginx from closing them

Bootstrap Route Registration ​

bootstrap/app.php needs to register the channels route file, otherwise broadcast channel authorization will not take effect:

php
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        channels: __DIR__.'/../routes/channels.php',  // Must be added
        health: '/up',
    )

Frontend Echo Component ​

The Echo component is located at innopacks/common/resources/views/components/echo.blade.php and is included in layouts via @include('common::components.echo').

All three layouts already include it:

  • innopacks/front/resources/views/layouts/app.blade.php
  • innopacks/panel/resources/views/layouts/app.blade.php
  • innopacks/seller/resources/views/seller/layouts/app.blade.php

Frontend JS assets need to be published to public/vendor/:

  • public/vendor/laravel-echo/echo.iife.js
  • public/vendor/pusher-js/pusher.min.js

Supervisor Process Management ​

Reverb needs to run as a persistent process, managed by Supervisor (see Supervisor):

ini
[program:innocn-reverb]
command=php /www/wwwroot/www.innoshop.cn/artisan reverb:start --port=8081
autostart=true
autorestart=true

Common Issues ​

1. curl Test Returns 500 / Internal Server Error ​

Symptom: Accessing https://example.com/app/your-key directly with curl returns 500.

Cause: Reverb only accepts WebSocket upgrade requests. Regular HTTP requests (without the Upgrade: websocket header) are rejected and return 500. This is normal behavior and does not indicate a Reverb malfunction.

Verification: Use a PHP script to simulate a WebSocket handshake:

php
<?php
$sock = stream_socket_client("tcp://127.0.0.1:8081", $errno, $errstr, 5);
$key = base64_encode(random_bytes(16));
$headers = "GET /app/your_app_key HTTP/1.1\r\n"
    . "Host: 127.0.0.1:8081\r\n"
    . "Upgrade: websocket\r\n"
    . "Connection: Upgrade\r\n"
    . "Sec-WebSocket-Key: $key\r\n"
    . "Sec-WebSocket-Version: 13\r\n\r\n";
fwrite($sock, $headers);
stream_set_timeout($sock, 3);
echo fread($sock, 4096);
fclose($sock);

Expect to see 101 Switching Protocols and pusher:connection_established.

2. channels.php Not Registered Causes Channel Authorization 404 ​

Symptom: WebSocket connection succeeds, but subscribing to a private channel returns 404.

Cause: The channels route file was not registered in bootstrap/app.php, so the channel authorization callbacks in routes/channels.php do not take effect.

Solution: Add the channels parameter in withRouting():

php
->withRouting(
    // ...
    channels: __DIR__.'/../routes/channels.php',
)

3. HTTP/2 Causes WebSocket Upgrade Failure ​

Symptom: Direct connection to the Reverb port works fine, but the WebSocket handshake fails through the Nginx HTTPS proxy.

Cause: Nginx is configured with http2 on;, but WebSocket upgrade requires HTTP/1.1. Browsers automatically handle protocol negotiation (initiating WebSocket requests with HTTP/1.1 first), but some clients or testing tools may have issues.

Note: In practice, mainstream browsers automatically downgrade to HTTP/1.1 when initiating WebSocket connections, so http2 on; typically does not affect normal frontend usage. If you do encounter issues, you can force HTTP/1.1 in the /app location (the Nginx proxy configuration already includes proxy_http_version 1.1).

4. Missing Frontend JS Assets ​

Symptom: Browser console reports echo.iife.js or pusher.min.js 404.

Solution: Publish the frontend assets:

bash
php artisan vendor:publish --tag=laravel-echo
php artisan vendor:publish --tag=pusher-js

Or manually confirm that public/vendor/laravel-echo/echo.iife.js and public/vendor/pusher-js/pusher.min.js exist.

5. Echo Not Initialized ​

Symptom: After page load, window.Echo is undefined, and the console shows a [Reverb] Echo initialization failed warning.

Troubleshooting:

  1. Check that .env has BROADCAST_CONNECTION=reverb
  2. Check that the layout file includes @include('common::components.echo')
  3. Check that config('broadcasting.connections.reverb') values are correct
  4. Clear the config cache: php artisan config:clear

6. Queue Not Running Causes Broadcast Events to Be Lost ​

Symptom: The server triggers a broadcast event, but the frontend does not receive it.

Cause: Broadcast events are dispatched asynchronously through the queue. If QUEUE_CONNECTION is not redis or the queue worker is not running, events will be discarded.

Solution:

  1. Confirm QUEUE_CONNECTION=redis in .env
  2. Confirm that the Horizon / queue:work process is running
  3. Check the Horizon Dashboard (/horizon) for failed jobs

7. Frontend Directly Connecting to Reverb Port (Bypassing nginx Reverse Proxy) ​

Symptom: The browser connects to wss://www.innoshop.cn:8081/app/... instead of wss://www.innoshop.cn/app/.... Some network environments may block non-standard ports, causing connection failures.

Cause: The Echo component directly uses REVERB_PORT (8081) as the frontend connection port. In production with an nginx reverse proxy, the frontend should go through port 443, with nginx forwarding to the internal Reverb.

Solution: Control this via the REVERB_FRONTEND_PORT environment variable:

Scenario.env ConfigurationFrontend Connection Address
Production (with nginx reverse proxy)REVERB_FRONTEND_PORT= (empty value)wss://www.innoshop.cn/app/... (via 443)
Local development (no reverse proxy)Do not set this variable, automatically uses REVERB_PORTws://localhost:8080/app/... (direct)

The Echo component checks REVERB_FRONTEND_PORT. When empty, it does not output wsPort/wssPort, and Pusher JS automatically uses the default port 443.

8. Port Conflict ​

Symptom: reverb:start fails to start or reports the port is already in use.

Troubleshooting:

bash
ss -tlnp | grep 8081

If the port is occupied by another process, modify REVERB_PORT in .env and restart.

When deploying multiple projects, ensure each project uses a different port (e.g., Factory uses 8080, innoshop.cn uses 8081).

Quick Verification Checklist ​

When encountering Reverb issues, troubleshoot in the following order:

  1. Is the process running: ps aux | grep reverb:start
  2. Is the port listening: ss -tlnp | grep <port>
  3. Is direct connection working: Test with PHP WebSocket handshake script at 127.0.0.1:<port>
  4. Is Nginx proxy working: Test with PHP WebSocket handshake script at ssl://domain:443
  5. Are environment variables correct: php artisan config:show broadcasting
  6. Do frontend assets exist: ls public/vendor/laravel-echo/ public/vendor/pusher-js/
  7. Does layout include Echo: grep -r "components.echo" innopacks/*/resources/views/layouts/
  8. Is the queue running: php artisan horizon:status or check Supervisor