Add this to your Nginx site configuration in Forge This should be added to the server block
location /app {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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_cache_bypass $http_upgrade;
# WebSocket specific
proxy_read_timeout 86400;
proxy_send_timeout 86400;
}
Optional: Add a health check endpoint
location /health {
proxy_pass http://127.0.0.1:8080/health;
proxy_http_version 1.1;
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;
}
[program:reverb-server]
process_name=%(program_name)s_%(process_num)02d
command=php /home/forge/pusher.yourdomain.com/artisan reverb:start --host=0.0.0.0 --port=8080
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=forge
numprocs=1
redirect_stderr=true
stdout_logfile=/home/forge/pusher.yourdomain.com/storage/logs/reverb.log
stopwaitsecs=3600
<?php
// For your existing Laravel 9 applications
// config/broadcasting.php
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'), // Your app key from Filament admin
'secret' => env('PUSHER_APP_SECRET'), // Your app secret from Filament admin
'app_id' => env('PUSHER_APP_ID'), // Your app ID from Filament admin
'options' => [
'host' => 'pusher.yourdomain.com',
'port' => 443,
'scheme' => 'https',
'encrypted' => true,
'useTLS' => true,
],
'client_options' => [
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
],
],
// .env configuration for client apps
/*
BROADCAST_CONNECTION=pusher
PUSHER_APP_ID=your-app-id-from-admin
PUSHER_APP_KEY=your-app-key-from-admin
PUSHER_APP_SECRET=your-app-secret-from-admin
PUSHER_HOST=pusher.yourdomain.com
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=
*/
// JavaScript configuration (for frontend)
/*
// resources/js/bootstrap.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'your-app-key-from-admin',
cluster: '', // Leave empty for custom host
wsHost: 'pusher.yourdomain.com',
wsPort: 443,
wssPort: 443,
forceTLS: true,
encrypted: true,
disableStats: true,
enabledTransports: ['ws', 'wss'],
});
*/
php artisan reverb:start --host=0.0.0.0 --port=8080
URL: https://pusher.yourdomain.com/admin Port: 443 (HTTPS) Served by: Laravel app with Filament
URL: wss://pusher.yourdomain.com/app/your-app-key Port: 443 (WSS - WebSocket Secure) Served by: Nginx proxy → Reverb server (internal port 8080)
URL: https://pusher.yourdomain.com/broadcasting/auth Port: 443 (HTTPS) Served by: Laravel app (for private channel authentication)
Internet (Port 443)
↓
Nginx (Port 80/443)
├── /admin → Laravel App (Filament admin)
├── /app → Reverb Server (Port 8080)
└── /broadcasting → Laravel App (auth endpoints)
All Pusher-compatible WebSocket servers (including Soketi, Laravel Reverb, and the official Pusher service) use this URL structure:
wss://your-domain.com/app/{app_key}
Authentication endpoint: https://domain.com/broadcasting/auth Purpose: Authenticate private/presence channels from client-side
When Laravel Uses /broadcasting/auth:
For Private Channels:
// Client tries to subscribe to private channel
Echo.private('orders.1').listen('OrderShipped', (e) => {
console.log(e.order);
});
What happens:
- Client connects to WebSocket: wss://pusher.yourdomain.com/app/your-key
- Client requests private channel: private-orders.
- Laravel client automatically calls: POST /broadcasting/auth
- Your Laravel app validates the user can access that channel
- Returns signed authentication token
- Client subscribes with the token
# Add this BEFORE the existing location / block
location /app {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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_cache_bypass $http_upgrade;
proxy_read_timeout 86400;
proxy_send_timeout 86400;
}
Directory: /home/forge/your.websockets.server.domain/
Command: php8.4 artisan reverb:start --host=0.0.0.0 --port=8080
php artisan make:filament-user
php8.4 artisan make:filament-user