BrianHollenbach's avatar

Laravel Reverb on Laravel Forge

Has anyone gotten Reverb to function on a Forge deployed application?

I followed the steps in the documentation but the connections are being refused.

Do I need to modify the NGINX config as per the Laravel Reverb documentation? or is it done automatically?

server { ...

location / {
    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://0.0.0.0:8080;
}

...

}

0 likes
30 replies
BrianHollenbach's avatar

@robj trust me it is not. Followed the docs to the letter but still not functioning.

3 likes
Marven's avatar

I was also not able to make it work.

Here is what I have done:

  • Register the ws-subdomain, so ws.xxx.de and point it to my application server (just like the main domain xxx.de does).
  • Make sure that a certificate for both domains is installed in the SSL tab.
  • Prepare my env file as follows:

REVERB_APP_ID=XXX REVERB_APP_KEY=XXX REVERB_APP_SECRET=XXX

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}" VITE_REVERB_HOST="${REVERB_HOST}" VITE_REVERB_PORT="${REVERB_PORT}" VITE_REVERB_SCHEME="${REVERB_SCHEME}"

  • Then hit the "Laravel Reverb" toggle on the "Laravel" panel. It promted the ws subdomain and the port 8080, as seen here https://forge.laravel.com/docs/sites/applications.html#laravel-reverb.

  • I have then checked that the env has beed extended with: REVERB_HOST=ws.xxx.de REVERB_PORT=443 REVERB_SCHEME="https"

  • Lastly I deployed my site so that npm run build makes use of the new port in the env.

But unfortunately, I still receive the following error in the frontend: app-Qkal0qg7.js:12 WebSocket connection to 'wss://ws.xxx.de/app/hwybqtva5n4dru43ayiz?protocol=7&client=js&version=8.4.0-rc2&flash=false' failed

I have also check the servers daemon for the reverb process and it has output the following: INFO Starting server on 0.0.0.0:8080 (ws.xxx.de).

My nginx config was not edited by forge in the process of activating reverb. Should it have been? EDIT: @brianhollenbach I have just received a message from Mohamed: "Forge adds the reverb nginx configuration inside /etc/nginx/forge-conf/site_name/after. It doesn't modify the original Nginx configuration file."

robj's avatar

I thought I'd give it a go too - set up an test which worked locally, create a new DO server and installed the app from Github in a similar process to @marven. Everything seemed to go OK however when trying the app I get: WebSocket connection to 'wss://ws.xxx:8080/app/qwertyasfgqwrteud?protocol=7&client=js&version=8.4.0-rc2&flash=false' failed: WebSocket is closed before the connection is established.

I've tinkered with the .env file trying different ports and schemes but can't get it to work - I feel like it is here in the config that the answer might lie.

@marven, was that Mohamed from Forge that replied to you?

Marven's avatar

@robj Yes "Mohamed at Forge". I guessed this is Mohamed from the Laravel team, but maybe not.

Marven's avatar
Marven
Best Answer
Level 17

It now works for me.

The issue on my end was, that I have opened the main domain and ws-domain in Chrome before I had set up the SSL certificate for the ws-domain.

I could successfully connect to reverb/websockets when using Firefox or Postman.

How to fix the issue with Chrome:

Open the developer tools. Then right-click on the page refresh icon on the top left and choose "empty cache and hard reload"

More ways to troubleshoot:

  • In Forge in your server's demon add the parameter --debug to the reverb:start command
  • Open Postman -> New -> WebSocket and paste in the wss://ws.... URL. Check if there are any erros.

Just to make sure, my .env looks like this:

REVERB_APP_ID=XXX
REVERB_APP_KEY=XXX
REVERB_APP_SECRET=XXX

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"

REVERB_HOST=ws.XXX.de
REVERB_PORT=443
REVERB_SERVER_PORT=8080
REVERB_SCHEME="https"

And under site -> SSL I have a certificate for both domains: XXX.de,ws.XXX.de

Hope that helps!

6 likes
Firemaps's avatar

@Marven Did you have to set up the SSL manually for ws.domain.xx or would a wildcard subdomain work? cannot get it working, thanks everyone for sharing your advice, looking forward to posting a solution

BrianHollenbach's avatar

Okay so I have been trying a few different things but still not functioning.

