Laravel Reverb в 2026 году: WebSocket-сервер на PHP без Node.js и сторонних сервисов
Введение: проблема realtime в PHP-приложениях
Долгое время PHP считался языком «запрос-ответ»: пришёл HTTP-запрос — отдали ответ. Реализовать что-то в реальном времени означало либо тащить в стек Node.js, либо платить за Pusher или Ably, либо возиться с self-hosted Soketi. Каждый из этих путей добавлял сложность: другой рантайм, новый сервис, дополнительные расходы или нестабильная самостоятельная поддержка.
История решений выглядела примерно так:
- Pusher — удобно, но платно и данные уходят на сторонний сервер.
- Socket.io + Node.js — мощно, но теперь в проекте два рантайма.
- Soketi — self-hosted Pusher-совместимый сервер на Node.js. Лучше, но всё равно Node.
- Ably — облачный вариант с более щедрым бесплатным планом, но та же зависимость от третьей стороны.
В марте 2024 года команда Laravel представила Laravel Reverb — первый официальный WebSocket-сервер, написанный на чистом PHP и встроенный прямо в экосистему фреймворка. В 2026 году это уже зрелое, production-ready решение. Давайте разберёмся, как оно устроено и как его использовать.
Что такое Laravel Reverb и как он появился
Laravel Reverb — это WebSocket-сервер первого класса для Laravel, реализованный поверх библиотеки ReactPHP. Он полностью совместим с протоколом Pusher Channels, а значит, фронтенд-код, который работал с Pusher или Soketi, переключается на Reverb без изменений — просто меняешь credentials в конфиге.
Reverb появился как ответ на один из самых популярных запросов сообщества: дать разработчикам на Laravel возможность строить realtime-приложения без выхода за пределы PHP-экосистемы. Джо Диксон (Joe Dixon) и команда Laravel потратили несколько месяцев на построение асинхронного event-loop поверх ReactPHP, который позволяет PHP держать тысячи открытых WebSocket-соединений в рамках одного долгоживущего процесса.
«Reverb создан, чтобы Laravel-разработчики могли строить realtime-приложения так же просто, как они строят обычные HTTP-эндпоинты.» — команда Laravel
Архитектура: как Reverb работает внутри
Понять архитектуру Reverb важно, чтобы правильно его настроить и не удивляться поведению в продакшене.
Event Loop и ReactPHP
Reverb запускается как долгоживущий PHP-процесс (не умирает после каждого запроса). Внутри — event loop на базе ReactPHP, который принимает входящие WebSocket-соединения и обрабатывает сообщения асинхронно. Это принципиально отличается от стандартной модели PHP-FPM.
Связь с Broadcasting и Event
Laravel Broadcasting — это абстракция над транспортом событий. Когда вы вызываете broadcast(new OrderShipped($order)), Laravel Broadcasting решает, куда отправить событие: в Pusher, в Redis, в Reverb или куда-то ещё. Reverb регистрируется как broadcasting-драйвер reverb.
Цепочка выглядит так:
- PHP-код файрит событие через
broadcast(). - Laravel Broadcasting отправляет его в очередь (или напрямую) в Reverb-сервер по HTTP/WebSocket.
- Reverb рассылает сообщение всем подписанным клиентам по нужным каналам.
- Фронтенд получает событие через
laravel-echoи Pusher JS SDK.
Установка и базовая настройка Reverb
Давайте пройдём установку шаг за шагом. Предполагается, что у вас уже есть Laravel-проект версии 11+.
Установка пакета
composer require laravel/reverb
php artisan reverb:install
Команда reverb:install опубликует конфиг config/reverb.php, добавит нужные переменные в .env и настроит Broadcasting на драйвер reverb.
Настройка .env
BROADCAST_DRIVER=reverb
REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
REVERB_HOST=0.0.0.0
REVERB_PORT=8080
REVERB_SCHEME=http
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="localhost"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
Запуск сервера
php artisan reverb:start
# или с указанием хоста и порта
php artisan reverb:start --host=0.0.0.0 --port=8080
Настройка фронтенда
Установите зависимости:
npm install --save-dev laravel-echo pusher-js
Настройте Echo в resources/js/bootstrap.js:
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT,
wssPort: import.meta.env.VITE_REVERB_PORT,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});
Масштабирование Reverb с Redis
Один инстанс Reverb — отлично для старта, но что делать, когда нагрузка растёт и нужно несколько серверов? Здесь на помощь приходит Redis.
Reverb поддерживает Redis как pub/sub-бэкенд. Когда событие публикуется на одном инстансе Reverb, Redis рассылает его всем остальным инстансам, и те доставляют сообщение своим подключённым клиентам. Это классическая схема горизонтального масштабирования.
Настройка Redis-бэкенда
# .env
REVERB_SCALING_ENABLED=true
REVERB_SCALING_DRIVER=redis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
В config/reverb.php убедитесь, что секция scaling выглядит так:
'scaling' => [
'enabled' => env('REVERB_SCALING_ENABLED', false),
'channel' => 'reverb',
'server' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REVERB_SCALING_REDIS_DATABASE', '0'),
],
],
Теперь можно запускать несколько инстансов php artisan reverb:start за балансировщиком нагрузки, и Redis будет синхронизировать состояние между ними.
Деплой Reverb в Docker и Kubernetes
Docker-конфигурация
Пример Dockerfile для Laravel-приложения с Reverb:
FROM php:8.3-cli-alpine
RUN apk add --no-cache \
git curl unzip libzip-dev \
&& docker-php-ext-install zip pcntl sockets
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /app
COPY . .
RUN composer install --no-dev --optimize-autoloader
EXPOSE 8080
CMD ["php", "artisan", "reverb:start", "--host=0.0.0.0", "--port=8080"]
Пример docker-compose.yml:
version: '3.9'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- APP_ENV=production
- REVERB_APP_ID=my-app-id
- REVERB_APP_KEY=my-app-key
- REVERB_APP_SECRET=my-app-secret
- REVERB_SCALING_ENABLED=true
- REDIS_HOST=redis
depends_on:
- redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
Kubernetes: Deployment и Service
В Kubernetes Reverb-сервер деплоится как отдельный Deployment с несколькими репликами. Трафик WebSocket прокидывается через Service типа LoadBalancer или через Ingress с поддержкой WebSocket.
apiVersion: apps/v1
kind: Deployment
metadata:
name: reverb
spec:
replicas: 3
selector:
matchLabels:
app: reverb
template:
metadata:
labels:
app: reverb
spec:
containers:
- name: reverb
image: your-registry/laravel-app:latest
command: ["php", "artisan", "reverb:start", "--host=0.0.0.0", "--port=8080"]
ports:
- containerPort: 8080
env:
- name: REVERB_SCALING_ENABLED
value: "true"
- name: REDIS_HOST
value: redis-service
---
apiVersion: v1
kind: Service
metadata:
name: reverb-service
spec:
selector:
app: reverb
ports:
- port: 8080
targetPort: 8080
type: LoadBalancer
Важно: убедитесь, что ваш Ingress-контроллер (например, nginx-ingress) настроен на поддержку апгрейда соединений до WebSocket через заголовки Upgrade и Connection.
Практический пример: чат в реальном времени
Создадим простой публичный чат с использованием Laravel Broadcasting и Vue 3.
Событие на сервере
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets;
public function __construct(
public string $message,
public string $username
) {}
public function broadcastOn(): Channel
{
return new Channel('public-chat');
}
public function broadcastAs(): string
{
return 'message.sent';
}
}
Контроллер
<?php
namespace App\Http\Controllers;
use App\Events\MessageSent;
use Illuminate\Http\Request;
class ChatController extends Controller
{
public function send(Request $request)
{
$request->validate(['message' => 'required|string|max:500']);
broadcast(new MessageSent(
message: $request->message,
username: $request->user()->name ?? 'Anonymous'
));
return response()->json(['status' => 'sent']);
}
}
Vue-компонент
<script setup>
import { ref, onMounted } from 'vue';
const messages = ref([]);
const newMessage = ref('');
onMounted(() => {
window.Echo.channel('public-chat')
.listen('.message.sent', (event) => {
messages.value.push(event);
});
});
const sendMessage = async () => {
await fetch('/chat/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content },
body: JSON.stringify({ message: newMessage.value })
});
newMessage.value = '';
};
</script>
<template>
<div>
<div v-for="msg in messages" :key="msg.message">
<strong>{{ msg.username }}:</strong> {{ msg.message }}
</div>
<input v-model="newMessage" @keyup.enter="sendMessage" placeholder="Введите сообщение..." />
</div>
</template>
Сравнение Reverb с Soketi и Pusher в 2026 году
Выбор инструмента зависит от ваших требований. Вот как выглядит картина в 2026 году:
- Laravel Reverb — нативный PHP, zero external runtime, бесплатно, отличная интеграция с Laravel Broadcasting, поддержка Redis для масштабирования. Идеален для команд, работающих в PHP-стеке. В 2026 году стабилен и поддерживается командой Laravel.
- Soketi — self-hosted, Node.js, Pusher-совместимый. Хорошо работает, но требует Node.js. Развитие замедлилось после появления Reverb, сообщество частично мигрировало.
- Pusher — облачный, zero maintenance, щедрый бесплатный план (200 одновременных соединений). Выбор для стартапов и MVP, где не хочется думать об инфраструктуре. Минус — данные уходят на чужой сервер, есть лимиты и цена при росте.
- Ably — более продвинутый облачный сервис с гарантиями доставки, историей сообщений и глобальной сетью. Дороже Pusher при масштабировании, зато больше возможностей.
Вывод: если вы работаете в Laravel-стеке и хотите полный контроль над инфраструктурой — Reverb это ваш выбор в 2026 году.
Ограничения и когда стоит выбрать другой инструмент
Reverb — отличный инструмент, но у него есть ограничения, о которых нужно знать:
- Один поток на процесс. PHP — не Go и не Erlang. Несмотря на event loop, Reverb работает в одном потоке. Для экстремальных нагрузок (сотни тысяч одновременных соединений) потребуется тщательная настройка горизонтального масштабирования с Redis.
- Нет встроенной истории сообщений. Reverb не хранит историю. Если нужна доставка пропущенных сообщений — реализуйте это сами через базу данных или выбирайте Ably.
- Нет presence-каналов out of the box. Точнее, presence-каналы поддерживаются, но их состояние не сохраняется между рестартами сервера без Redis.
- WebSocket-only. Reverb не поддерживает SSE (Server-Sent Events) или Long Polling как фолбэк. Если нужна поддержка окружений без WebSocket — Laravel Echo с другим транспортом или Mercure будут лучшим выбором.
- Production-нагрузка требует супервизора. Reverb нужно запускать через Supervisor или аналогичный process manager, чтобы он перезапускался при падении.
Заключение
Laravel Reverb в 2026 году — это зрелое, production-ready решение для realtime в PHP-приложениях. Он убирает главный барьер: больше не нужен Node.js, не нужен сторонний сервис, не нужны лишние деньги на Pusher. Вы пишете PHP — Reverb доставляет события клиентам по WebSocket.
Начать можно за 15 минут: установил пакет, добавил переменные в .env, запустил php artisan reverb:start — и realtime в вашем Laravel-проекте работает. Дальше — Redis для масштабирования, Docker и Kubernetes для надёжного деплоя.
Экспериментируйте, стройте чаты, дашборды реального времени, live-уведомления — инструмент готов. Стек остаётся чистым PHP, команда Laravel поддерживает Reverb и развивает его. Самое время попробовать.
Технологии
Теги
Руслан Исмаилов
Senior Web / Backend разработчик. Senior web/backend разработчик с 9-летним опытом. Стек: PHP, Laravel, PostgreSQL, Redis, Docker, Kubernetes, REST, микросервисы, CI/CD. Подробнее обо мне →