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
- Aplikasi men-dispatch event yang mengimplementasikan
ShouldBroadcast, misalnya dari controller, job, atau observer. - Event masuk queue, lalu dikirim ke Reverb.
- Reverb mengirim pesan ke semua klien yang berlangganan channel tersebut.
- 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 channel | Siapa yang bisa mendengar | Contoh |
|---|---|---|
| Public | Semua orang | Skor pertandingan, pengumuman |
| Private | Pengguna yang lolos otorisasi | Status pesanan, notifikasi pribadi |
| Presence | Seperti private, plus tahu siapa saja yang online | Chat 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.phpdenganREVERB_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:worksebelum mencurigai Reverb. - Private channel selalu ditolak karena request otorisasi
/broadcasting/authtidak membawa session atau token. - Mixed content: halaman HTTPS mencoba terhubung ke
ws://. PastikanREVERB_SCHEME=httpsdi 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.