In postman I get the following: Could not connect to wss://ws.xxxx.xxxx.xxx:8080/app/qwertyqwerrtysad Error: write EPROTO 5388810984:error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE:../../../../src/third_party/boringssl/src/ssl/tls_record.cc:594:SSL alert number 40 5388810984:error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO:../../../../src/third_party/boringssl/src/ssl/handshake.cc:644: Handshake Details Request URL: https://ws.xxxx.xxxx.xxx:8080/app/qwertyqwerrtysad Request Method: GET Request Headers Sec-WebSocket-Version: 13 Sec-WebSocket-Key: xxxxxxxxxxxxxxxx Connection: Upgrade Upgrade: websocket Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Host: ws.xxxx.xxxx.xxx:8080

Also: Could not connect to wss://ws.xxxx.xxxx.xxx/app/qwertyqwerrtysad 21:08:38 Error: Unexpected server response: 502 Handshake Details Request URL: https://ws.xxxx.xxx/app/qwertyqwerrtysad Request Method: GET Status Code: 502 Bad Gateway Request Headers Sec-WebSocket-Version: 13 Sec-WebSocket-Key: xxxxxxxxxxxxxxxx Connection: Upgrade Upgrade: websocket Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Host: ws.xxxx.xxxx.xxx Response Headers Server: nginx Date: Wed, 03 Apr 2024 19:08:38 GMT Content-Type: text/html; charset=utf-8 Content-Length: 150 Connection: keep-alive

I followed the steps that has been kindly provided by @marven but still no luck.

I have an ssl for both dns addresses and this is the env: REVERB_HOST=ws.xxxx.xxxx.xxx REVERB_PORT=443 REVERB_SERVER_PORT=8080 REVERB_SCHEME="https"

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}" VITE_REVERB_HOST="${REVERB_HOST}" VITE_REVERB_PORT="${REVERB_PORT}" VITE_REVERB_SCHEME="${REVERB_SCHEME}"

The level of frustration is so unreal as my local environment is working and just mocking me

BrianHollenbach's avatar

I fixed it.

It was a reverb config setting. I modified this setting in the config/reverb.php file: 'tls' => [ ],

Based on a suggestion from another feed which is wrong.

@marven you rock!

1 like
jcergolj's avatar

For me the solution was instead of

location / {
    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://0.0.0.0:8080;
}

...

I had to change the location to /app like this

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://0.0.0.0:8080;
}

...

and then it worked!

Hours spend to find the issue: ~50 :)

KirGus's avatar

What helped me:

— First, you need to activate Laravel Reverb in the Application tab so that the appropriate configurations appear in the Environment.

— Then switch to SSL and delete the current certificate, because it does not have ws.XXX.com .

— Then go back to the Application tab, turn off, and then turn on Laravel Reverb to change the configurations in the Environment.

— Perform the Deploy Now

— Open the developer tools. Then right-click on the page refresh icon on the top left and choose "Empty cache and hard reload"

2 likes
euducavalheiro's avatar

@KirGus Are you using Livewire as well? I still having problems to make a successfull deploy to Forge after follow this instructions. Maybe can be the cloudflare certificate?

lucasweaver's avatar

I've got it working on Laravel 10 deployed on Forge.

What finally seemed to get it to work was

  • having the valid SSL cert for ws.mydomain.com verified in the Forge UI
  • removing all the reverb related env variables and saving
  • turning off reverb in the Forge UI
  • turning reverb back on in the Forge UI

Some issues I encountered:

  • Make sure you set up the subdomain as an A record and not a CNAME
  • Don't forget to add "BROADCAST_CONNECTION=reverb BROADCAST_DRIVER=reverb" into your production env file

I highly recommend setting up the subdomain and A record, then verifying the SSL cert BEFORE you turn on reverb in the Forge UI. It seemed to handle the nginx and env variables correctly when done in that order.

Rockblings's avatar

I have tried everything above but still doesnt work. it shows that it is connected but it is not broadcasting.

Rockblings's avatar

An chance anyone has a consistent solutions or cause of this issue? i really appreciate it. thanks

szympek's avatar

By combining solutions mentioned above, we have successfully deployed the Reverb server using forge. Hopefully, the following might help someone.

Let's start with clearing up the confusion between REVERB_SERVER_PORT and REVERB_PORT. As clearly stated in the official docs the REVERB_SERVER_PORT sets the local port of the Reverb server while REVERB_PORT is the public port on which the WebSocket clients are supposed to subscribe. We need to do the magic of redirecting the incoming HTTPS requests to the REVERB_SERVER_PORT from the REVERB_PORT.

