Back to Menu

# How to Set Up Laravel Reverb on Cloudways with FilamentPHP and Cloudflare

How to Set Up Laravel Reverb on Cloudways with FilamentPHP and Cloudflare

Learn how to set up Laravel Reverb on Cloudways with FilamentPHP and Cloudflare for real-time notifications and WebSocket support. This step-by-step guide covers the server setup, configuration, and deployment process for a smooth production-ready setup.

5 min read
#LaravelReverb#Cloudways#FilamentPHP#Cloudflare#LaravelWebSockets#Laravel

Table of Contents

How to Set Up Laravel Reverb on Cloudways with FilamentPHP and Cloudflare

Prerequisites

  • An existing FilamentPHP project.
  • A Cloudways hosting account with a Laravel-based website already deployed.
  • Cloudflare DNS configured for your domain.
  • SSH access to your Cloudways server via PuTTY or Termius.

Part 1: Local Development Setup

Step 1 - Install Reverb on your FilamentPHP Project

Terminal window
composer require laravel/reverb
php artisan reverb:install

This creates config/reverb.php and adds Reverb environment variables to .env.

Step 2 - Update Local .env

BROADCAST_CONNECTION=reverb
REVERB_APP_ID=<auto-generated>
REVERB_APP_KEY=<auto-generated>
REVERB_APP_SECRET=<auto-generated>
REVERB_HOST="localhost"
REVERB_PORT=8080
REVERB_SCHEME=http
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8080
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"

Remove any duplicate Reverb entries if reverb:install doubled them.

Step 3 - Publish Filament Config

Terminal window
php artisan vendor:publish --tag=filament-config

Step 4 - Update config/filament.php

Uncomment the broadcasting.echo section and set:

'broadcasting' => [
'echo' => [
'broadcaster' => 'reverb',
'key' => env('VITE_REVERB_APP_KEY'),
'cluster' => env('VITE_REVERB_APP_CLUSTER'),
'wsHost' => env('VITE_REVERB_HOST'),
'wsPort' => env('VITE_REVERB_PORT'),
'wssPort' => env('VITE_REVERB_PORT'),
'authEndpoint' => '/broadcasting/auth',
'disableStats' => true,
'encrypted' => true,
'forceTLS' => (env('VITE_REVERB_SCHEME', 'http') === 'https'),
],
],

forceTLS is driven by environment variables, so there is no need to change config between environments.

Step 5 - Update config/broadcasting.php

Make the server-side connection use local Reverb, not the public domain:

'reverb' => [
'driver' => 'reverb',
'key' => env('REVERB_APP_KEY'),
'secret' => env('REVERB_APP_SECRET'),
'app_id' => env('REVERB_APP_ID'),
'options' => [
'host' => env('REVERB_SERVER_HOST', '127.0.0.1'),
'port' => env('REVERB_SERVER_PORT', 8091),
'scheme' => 'http',
'useTLS' => false,
],
'client_options' => [],
],

This is critical for production. Laravel pushes events to Reverb locally (127.0.0.1), avoiding SSL certificate issues.

Step 6 - Clear Caches

Terminal window
php artisan config:clear
php artisan route:clear
php artisan cache:clear

Step 7 - Create start-reverb.bat (Windows local dev)

Terminal window
@echo off
:start
echo Starting Laravel Reverb WebSocket Server...
php artisan reverb:start --debug
echo Reverb stopped. Restarting in 5 seconds...
timeout /t 5 /nobreak
goto start

Step 8 - Test Locally

  1. Run start-reverb.bat in one terminal.
  2. Open the IMS in the browser and inspect DevTools → Network → WS / Socket tab.
  3. You should see ws://localhost:8080/app/... with 101 Switching Protocols.
  4. Test a broadcast in another terminal:
Terminal window
php artisan tinker --execute="\Filament\Notifications\Notification::make()->title('Test')->body('Works!')->broadcast(\App\Models\User::find(1));"

A toast notification should pop up in the browser.



Part 2: Production Setup (Cloudways)

Step 9 - Update Production .env

BROADCAST_CONNECTION=reverb
REVERB_APP_ID=<your-app-id>
REVERB_APP_KEY=<your-app-key>
REVERB_APP_SECRET=<your-app-secret>
REVERB_HOST="ws.yourdomain.com"
REVERB_PORT=443
REVERB_SCHEME=https
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8091
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"

Key distinction:

  • REVERB_HOST / REVERB_PORT / REVERB_SCHEME = what the browser connects to publicly
  • REVERB_SERVER_HOST / REVERB_SERVER_PORT = what Reverb binds to internally
  • config/broadcasting.php uses REVERB_SERVER_* to push events locally

Step 10 - Cloudflare DNS

