VPS GoDaddy, AlmaLinux. I'm writing a messenger and used the following technology stack: Laravel Reverb, Redis. I installed Reverb like this:
php artisan install:broadcasting
I couldn't configure the Nginx proxy (it seems that this is prohibited on this hosting), so I used Pre VirtualHost Include from Apache:
# Load required proxy modules
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
# Global proxy settings
ProxyPreserveHost On
ProxyRequests Off
# Laravel Reverb configuration for <host>
<VirtualHost *:80>
ServerName <host>
ServerAlias www.<host>
DocumentRoot /home/<project>/public_html/public
# WebSocket connections on /app
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/app/(.*)$ ws://127.0.0.1:3000/app/$1 [P,L]
# API requests on /apps
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/apps/(.*)$ ws://127.0.0.1:3000/apps/$1 [P,L]
# HTTP proxy for /app (WebSocket endpoint)
ProxyPass /app/ http://127.0.0.1:3000/app/
ProxyPassReverse /app/ http://127.0.0.1:3000/app/
# HTTP proxy for /apps (API endpoint)
ProxyPass /apps/ http://127.0.0.1:3000/apps/
ProxyPassReverse /apps/ http://127.0.0.1:3000/apps/
# Proxy headers (Apache equivalent for Nginx headers)
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:3000/ connectiontimeout=5 retry=300
ProxyPassReverse / http://127.0.0.1:3000/
ErrorLog /usr/local/apache/domlogs/<host>_error.log
CustomLog /usr/local/apache/domlogs/<host>_access.log combined
</VirtualHost>
<VirtualHost *:443>
ServerName <host>
ServerAlias www.<host>
DocumentRoot /home/<project>/public_html/public
# WebSocket connections on /app (HTTPS)
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/app/(.*)$ ws://127.0.0.1:3000/app/$1 [P,L]
# API requests on /apps (HTTPS)
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule ^/apps/(.*)$ ws://127.0.0.1:3000/apps/$1 [P,L]
# HTTP proxy for /app
ProxyPass /app/ http://127.0.0.1:3000/app/
ProxyPassReverse /app/ http://127.0.0.1:3000/app/
# HTTP proxy for /apps
ProxyPass /apps/ http://127.0.0.1:3000/apps/
ProxyPassReverse /apps/ http://127.0.0.1:3000/apps/
# Headers for WebSocket over SSL
<Location "/app/">
ProxyPass http://127.0.0.1:3000/app/
ProxyPassReverse http://127.0.0.1:3000/app/
ProxyPreserveHost On
# Apache equivalent of Nginx headers
Header always set "Upgrade" "%{HTTP:Upgrade}i"
Header always set "Connection" "%{HTTP:Connection}i"
SetEnvIf X-Forwarded-Proto https HTTPS=on
</Location>
<Location "/apps/">
ProxyPass http://127.0.0.1:3000/apps/
ProxyPassReverse http://127.0.0.1:3000/apps/
ProxyPreserveHost On
</Location>
ErrorLog /usr/local/apache/domlogs/<host>_ssl_error.log
CustomLog /usr/local/apache/domlogs/<host>_ssl_access.log combined
</VirtualHost>
.env variables:
# --- Reverb (Broadcast Driver) ---
BROADCAST_DRIVER=reverb
REVERB_SERVER_HOST=127.0.0.1
REVERB_SERVER_PORT=3000
REVERB_APP_ID=<id>
REVERB_APP_KEY=<key>
REVERB_APP_SECRET=<secret>
REVERB_HOST="<host>"
REVERB_PORT=443
REVERB_SCHEME=https
REVERB_CLUSTER=mt1
VITE_REVERB_APP_KEY=${REVERB_APP_KEY}
VITE_REVERB_HOST=${REVERB_HOST}
VITE_REVERB_PORT=443
VITE_REVERB_SCHEME=https
VITE_REVERB_CLUSTER="${REVERB_CLUSTER}"
QUEUE_CONNECTION=redis
#Other redis settings
config/broadcasting.php:
return [
/*
|--------------------------------------------------------------------------
| Default Broadcaster
|--------------------------------------------------------------------------
|
| This option controls the default broadcaster that will be used by the
| framework when an event needs to be broadcast. You may set this to
| any of the connections defined in the "connections" array below.
|
*/
'default' => env('BROADCAST_DRIVER', 'reverb'),
/*
|--------------------------------------------------------------------------
| Broadcast Connections
|--------------------------------------------------------------------------
|
| Here you may define all of the broadcast connections that will be used
| to broadcast events to other systems or over websockets. Samples of
| each available type of connection are provided inside this array.
|
*/
'connections' => [
'reverb' => [
'driver' => 'pusher',
'key' => env('REVERB_APP_KEY'),
'secret' => env('REVERB_APP_SECRET'),
'app_id' => env('REVERB_APP_ID'),
'options' => [
'host' => env('REVERB_HOST', '127.0.0.1'),
'port' => env('REVERB_PORT', 8080),
'scheme' => env('REVERB_SCHEME', 'http'),
'cluster' => env('REVERB_CLUSTER', 'mt1'),
'useTLS' => env('REVERB_SCHEME', 'http') === 'https',
],
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => true,
],
],
'ably' => [
'driver' => 'ably',
'key' => env('ABLY_KEY'),
],
'log' => [
'driver' => 'log',
],
'null' => [
'driver' => 'null',
],
],
];
config/reverb.php:
return [
/*
|--------------------------------------------------------------------------
| Default Reverb Server
|--------------------------------------------------------------------------
|
| This option controls the default server used by Reverb to handle
| incoming messages as well as broadcasting message to all your
| connected clients. At this time only "reverb" is supported.
|
*/
'default' => env('REVERB_SERVER', 'reverb'),
/*
|--------------------------------------------------------------------------
| Reverb Servers
|--------------------------------------------------------------------------
|
| Here you may define details for each of the supported Reverb servers.
| Each server has its own configuration options that are defined in
| the array below. You should ensure all the options are present.
|
*/
'servers' => [
'reverb' => [
'host' => env('REVERB_SERVER_HOST', '0.0.0.0'),
'port' => env('REVERB_SERVER_PORT', 8080),
'path' => env('REVERB_SERVER_PATH', ''),
'hostname' => env('REVERB_HOST'),
'options' => [
'tls' => [],
],
'max_request_size' => env('REVERB_MAX_REQUEST_SIZE', 10_000),
'scaling' => [
'enabled' => env('REVERB_SCALING_ENABLED', false),
'channel' => env('REVERB_SCALING_CHANNEL', 'reverb'),
'server' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'port' => env('REDIS_PORT', '6379'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'database' => env('REDIS_DB', '0'),
'timeout' => env('REDIS_TIMEOUT', 60),
],
],
'pulse_ingest_interval' => env('REVERB_PULSE_INGEST_INTERVAL', 15),
'telescope_ingest_interval' => env('REVERB_TELESCOPE_INGEST_INTERVAL', 15),
],
],
/*
|--------------------------------------------------------------------------
| Reverb Applications
|--------------------------------------------------------------------------
|
| Here you may define how Reverb applications are managed. If you choose
| to use the "config" provider, you may define an array of apps which
| your server will support, including their connection credentials.
|
*/
'apps' => [
'provider' => 'config',
'apps' => [
[
'key' => env('REVERB_APP_KEY'),
'secret' => env('REVERB_APP_SECRET'),
'app_id' => env('REVERB_APP_ID'),
'options' => [
'host' => env('REVERB_HOST'),
'port' => env('REVERB_PORT', 443),
'scheme' => env('REVERB_SCHEME', 'https'),
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
],
'allowed_origins' => ['*'],
'ping_interval' => env('REVERB_APP_PING_INTERVAL', 60),
'activity_timeout' => env('REVERB_APP_ACTIVITY_TIMEOUT', 30),
'max_message_size' => env('REVERB_APP_MAX_MESSAGE_SIZE', 10_000),
],
],
],
];
resources/js/echo.js:
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
const echoConfig = {
broadcaster: 'pusher',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST || window.location.hostname,
wsPort: import.meta.env.VITE_REVERB_PORT || window.location.port,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME || window.location.protocol) === 'https:',
enabledTransports: ['ws', 'wss'],
cluster: import.meta.env.VITE_REVERB_CLUSTER || 'mt1',
authEndpoint: '/broadcasting/auth',
auth: {
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content,
},
},
};
if (!echoConfig.key) {
console.error('REVERB_APP_KEY is not defined');
} else {
window.Echo = new Echo(echoConfig);
}
Starting reverb server (due to weird settings of the hosting):
/opt/cpanel/ea-php83/root/usr/bin/php artisan reverb:start --host=127.0.0.1 --port=3000 --debug -vvv
And in this debug output I'm getting an error:
[ERROR] Laravel\Reverb\Protocols\Pusher\Http\Controllers\PusherController::__invoke(): Argument #2 ($connection) must
be of type Laravel\Reverb\Servers\Reverb\Connection, Laravel\Reverb\Servers\Reverb\Http\Connection given,
called in /home/<project>/public_html/vendor/laravel/reverb/src/Servers/Reverb/Http/Router.php on line 74
Updating packages does not help. Package "laravel/reverb": "^1.5". Please explain to me how to solve this issue, cause my connections failed:
echo-B7dTUkUW.js:8 WebSocket connection to 'wss://<host>/app/<key>?protocol=7&client=js&version=8.4.0&flash=false' failed