Reverb를 운영하지 않는 Laravel Echo
.env 값 몇 개만 바꾸면 이벤트, 채널, whisper, toOthers()가 그대로 동작합니다.
Laravel Broadcasting은 원래 Pusher 프로토콜을 쓰기 때문에, Laravel 앱은 기본 제공 pusher 연결 그대로 Hibira로 브로드캐스트를 보낼 수 있습니다. 이벤트, 채널 라우트, Echo 코드는 바뀌지 않습니다. 사라지는 것은 직접 운영해야 했던 WebSocket 서버입니다. 계속 실행되는 Reverb 프로세스, 서버 한 대를 넘어설 때 필요한 Redis, 스티키 로드 밸런싱, 그리고 밤에 그것을 지켜볼 사람.
사용자가 얻는 것
- 주문 상태, 알림, 대시보드가 새로고침 없이 업데이트됩니다.
- Echo의
join과whisper로 "입력 중…" 표시와 온라인 목록이 있는 채팅. - 페이지를 여는 순간 최신 상태. 다음 이벤트가 올 때까지 빈 화면이 아닙니다.
사용하는 기능
pusher연결과pusher/pusher-php-server를 쓰는 Laravel Broadcasting.- 브라우저에서는 Laravel Echo와
pusher-js. - 직접 작성한
routes/channels.php로 인가하는 프라이빗 채널과 프레즌스 채널. - 클라이언트 이벤트(Echo
whisper)와 보낸 사람 제외(toOthers()). - 마지막 이벤트를 새 구독자 모두에게 전달하는 캐시 채널(
cache-).
1단계: Broadcasting을 Hibira로 향하게 하기
Laravel 11 이상에서는 broadcasting을 설치하고, 물어보면 Pusher를 고릅니다.
php artisan install:broadcasting
composer require pusher/pusher-php-server
npm install --save-dev laravel-echo pusher-js그다음 .env에 연결을 설정합니다. 값은 앱 페이지에 있습니다.
BROADCAST_CONNECTION=pusher
PUSHER_APP_ID=YOUR_APP_ID
PUSHER_APP_KEY=YOUR_APP_KEY
PUSHER_APP_SECRET=YOUR_APP_SECRET
PUSHER_HOST=ws.hibira.io
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=ap
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"Laravel 10 이하에서는 BROADCAST_CONNECTION 대신 BROADCAST_DRIVER=pusher를 씁니다. 기본 config/broadcasting.php는 이미 호스트, 포트, 스킴을 Pusher 라이브러리에 넘깁니다. 직접 작성한 설정 파일이라면 options가 이 값을 읽는지 확인하세요. 그래야 pusher.com으로 연결하지 않습니다.
2단계: Echo 설정
// resources/js/echo.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: 'ap',
wsHost: import.meta.env.VITE_PUSHER_HOST,
wsPort: import.meta.env.VITE_PUSHER_PORT,
wssPort: import.meta.env.VITE_PUSHER_PORT,
forceTLS: import.meta.env.VITE_PUSHER_SCHEME === 'https',
enabledTransports: ['ws', 'wss'],
});3단계: 고객 한 명에게 이벤트 브로드캐스트
class OrderShipped implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(public Order $order) {}
public function broadcastOn(): array
{
return [new PrivateChannel('orders.'.$this->order->id)];
}
}
// routes/channels.php
Broadcast::channel('orders.{id}', fn ($user, $id) => $user->orders()->whereKey($id)->exists());
// Wherever the order ships
OrderShipped::dispatch($order);Echo.private(`orders.${orderId}`)
.listen('OrderShipped', (e) => showStatus(e.order));ShouldBroadcast 이벤트는 큐를 거치므로 워커(php artisan queue:work)가 실행 중이어야 합니다. 큐가 없는 프로젝트라면 ShouldBroadcastNow로 요청 중에 바로 발행하세요.
4단계: 프레즌스, whisper, toOthers()
Echo.join(`room.${roomId}`)
.here((users) => online.set(users))
.joining((user) => online.add(user))
.leaving((user) => online.remove(user))
.listen('MessageSent', (e) => messages.append(e.message))
.listenForWhisper('typing', (e) => typing.show(e.name, 3000));broadcast(new MessageSent($message))->toOthers();whisper는 클라이언트 이벤트입니다. 앱 설정에서 Allow client events를 켜세요. toOthers()는 X-Socket-ID 헤더로 보낸 사람의 탭을 건너뛰며, Echo가 Axios 요청에 이 헤더를 자동으로 붙입니다. fetch를 쓴다면 'X-Socket-ID': Echo.socketId()를 직접 보내세요. 채팅방 전체는 채팅 사용 사례에 있습니다.
5단계: 새 페이지마다 최신 상태
이름이 cache-로 시작하는 채널에 브로드캐스트하면, 나중에 구독한 사람도 마지막 이벤트를 바로 받습니다(30분간 보관).
public function broadcastOn(): array
{
return [new Channel('cache-scoreboard')];
}Echo.channel('cache-scoreboard')
.listen('ScoreUpdated', (e) => board.render(e.scores));Echo.private('cache-orders.1')도 같은 방식으로 동작하며 private-cache-orders.1 채널이 됩니다.
Reverb나 다른 Pusher 호환 서비스에서 옮겨 오기
바뀌는 것은 .env 값뿐입니다. 이벤트, 채널 라우트, Echo 코드는 그대로이므로 환경을 하나씩 전환할 수 있고 되돌리기도 그만큼 쉽습니다. 확인할 항목은 마이그레이션 페이지에, 로그인하면 Laravel 가이드에 앱 값이 채워진 같은 설정이 있습니다.
팁
- 환경(로컬, 스테이징, 프로덕션)마다 앱을 따로 만들면 테스트 이벤트가 실제 사용자에게 가지 않습니다.
- 프레즌스 채널은 멤버가 최대 100명입니다. 더 큰 방은 대규모 시청자를 참고하세요.
- 브로드캐스트는 몇 개의 브라우저가 받든 메시지 1건으로 계산되며, 전달과 프레즌스 업데이트는 무료입니다.