baggins800/reverb-rs
Rust implementation of the Laravel Reverb WebSocket server: a fast, low-memory drop-in alternative for real-time broadcasting. Speaks the Reverb protocol, so existing Laravel Echo clients and broadcasting configuration keep working unchanged.
baggins800/reverb-rs is a Laravel wrapper around a Rust reimplementation of the Reverb WebSocket server. Instead of running Reverb as a long-lived PHP/ReactPHP process, you run a ~10 MB statically linked binary that speaks the same Pusher protocol, so your Echo/pusher-js frontend and reverb broadcasting config stay untouched. v0.1.1 adds a published container image alongside the existing artisan workflow.
Minimal path:
composer require baggins800/reverb-rs
php artisan reverb-rs:binary # fetches the arch-matched binary
php artisan reverb-rs:start # boots the server
Or, container-first:
docker pull ghcr.io/baggins800/reverb-rs:v0.1.1
Where to look first:
php artisan reverb-rs:start --help and reverb-rs:binary --help — the flags here tell you how much of config/reverb.php it actually honours.config/reverb.php / REVERB_APP_ID, REVERB_APP_KEY, REVERB_APP_SECRET, REVERB_HOST, REVERB_PORT, REVERB_SCHEME env block. Keep BROADCAST_CONNECTION=reverb and leave resources/js/echo.js alone./broadcasting/auth route — channel authorization still happens in Laravel, so private/presence channels are your fastest end-to-end smoke test.First real use case: a small VPS or Docker Compose stack where you don't want a second PHP-FPM-ish process burning 60–100 MB just to hold WebSocket connections. The 10 MB static binary is the entire sell.
Two deployment shapes, pick one per environment.
php artisan reverb-rs:start under Supervisor/systemd, or as a separate terminal next to npm run dev.ghcr.io/baggins800/reverb-rs:v0.1.1 image as its own Compose service or k8s Deployment. Don't run both this and reverb-rs:start; you'll fight over the port and get confusing logs.Bake the binary at build time, never at boot. reverb-rs:binary hits the network. In a Dockerfile:
RUN php artisan reverb-rs:binary
Run it as a build step so production containers start with no egress, work on read-only root filesystems, and boot fast.
Keep config parity between the web and WS processes. The app ID/key/secret must match exactly on both sides, otherwise HTTP broadcast (broadcast()) succeeds but clients never receive anything — a classic 30-minute debugging session. Drive both from the same env vars.
Pin the binary version to the package version. The changelog shows tags (v0.1.1) matching across image and binary. Put php artisan reverb-rs:binary in your deploy/upgrade script right after composer install, otherwise a composer update upgrades the PHP wrapper while the on-disk binary stays stale.
Local dev loop. Terminal 1: php artisan reverb-rs:start. Terminal 2: npm run dev. Terminal 3: php artisan serve. Verify with Echo.private('App.Models.User.1').listen(...) — presence and private channels exercise the auth path, which is the part a Rust reimplementation most often gets subtly wrong.
Health checks must be TCP, not shell. The image is distroless with no shell and no curl. Use a TCP probe on the WS port (default 8080) or a Pusher-protocol HTTP ping, not CMD-SHELL curl.
Scaling. A single Rust process is likely to handle far more concurrent connections than Reverb-PHP, which may let you defer horizontal scaling entirely. If you do run multiple replicas, confirm Redis pub/sub support before assuming broadcasts fan out across nodes — if it isn't there, use sticky sessions and treat each node as isolated.
baggins800/reverb-rs to an exact version in composer.json and pin the image tag. A 0.x minor bump can change flags, config keys, or the binary download URL.reverb-rs:binary is a network command. It will fail in air-gapped CI, on read-only container filesystems, and behind strict egress policies. Pre-bake it or vendor the binary into your image and skip the command entirely.nonroot has consequences. No shell means no docker exec sh, no CMD-SHELL health checks, and no ad-hoc debugging inside the container. Logs on stdout/stderr are your only observability — check whether RUST_LOG or an equivalent is honoured and wire it into your log shipper. Also: nonroot cannot bind ports below 1024, so keep the WS port at 8080+.distroless/static, Alpine/musl hosts are fine. But it also means no glibc-dynamic fallback — if you swap in your own base image, keep it minimal and don't expect to run the binary under a different libc.whisper client events, channel authorization payloads (does the binary forward /broadcasting/auth correctly with cookies/CSRF?), reconnection after network drop, and ->toOthers() echo suppression.routes/channels.php (good), but custom server-side hooks are likely off the table. Check the package docs before designing around them.php artisan reverb:start as a reference implementation. When something doesn't connect, A/B against stock Reverb. If it works there and not here, you've isolated the bug to the binary rather than your config.reverb-rs:start from Supervisor; if Supervisor runs it, don't also start the image. Port conflicts here produce logs that look like client-side failures.v0.1.1 is multi-arch (amd64/arm64), so Apple Silicon and Graviton hosts pull natively. Don't hardcode a digest from one arch into a multi-arch deployment.How can I help you explore Laravel packages today?