How to use Laravel Reverb on production server
In development environment setup Reverb is pretty straight forward. Setting it up will not bother you too much, But in production server cases are different like you need to setting up SSL. The url behavior will change, suddenly you will realize your dev setup is not working here anymore . The minimum requirement of having Reverb in your Laravel project is PHP 8.2+ and Laravel 10.47+
and I assume you have prior knowledge about docker ,Laravel horizon(but not mandatory, you can use it also with tradition queue system) ,Laravel Events . I will not explain any code rather I will be focuses on production server configuration.
In this article I will use
- Docker for containerization it
- nginx as a web server
- Laravel horizon for queue (You can broadcast any event without queues, you just need to implement this ShouldBroadcastNow interface in your event class)
- supervisord ( to run php:artisan horizon and php:artisan reverb:start)
- Redis as queue driver (not important to focus on, but I mentioned it)
Lets begin with the docker compose file
version: '3.8'
services:
server:
image: nginx:stable-alpine
container_name: w3c-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./src:/var/www/html:cached
- ./.docker/nginx/conf.d:/etc/nginx/conf.d
- /etc/letsencrypt/ssl/fullchain.pem:/etc/nginx/ssl/fullchain.pem
- /etc/letsencrypt/ssl/privkey.pem:/etc/nginx/ssl/privkey.pem
networks:
- w3c-network
depends_on:
- app
- mysql
app:
build:
context: .
dockerfile: php.Dockerfile
container_name: w3c-php
volumes:
- ./src:/var/www/html:cached
- ./.docker/php/php.ini:/usr/local/etc/php/conf.d/custom.ini
ports:
- "9000:9000"
- "5173:5173"
networks:
- w3c-network
mysql:
image: mysql:8.0.17
container_name: w3c-mysql
ports:
- "3306:3306"
restart: unless-stopped
environment:
MYSQL_DATABASE: w3c-chat
MYSQL_USER: w3c-chat_sad
MYSQL_PASSWORD: "password"
MYSQL_ROOT_PASSWORD: "password"
networks:
- w3c-network
volumes:
- ./.docker/data/mysql-data:/var/lib/mysql
php-myadmin:
image: phpmyadmin
restart: always
container_name: w3c-phpMyadmin
ports:
- 8081:80
environment:
- PMA_HOST=mysql
- PMA_PORT=3306
networks:
- w3c-network
redis:
image: redis:alpine
container_name: w3c-redis
ports:
- "6379:6379"
volumes:
- .docker/data/redis-data:/data
networks:
- w3c-network
supervisor:
build:
context: .
dockerfile: supervisord.Dockerfile
container_name: w3c-supervisor
ports:
- "8080:8080"
volumes:
- ./src:/var/www/html
- .docker/supervisord/supervisord.conf:/etc/supervisor/supervisord.conf
networks:
- w3c-network
networks:
w3c-network:
driver: bridgeWhen you start reverb its enable itself on 8080 port .In this above configuration if you notice I did not open the 8080 port in my app service section where I set my php image rather I opened it in supervisord image(Following Laracast and others tutorial I always open 8080 port for php image and failed while I run reverb using supervisord. Its only works when you run php artisan reverb:start command inside the php container, Then I realized instead of php container I must enable 8080 port for supervisord) . This is the reason why I enable the 8080 port on supervisord.
Get Saddanfah’s stories in your inbox
Join Medium for free to get updates from this writer.
Ok now lets move to the .env part where you have to fill up some important part of this configuration process
APP_URL=http://yourdomain.com
BROADCAST_DRIVER=reverb
QUEUE_CONNECTION=redis(As Im using Laravel horizon, queue connection must be redis)
REDIS_CLIENT=predis
REDIS_HOST=redis( Redis host typically 127.0.0.1 but in our case it will be redis which in our docker file redis host image name)
REDIS_PASSWORD=null
REDIS_PORT=6379
REVERB_APP_ID=823522 (randomly generated)
REVERB_APP_KEY=zijrszregsiatovnmv5s (randomly generated)
REVERB_APP_SECRET=mocpvd4cn4qxs8ma7v58 (randomly generated)
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8080
REVERB_HOST="yourdomain.com"
REVERB_PORT=443
REVERB_SCHEME=httpsThis is my supervisord file
[supervisord]
logfile=/etc/supervisor/logs/supervisord.log ; main log file; default $CWD/supervisord.log
logfile_maxbytes=5MB ; max main logfile bytes b4 rotation; default 50MB
logfile_backups=10 ; # of main logfile backups; 0 means none, default 10
loglevel=info ; log level; default info; others: debug,warn,trace
pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid
nodaemon=false ; start in foreground if true; default false
minfds=1024 ; min. avail startup file descriptors; default 1024
minprocs=200 ; min. avail process descriptors;default 200
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
[program:laravel-horizon]
process_name=%(program_name)s
command=php /var/www/html/artisan horizon
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
numprocs=1
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/horizon.log
stopwaitsecs=3600
stdout_logfile_maxbytes=5MB
[program:laravel-reverb]
process_name=%(program_name)s
command=php /var/www/html/artisan reverb:start
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
numprocs=1
minfds=10000
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/reverb.log
stopwaitsecs=3600
stdout_logfile_maxbytes=5MBNow is the most important part your nginx configuration.
server {
listen 80;
server_name your.domain.name;
# Redirect HTTP to HTTPS
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on; # Enable HTTP/2
server_name your.domain.name;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html/public;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
location /app {
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header SERVER_PORT $server_port;
proxy_set_header REMOTE_ADDR $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://supervisor:8080; /****Importan notice****/
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
notice what I wrote proxy_pass http://supervisor:8080 . This “supervisor” came from the host supervisord image name I defined in my docker compose file .
Now run docker-compose up -d — build
Boooooooooomm! You’re ready to rock on your websocket project.
I have a youtube channel where I irregularly ;) post tips and tricks. You can subscribe it for future pro tips Sad Programmer
In any emergency rech on my linkedin : Omar Fahruk Saddan