Here is what we did to make it work:

  1. Created a DNS redirect for ws.example.com to the server IP.
  2. From Forge deleted all the SSL certificates for example.com and added a single cetrificate for both example.com and ws.example.com.
  3. From Forge edited the Nginx config by removing ws.example.com from the server_name line.
  4. Turned on the Reverb server. We set the port to 9898 and host to ws.example.com, you can set it to any valid non-conflicting value you like. REVERB_SERVER_PORT env value is the same as the port value in the dialog.
  5. Now here comes the tricky and undocumented part. Laravel created an Nginx config file for proxying requests from 443 (default REVERB_PORT) to… 443. Maybe it got messed up due to multiple attempts of getting this set up by us but what we want is the HTTPS calls on internet facing port 443 to be redirected to the 9898 port in our instance. We needed to edit the file:
sudo vim /etc/nginx/forge-conf/example.com/after/reverb.conf

You need to provide a sudo password for your server. Use nano if exiting vim is a mystery to you. You should review the config to make sure it reflects your desired setup. Specifically make sure the following values are correct:

  • server_name is set to ws.example.com,
  • ssl_certificate and ssl_certificate_key are set to the correct paths,
  • ports in listen 443 ssl http2 and listen [::]:443 ssl http2 lines are the same as REVERB_PORT, 443 in our case,
  • in the location section the port defined in proxy_pass \h\t\t\p://0.0.0.0:9898 is the same as the REVERB_SERVER_PORT, 9898 in our case.

In our case the last value was set to 443 and we had to set it to 9898 manually.

  1. After storing the changes restarted the Nginx server from the Forge panel or console.
  2. It's also worth of checking if your .env contains values coherent with the rest of your setup: REVERB_SCHEME set to https and other values REVERB_SERVER_PORT, REVERB_PORT, REVERB_HOST set as described above.

Hope that helps.

Rockblings's avatar

@szympek thank you for taking your time to outlines the various steps. i had implemented similar steps. it worked at first then it stopped working. i havent been able to get it to work again. It still works great on my local environment using laravel herd. There are no errors in the console and it shows that it is connected and subscribed to the channel but it does not broadcast to the frontend. I'm using inertiajs react as frontend.

KeithHalsey's avatar

Just in case anyone else is still have problems, one of the things that tripped me up is that whilst npm run dev looks like it's updating if you change a .env file, it needs restarting if you are passing a variable through to vite (i.e. one starting VITE_)

I was having problems getting it working in production with forge and also in development with sail so in case its useful to anyone here is my settings:

javascript

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    wsHost: import.meta.env.VITE_REVERB_HOST || window.location.hostname,
    wsPort: import.meta.env.VITE_REVERB_PORT,
    wssPort: import.meta.env.VITE_REVERB_PORT,
    key: import.meta.env.VITE_REVERB_APP_KEY,
    cluster: import.meta.env.VITE_REVERB_CLUSTER,
    forceTLS: false,
    disableStats: false,
    enabledTransports: ['ws', 'wss'],
});

In sail

.env

REVERB_APP_ID=
REVERB_APP_KEY=
REVERB_APP_SECRET=

REVERB_CLUSTER=mt1
REVERB_SCHEME=http
REVERB_HOST=localhost
REVERB_PORT=8080
REVERB_SERVER_PORT=8080
REVERB_SERVER_HOST=0.0.0.0

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
VITE_REVERB_CLUSTER="${REVERB_CLUSTER}"

added to docker-compose.yml

services:
    laravel:
        build:
            context: ./vendor/laravel/sail/runtimes/8.2
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.2/app
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '${APP_PORT:-80}:80'
            - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
            - '${REVERB_SERVER_PORT:-8080}:8080'
...

In production on forge

.env

REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret

REVERB_CLUSTER=mt1
REVERB_SCHEME="https"
REVERB_HOST=ws.xxx.co.uk
REVERB_PORT=443
REVERB_SERVER_PORT=8080

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
VITE_REVERB_CLUSTER="${REVERB_CLUSTER}"

On forge I also ended up having to spin up a new server and start from scratch as my nginx config file had got so mangled, but once I'd done that I did just click on the reverb button under sites and it worked a dream (eventually)

The amount of time I have spent on this is crazy, but then I really don't know much about ports! Good Luck

1 like
KeithHalsey's avatar

Oh - and I can only get it working on a fresh DO droplet. Anything old just doesn't want to work.

stuartcusack's avatar

For me the problem was that I was trying to use a CloudFlare origin certificate. I tried both the wildcard(*) version and I also tried adding each ws. subdomain separately. It seems that CloudFlare origin certificates just don't work with Laravel Forge's Reverb at the moment.

Using Letsencrypt worked fine, you just might need to generate a fresh certificate to ensure your ws subdomain is covered.

Please or to participate in this conversation.