I’m trying to implement Laravel Websockets with multiple servers.
I have an App server and a Queue Worker server running. I tried to broadcast my notifications from the Queue Worker server but I’m getting
lluminateBroadcastingBroadcastException: Pusher error: . in /home/forge/my-app/vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php:128
In the App Server, in Network tab I can confirm it connects to the websocket. I’ve used alex bouma’s post and setup reverse proxy. If I broadcast within the App Server, it works:
server {
listen 6002 ssl http2;
listen [::]:6002 ssl http2;
server_name example.com;
index.php
location / {
proxy_pass http://127.0.0.1:6001;
proxy_read_timeout 60;
proxy_connect_timeout 60;
proxy_redirect off;
# Allow the use of websockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
App Server & Queue Worker are in private networks and can connect to each other. However when I try to broadcast from the Queue Worker server, it doesn’t work.
I’m having difficulty understanding how to make it work.
-
Do I have to run
php artisan websockets:serve
also on the queue worker? If so, do I need to give--host={private-ip}
flag? -
In my
broadcasting.php
, I have added App Server’s private ip asPUSHER_ENDPOINT_HOST
for Queue Worker’s env. Is this correct?
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => in_array(config('app.env'), ['production', 'staging']),
'host' => env('PUSHER_ENDPOINT_HOST', '127.0.0.1'),
'port' => 6001,
'scheme' => 'http'
],
],
Update: I have made changes as @KamleshPaul suggested. Here is how all my code looks like below.
I have these configs in both app server and worker server. I’m running php artisan websockets:serve
on both, and App Server successfully connects to the socket. However, the queue worker doesn’t send the notification.
Both php artisan websockets:serve
shows: "Starting the WebSocket server on port 6001…"
But still it doesn’t seem to work. (By the way, I’m using Laravel Forge and allowed ports are:
-
App: 6001, 6002, 433, 22
-
Worker: 6001, 6002, 22
.env
PUSHER_APP_ID=aaa
PUSHER_APP_KEY=bbb
PUSHER_APP_SECRET=ccc
PUSHER_APP_CLUSTER=mt1
PUSHER_HOST=socket.my_domain.com
PUSHER_PORT=433
PUSHER_SCHEME=https
VITE_PUSHER_APP_KEY=${PUSHER_APP_KEY}
VITE_PUSHER_APP_CLUSTER=${PUSHER_APP_CLUSTER}
VITE_PUSHER_HOST=${PUSHER_HOST}
VITE_PUSHER_SCHEME={PUSHER_SCHEME}
VITE_PUSHER_PORT={PUSHER_PORT}
echo.js
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
wsHost: import.meta.env.VITE_PUSHER_HOST,
wsPort: import.meta.env.VITE_PUSHER_PORT || 443,
forceTLS: true,
disableStats: true,
scheme: import.meta.env.VITE_PUSHER_SCHEME,
enabledTransports: ["ws", "wss"],
}
broadcasting.php
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'encrypted' => true,
'host' => env('PUSHER_HOST'),
'port' => env('PUSHER_PORT'),
'scheme' => env('PUSHER_SCHEME')
],
],
nginx of socket.my_domain.com
# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/socket.my_domain.com/before/*;
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name socket.my_domain.com;
server_tokens off;
root /home/forge/socket.my_domain.com/public;
# FORGE SSL (DO NOT REMOVE!)
ssl_certificate /etc/nginx/ssl/socket.my_domain.com/1262458/server.crt;
ssl_certificate_key /etc/nginx/ssl/socket.my_domain.com/1262458/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_dhparam /etc/nginx/dhparams.pem;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/socket.my_domain.com/server/*;
location / {
proxy_pass http://127.0.0.1:6001;
proxy_read_timeout 60;
proxy_connect_timeout 60;
proxy_redirect off;
# Allow the use of websockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/socket.my_domain.com-error.log error;
error_page 404 /index.php;
location ~ .php$ {
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ /.(?!well-known).* {
deny all;
}
}
# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/socket.my_domain.com/after/*;
2
Answers
I finally figured it out. These settings below worked for me. Hopefully it saves you some time :)
I decided to use reverse proxy on subdomain approach like described in the docs.
For the subdomain's nginx, the only different thing from a default Laravel nginx config is the
location / {}
. Just copy the nginx config of your Laravel app, change theserver_name
and replace thelocation / {}
and you are good to go.Make sure you run
php artisan websockets:serve
in both instances: in my case - App & Worker server.Make sure you allow port 6001 on your app server
In my case, if I ssh into the server and write
php artisan websockets:serve
, it doesn't show the upcoming messages or connections like it do in local, so be aware of it.Some resources:
Up and running with Laravel Websockets + Laravel Websockets on Forge
https://blog.codecourse.com/laravel-websockets-on-forge/
as per laravel websockets doc
create a subdomain
socket.yourapp.tld
then create a nginx config like thisthen in
broadcasting.php
you need to change thesesame goes for javascript
ref link https://beyondco.de/docs/laravel-websockets/basic-usage/ssl#usage-with-a-reverse-proxy-like-nginx