DEV Community

Edgaras
Edgaras

Posted on

Configuring Reverb in Laravel 11 with Apache

Reverb is a practical alternative to Pusher for real-time event broadcasting in Laravel. This guide focuses on configuring Reverb in Laravel 11 for a live production system hosted behind Cloudflare with Flexible SSL.

Prerequisites

Before diving into the setup, ensure you have the following:

  1. Laravel 11 installed: You can set up a fresh Laravel 11 application using Composer.
  2. Apache web server: Ensure Apache is installed and running.
  3. Cloudflare account: Your application should be set up behind Cloudflare with Flexible SSL enabled.

Install Reverb

To start, you need to install Reverb in your Laravel project. Run the following Composer command:

composer require laravel/reverb
Enter fullscreen mode Exit fullscreen mode

After installation, publish the configuration file:

php artisan vendor:publish --provider="Laravel\Reverb\ReverbServiceProvider"
Enter fullscreen mode Exit fullscreen mode

This will create a config/reverb.php file where you can adjust Reverb’s settings.

Reverb Configuration Example

The following is an example configuration for Reverb:

<?php

return [

    'default' => env('REVERB_SERVER', 'reverb'),

    'servers' => [

        'reverb' => [
            'host' => env('REVERB_HOST', '0.0.0.0'),
            'port' => env('REVERB_PORT', 6001),
            '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'),
                ],
            ],
            'pulse_ingest_interval' => env('REVERB_PULSE_INGEST_INTERVAL', 15),
            'telescope_ingest_interval' => env('REVERB_TELESCOPE_INGEST_INTERVAL', 15),
        ],

    ],

    '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),
            ],
        ],

    ],

];
Enter fullscreen mode Exit fullscreen mode

.env Settings

Ensure the following environment variables are correctly configured in your .env file:

BROADCAST_CONNECTION=reverb 
QUEUE_CONNECTION=database

REVERB_HOST=127.0.0.1 
REVERB_PORT=6001
REVERB_APP_ID=<app-id>
REVERB_APP_KEY=<app-key>
REVERB_APP_SECRET=<app-secret>
REVERB_SCHEME=http

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="example.com"
VITE_REVERB_PORT=443
VITE_REVERB_SCHEME=https 
Enter fullscreen mode Exit fullscreen mode

Creating an Event

Use the following Artisan command to generate a new event class:

php artisan make:event MessageSent
Enter fullscreen mode Exit fullscreen mode

Here is an example implementation of the MessageSent event:

<?php

namespace App\Events;

use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\Channel;

class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;

    public function __construct($message)
    {
        $this->message = $message;
    }

    public function broadcastOn(): Channel
    {
        return new Channel('chat-channel');
    }

    public function broadcastAs(): string
    {
        return 'message-sent';
    }
}
Enter fullscreen mode Exit fullscreen mode

Laravel Blade Example

Create a simple Blade template to test Reverb functionality (welcome.blade.php):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>Laravel Reverb WebSocket Test</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pusher/8.3.0/pusher.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/laravel-echo/1.17.1/echo.iife.min.js"></script>
</head>
<body>
    <h1>Laravel Reverb WebSocket Test</h1>
    <p>Open the console to see WebSocket messages.</p>
    <button id="sendMessage">Send Test Message</button>

    <script>
        document.addEventListener('DOMContentLoaded', function () {

            document.getElementById('sendMessage').addEventListener('click', async () => {
                const response = await fetch('/send-message', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
                    },
                    body: JSON.stringify({ message: 'Hello, Reverb!' }),
                });

                const result = await response.json();
                console.log('Message sent:', result);
            });

            window.Pusher = Pusher;
            window.Echo = new Echo({
                broadcaster: 'reverb',
                key: '{{ env('REVERB_APP_KEY') }}',
                wsHost: '{{ env('VITE_REVERB_HOST', request()->getHost()) }}',
                wsPort: 6001,
                wssPort: 443,
                forceTLS: true,
                enabledTransports: ['ws', 'wss'],
                cluster: 'mt1',
            });

            window.Echo.channel('chat-channel')
                .listen('.message-sent', (data) => {
                    console.log('Received event:', data.message);
            });

        });
    </script>
</body>
</html>

Enter fullscreen mode Exit fullscreen mode

Defining Routes

Below is the code to define the required routes:

<?php

use Illuminate\Support\Facades\Route;
use App\Events\MessageSent;

Route::post('/send-message', function (\Illuminate\Http\Request $request) {

    event(new MessageSent($request->input('message')));

    return response()->json(['success' => true]);

});

Route::get('/', function () { return view('welcome'); });

Enter fullscreen mode Exit fullscreen mode

Apache Configuration

Run the following commands to enable the necessary Apache modules:

sudo a2enmod proxy
sudo a2enmod proxy_wstunnel 
sudo a2enmod rewrite
Enter fullscreen mode Exit fullscreen mode

Below is an example configuration for your Apache VirtualHost setup:

<VirtualHost *:80>
    ServerAdmin admin@example.com
    ServerName example.com
    DocumentRoot /var/www/example.com/public

    ProxyPreserveHost On
    ProxyRequests Off
    ProxyPass /app ws://127.0.0.1:6001/app
    ProxyPassReverse /app ws://127.0.0.1:6001/app

    SetEnvIf X-Forwarded-Proto https HTTPS=on

    ErrorLog /var/www/logs/example.com_error.log
    CustomLog /var/www/logs/example.com_access.log combined
</VirtualHost>

<Directory /var/www/example.com>
    Options -Indexes +FollowSymLinks -MultiViews
    AllowOverride All
    Require all granted
</Directory>
Enter fullscreen mode Exit fullscreen mode

Running Services

To start the services, you'll need to launch the event worker and the Rebel server.
Run the following command to initiate the event worker:

php artisan queue:work
Enter fullscreen mode Exit fullscreen mode

Use the command below to start the Rebel server on the specified port and host:

php artisan reverb:start --port=6001 --host=0.0.0.0
Enter fullscreen mode Exit fullscreen mode

Conclusion

If you do not use the CDN for Laravel Echo and Pusher, you will need to install the required npm libraries (pusher-js and laravel-echo) to integrate real-time event broadcasting into your application. This setup requires a frontend build process to manage and bundle the libraries within your project.

For applications hosted behind Cloudflare with Full SSL, a separate VirtualHost must be configured with properly defined SSL certificates. This ensures secure WebSocket communication and avoids issues with SSL/TLS mismatches, which can prevent WebSocket connections from functioning correctly.

Top comments (0)