Add an A record in Cloudflare under DNS → Records → Add Record:

FieldValue
TypeA
Namews
IPv4Your Cloudways server IP
ProxyProxied (orange cloud)
TTLAuto

To find your server IP, check your existing main domain A record or Cloudways → My Servers → Master Credentials → Public IP.

Step 11 - SSL Certificate

Ensure your Cloudflare Origin Certificate covers *.yourdomain.com as a wildcard. Check this in Cloudflare → SSL/TLS → Origin Server.

If not, create one using:

FieldValue
Private key typeRSA (2048)
Hostnamesyourdomain.com, *.yourdomain.com
Certificate validity15 years

Copy the certificate and private key, then upload them to Cloudways → Application Settings → SSL Certificate → Upload Custom SSL.

Step 12 - Cloudways Domain Mapping

Go to Cloudways → My Applications → Domain Management and add ws.yourdomain.com as an alias domain.

Step 13 - Disable HTTP/2 in Nginx

Contact Cloudways support with this message:

Please comment out http2 on; in my application’s Nginx server block. I need HTTP/1.1 for WebSocket support with Laravel Reverb.

This is required because Nginx HTTP/2 strips WebSocket upgrade headers.

Step 14 - Nginx WebSocket Proxy

Contact Cloudways support:

location /app {
proxy_pass http://127.0.0.1:8091;
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_set_header X-Forwarded-Host $host;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_read_timeout 86400s;
}

Step 15 - Supervisor Job for Reverb

A. Create the job in Cloudways GUI

A.1. Contact Cloudways support to fix the command

I created a new Supervisord job (ID: [your job ID]). I need it to run: php artisan reverb:start --host=0.0.0.0 --port=8091
This is a WebSocket server, not a queue worker. Please:

  • Use exactly the command above - no --queue, --sleep, --tries, --quiet, or --timeout flags
  • Number of processes: 1
  • Auto-restart if it stops

B. Verify after support confirms

Terminal window
ps aux | grep reverb

This should show the Reverb process running.

Step 16 - Clear Caches

Terminal window
php artisan config:clear
php artisan route:clear
php artisan cache:clear

Step 17 - Verify Production

  1. Check Reverb is running:
Terminal window
ps aux | grep reverb
  1. Test whether the port is listening:
Terminal window
curl -i http://127.0.0.1:8091

It should return HTTP/1.1 404 Not Found, which means Reverb is responding.

  1. Test WebSocket handshake directly, bypassing Nginx:
Terminal window
curl -i -N \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
http://127.0.0.1:8091/app/<your-reverb-key>

It should return 101 Switching Protocols.

  1. Test through Nginx + Cloudflare:
Terminal window
curl -i -N -k \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
https://ws.yourdomain.com/app/<your-reverb-key>

It should return 101 Switching Protocols.

  1. Check the browser:

Open IMS → DevTools → Network → Socket tab (Edge) or WS tab (Chrome). You should see wss://ws.yourdomain.com/app/... with 101 Switching Protocols and ping/pong messages.

  1. Test a broadcast:
Terminal window
php artisan tinker --execute="\Filament\Notifications\Notification::make()->title('Production Test')->body('Broadcast at ' . now()->toTimeString())->broadcast(\App\Models\User::find(1));"

A toast notification should appear in the browser instantly.



Final Architecture

Browser (wss://ws.yourdomain.com:443)
→ Cloudflare (proxied, orange cloud, WebSockets enabled)
→ Nginx (location /app → 127.0.0.1:8091, HTTP/2 disabled)
→ Laravel Reverb (0.0.0.0:8091)
Laravel Server-Side (broadcasting events)
→ http://127.0.0.1:8091 (local, no SSL)
→ Laravel Reverb
→ pushes to connected browsers


Troubleshooting Cheatsheet

ProblemSolution
Reverb not runningps aux grep reverb then sudo supervisorctl restart <job_id>
Browser wss:// connection errorCheck Nginx proxy exists, HTTP/2 disabled, Cloudflare WebSockets enabled
Browser ws:// mixed content errorEnsure REVERB_SCHEME=https in production .env
Broadcast fails with SSL errorEnsure config/broadcasting.php uses REVERB_SERVER_HOST (127.0.0.1), not public domain
No toast notificationCheck failed jobs: php artisan queue:failed, flush with php artisan queue:flush
Address already in use errorpkill -f "reverb:start" then restart Supervisor
Config not taking effectphp artisan config:clear
Nginx returns 500 on /appHTTP/2 is enabled - ask Cloudways to disable it
curl SSL certificate error from SSHNormal for Cloudflare Origin certs - use -k, browser should still work

Comments & Reactions

(click to open)

Related posts