Laravel Reverb adalah WebSocket server resmi Laravel yang berjalan di servermu sendiri, sehingga fitur real-time seperti notifikasi instan, chat, dan dashboard yang ter-update otomatis tidak lagi bergantung pada layanan berbayar seperti Pusher. Alurnya: event di-broadcast dari Laravel, Reverb meneruskannya ke browser lewat WebSocket, dan Laravel Echo di frontend memperbarui tampilan. Panduan ini berlaku untuk Laravel 11 ke atas.

Cara Kerja Real-time di Laravel

  1. Aplikasi men-dispatch event yang mengimplementasikan ShouldBroadcast, misalnya dari controller, job, atau observer.
  2. Event masuk queue, lalu dikirim ke Reverb.
  3. Reverb mengirim pesan ke semua klien yang berlangganan channel tersebut.
  4. Laravel Echo di browser menerima pesan dan menjalankan callback untuk memperbarui UI.

Instalasi Laravel Reverb

php artisan install:broadcasting

Perintah ini memasang Reverb, membuat routes/channels.php, dan menyiapkan Laravel Echo beserta pusher-js (dipakai Echo sebagai klien WebSocket karena Reverb memakai protokol Pusher). Variabel yang ditambahkan ke .env:

BROADCAST_CONNECTION=reverb
REVERB_APP_ID=...
REVERB_APP_KEY=...
REVERB_APP_SECRET=...
REVERB_HOST=localhost
REVERB_PORT=8080
REVERB_SCHEME=http

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"

Membuat Event yang Di-broadcast

php artisan make:event OrderStatusUpdated
class OrderStatusUpdated implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(public Order $order) {}

    public function broadcastOn(): array
    {
        return [new PrivateChannel("orders.{$this->order->id}")];
    }

    public function broadcastAs(): string
    {
        return 'order.status-updated';
    }

    public function broadcastWith(): array
    {
        return ['id' => $this->order->id, 'status' => $this->order->status, 'updated_at' => $this->order->updated_at->toIso8601String()];
    }
}

Kirim data seperlunya di broadcastWith(). Tanpa method ini, semua properti publik ikut terkirim, termasuk data yang mungkin tidak perlu dilihat klien.

Otorisasi Channel

// routes/channels.php
Broadcast::channel('orders.{order}', function (User $user, Order $order) {
    return $user->id === $order->customer_id || $user->can('manage-orders');
});

// presence channel: mengembalikan data pengguna yang sedang online
Broadcast::channel('support.room.{room}', function (User $user, int $room) {
    return $user->canJoinRoom($room) ? ['id' => $user->id, 'name' => $user->name] : false;
});
Jenis channelSiapa yang bisa mendengarContoh
PublicSemua orangSkor pertandingan, pengumuman
PrivatePengguna yang lolos otorisasiStatus pesanan, notifikasi pribadi
PresenceSeperti private, plus tahu siapa saja yang onlineChat room, dokumen yang diedit bersama

Dispatch dari Aplikasi

$order->update(['status' => 'dikirim']);
OrderStatusUpdated::dispatch($order);

// atau langsung tanpa queue (hanya untuk kasus tertentu)
broadcast(new OrderStatusUpdated($order))->toOthers();

toOthers() mencegah pengirim menerima event dari aksinya sendiri, berguna di chat agar pesan tidak muncul dua kali.

Frontend dengan Laravel Echo

// halaman detail pesanan
window.Echo.private(`orders.${orderId}`)
    .listen('.order.status-updated', (event) => {
        document.querySelector('[data-order-status]').textContent = event.status;
    });

// chat room dengan presence channel
window.Echo.join(`support.room.${roomId}`)
    .here((users) => renderOnline(users))
    .joining((user) => addOnline(user))
    .leaving((user) => removeOnline(user))
    .listen('.message.sent', (event) => appendMessage(event));

Titik di depan nama event (.order.status-updated) wajib saat memakai broadcastAs(), agar Echo tidak menambahkan namespace class.

Menjalankan Reverb

# development
php artisan reverb:start --debug

# jangan lupa worker queue, karena event broadcast masuk queue
php artisan queue:work

Laravel Reverb di Production

  • Jalankan dengan Supervisor agar Reverb hidup kembali bila mati:
[program:reverb]
command=php /var/www/tokoku/artisan reverb:start --host=0.0.0.0 --port=8080
autostart=true
autorestart=true
user=deploy
  • Taruh di belakang Nginx dengan proxy WebSocket dan HTTPS, sehingga klien terhubung lewat wss:// di port 443.
location /app {
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
    proxy_pass http://127.0.0.1:8080;
}
  • Naikkan batas file terbuka (ulimit -n) karena setiap koneksi WebSocket memakai satu file descriptor.
  • Scaling horizontal: untuk beberapa server Reverb, aktifkan scaling lewat Redis pub/sub di config/reverb.php dengan REVERB_SCALING_ENABLED=true.

Langkah dasar server dan SSL ada di deploy Laravel ke VPS Ubuntu, dan pemakaian Redis dibahas di Redis cache layer di Laravel.

Kesalahan yang Sering Terjadi

  • Event tidak sampai ke browser karena worker queue tidak berjalan. Cek dulu queue:work sebelum mencurigai Reverb.
  • Private channel selalu ditolak karena request otorisasi /broadcasting/auth tidak membawa session atau token.
  • Mixed content: halaman HTTPS mencoba terhubung ke ws://. Pastikan REVERB_SCHEME=https di production.
  • Mengirim seluruh model lewat broadcast, termasuk kolom sensitif.

Langkah Berikutnya

Kalau ingin mengirim notifikasi real-time ke aplikasi mobile atau SPA terpisah, siapkan autentikasinya dengan REST API dengan Laravel Sanctum.