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)
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=redisReverb 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:
# 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.1Upgrade/Connectionheaders — Trigger the WebSocket handshakeproxy_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:
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.phpinnopacks/panel/resources/views/layouts/app.blade.phpinnopacks/seller/resources/views/seller/layouts/app.blade.php
Frontend JS assets need to be published to public/vendor/:
public/vendor/laravel-echo/echo.iife.jspublic/vendor/pusher-js/pusher.min.js
Supervisor Process Management
Reverb needs to run as a persistent process, managed by Supervisor (see Supervisor):
[program:innocn-reverb]
command=php /www/wwwroot/www.innoshop.cn/artisan reverb:start --port=8081
autostart=true
autorestart=trueCommon 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
$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():
->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:
php artisan vendor:publish --tag=laravel-echo
php artisan vendor:publish --tag=pusher-jsOr 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:
- Check that
.envhasBROADCAST_CONNECTION=reverb - Check that the layout file includes
@include('common::components.echo') - Check that
config('broadcasting.connections.reverb')values are correct - 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:
- Confirm
QUEUE_CONNECTION=redisin.env - Confirm that the Horizon / queue:work process is running
- 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 Configuration | Frontend 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_PORT | ws://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:
ss -tlnp | grep 8081If 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:
- Is the process running:
ps aux | grep reverb:start - Is the port listening:
ss -tlnp | grep <port> - Is direct connection working: Test with PHP WebSocket handshake script at
127.0.0.1:<port> - Is Nginx proxy working: Test with PHP WebSocket handshake script at
ssl://domain:443 - Are environment variables correct:
php artisan config:show broadcasting - Do frontend assets exist:
ls public/vendor/laravel-echo/ public/vendor/pusher-js/ - Does layout include Echo:
grep -r "components.echo" innopacks/*/resources/views/layouts/ - Is the queue running:
php artisan horizon:statusor check Supervisor