Laravel-websockets: WebSocket connection to 'wss://mydomain:6001/app/1234567890?protocol=7&client=js&version=5.0.2&flash=false' failed: Error in connection establishment: net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH

Created on 7 Nov 2019  路  37Comments  路  Source: beyondcode/laravel-websockets

I'm getting this error. Its killing my time. I dig deep and found no proper solution for this issue. in LOCAL SERVER its working fine *. but in *LIVE SERVER this issue arises.

I put 'local_pk' and 'local_cert' both path inside websockets.php file

its my app.js file

window.Echo = new Echo({
broadcaster: 'pusher',
key: '1234567890',
wsHost: window.location.hostname,
wsPort: 6001,
encrypted: false,
wssPort: 6001,
disableStats: true,
enabledTransports: ['ws', 'wss'],
});

here is my broadcasing.hp config

'connections' => [

    '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'),
            'host' => '127.0.0.1',
            'encrypted' => false,
            'port' => 6001,
            'scheme' => 'https',
            'curl_options' => [
                CURLOPT_SSL_VERIFYHOST => 0,
                CURLOPT_SSL_VERIFYPEER => 0,
            ]
        ],
    ],

PLEASE HELP ME OUT.

Most helpful comment

Hey Guys, i just solved the same problem by running websockets with sudo:
sudo php artisan websockets:serve

this solved my problem!
Thanks
@fahim152

All 37 comments

Same issue, tried several variations of config. Seems broken on newest Valet/Laravel? It's working fine with the exact same config on 1.1 and Laravel 5.8

@fahim152 I solved this in my ENV by providing both of my Valet certificates exact paths. Previously, I had them aliased to user path using ~/. If this is your case, you'll need to provide with exact paths.

okay thanks. I'm using my vps server and lets encrypt as ssl. I did provide private key and full chain key path on websockets.php , Not worked that time. gotta try again. Hope it will solve the issue

I'm using LetsEncrypt as well on my staging server. Are you using a PEM or CRT/KEY files? Let me know if it works for you.

I'm using LetsEncrypt as well on my staging server. Are you using a PEM or CRT/KEY files? Let me know if it works for you.

Hi I'm using like this into my laravel .env file:
LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT=/etc/letsencrypt/live/app.socialhub.pro/fullchain.pem
LARAVEL_WEBSOCKETS_SSL_LOCAL_PK=/etc/letsencrypt/live/app.socialhub.pro/privkey.pem

but I got the same erro :( Plase helpme if you can :)

With Laravel Forge, I plugged in both the crt and key files generated from LetsEncrypt. I am not working with the pem keys although I believe the documentation says you can.

Do you have the crt and key files? Maybe give those a try?

With Laravel Forge, I plugged in both the crt and key files generated from LetsEncrypt. I am not working with the pem keys although I believe the documentation says you can.

Do you have the crt and key files? Maybe give those a try?

I convert my cert.pem to .crt and my key.pem to .key. I'm trying to make work now...

Thanks for the quick answer :)

Nothing work with https :( only work with http!

I tried almost all combinations:
//// My .vue component on start
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
wsHost: process.env.MIX_APP_HOST,
// wsHost: window.location.hostname,
wsPort: 6001,
wssPort: 6001,
// enabledTransports: ['ws'],
enabledTransports: ['ws', 'wss'],
// encrypted: true,
encrypted: false,
disableStats: false
});

///// config/broadcasting.php
        'options' => [
            'cluster' => env('PUSHER_APP_CLUSTER'),
            // 'encrypted' => true,
            // 'scheme' => 'https',       
            'useTLS' => false,
            'encrypted' => false,
            'host' => env('APP_HOST'),
            'port' => 6001,
            'scheme' => 'http',       

            'curl_options' => [
                CURLOPT_SSL_VERIFYHOST => 0,
                CURLOPT_SSL_VERIFYPEER => 0,
            ]         
        ],

 ///// config/websockets.php
'ssl' => [

    'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),

    'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),

    // 'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),
    'passphrase' => null,

    'verify_peer' => false,
],

Clear all laravel cache, npm run dev, composer dump-autoload -o, clear navigator cache, restart supervisor and websockets, and I still having websocket with https erros like:

WebSocket connection to 'wss://[MYDOMINE]:6001/app/NNN?protocol=7&client=js&version=5.0.3&flash=false' failed: WebSocket is closed before the connection is established.

@fahim152 , I had the same issue as yours. I am also using a vps server, and positive ssl. I ended up switching from https to http and I added this code to my .htaccess file to point to http as so

RewriteCond %{HTTPS} on
RewriteRule (.*) http://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

And it works!

I am thinking it has to do with the ssl. Each time, I switch to https I get an error similar to yours:- " Firefox can't establish a connection to the server at wss://mydomain/app/1234567890?protocol=7&client=js&version5.0.3&flash=false. "
" The connection at wss://mydomain/app/1234567890?protocol=7&client=js&version5.0.3&flash=false was interrupted while page was loading".

I am still investigating, if i find the solution, i will update it here.

@UchennaPrudensia unfortunately your soluction not use https, like mine :(
I'm still facing this problem whitout success... http work perfect, https not, i'm thinking buy another sertificate files... I'm using certificates from "letsencrypt", and its are free, I do not know if it make sence...

thanks

Hey Guys, i just solved the same problem by running websockets with sudo:
sudo php artisan websockets:serve

this solved my problem!
Thanks
@fahim152

I am having the same issue : failed: Error in connection establishment: net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH

// broadcast.php setting
'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'),
'host' => '127.0.0.1',
'port' => 6001,
'scheme' => 'https',
'curl_options' => [
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_SSL_VERIFYPEER => 0,
]
],
],

// echo settings
import Echo from "laravel-echo";

window.Pusher = require('pusher-js');

window.Echo = new Echo({
broadcaster: 'pusher',
key: 'myKey',
wsHost: window.location.hostname,
wsPort: 6001,
wssPort: 6001,
encrypted: true,
disableStats: true,
enabledTransports: ['ws', 'wss'],
});

ssl configured with signed certificate according to the documentation but still facing this issue

@AyazTechloyce try running websockets with sudo like this:

sudo php artisan websockets:serve

this solved my problem

The reason sudo works is because there is a permissions problem on the cert files for the web service user. You can copy the key and cert (or change the current permissions) to an accessible location and it will work fine for the web user to run the artisan command. If you are using letsencrypt or certbot or something to renew your certs that will be a continual problem I think. It also seems a bit insecure to allow the web user access to the the key file if you got compromised. So not really a production solution like reverse-proxy through nginx would be. For the live server I found it better to set up the websocket as http and let nginx handle the ssl encryption.

@joshcalloway can you make laravel-websockets work on port 80 instead of 6001 ? I have tried all configurations possible, this is my current nginx config:

server {
    root /var/www/html/websockets-domain/public;
    index index.html index.htm index.php;
    server_name ws-test.domain.com;

    location / {
        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_pass http://127.0.0.1:6001/;
        add_header X-location websocket always;
    }

    location /laravel-websockets {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
       include snippets/fastcgi-php.conf;
       fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/ws-test.domain.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/ws-test.domain.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

I tried variants with: location /app/ { ...
but it keeps giving me a 502 error.
I don't know how to make it work. :(

I think you probably could. I followed the directions at https://docs.beyondco.de/laravel-websockets/1.0/basic-usage/ssl.html#usage-with-a-reverse-proxy-like-nginx to make it work over 443 but it seems like it would just as easy to proxy 80 instead. Here is a copy of my config running on a subdomain

`server {
listen 443 ssl http2;
listen [::]:443 ssl http2;

server_name {{ dev_socket_domain }};
set $base {{ dev_site_path }};
root $base/current/public;

# SSL
ssl_certificate /etc/letsencrypt/live/{{ dev_socket_domain }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ dev_socket_domain }}/privkey.pem;

# Logging
access_log /var/log/nginx/{{ dev_socket_domain }}.access.log;
error_log /var/log/nginx/{{ dev_socket_domain }}.error.log warn;

# Fallback
location / {
proxy_pass http://127.0.0.1:6001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto  https;
proxy_set_header X-VerifiedViaNginx yes;
proxy_read_timeout                  60;
proxy_connect_timeout               60;
proxy_redirect                      off;

# Specific for websockets: force the use of HTTP/1.1 and set the Upgrade header
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;

}

# General Config
include includes/general.conf;
}`

@joshcalloway thanks for the help, but it didnt work. I keep getting this error:
Error during WebSocket handshake: Unexpected response code: 502

event on por 80 if i disable ssl the error persists.

If I try to connect directly on port 6001, it works fine.

The problem is the .pem certificates. I had the same problem with the .pem certificates, installed new .crt and .key and it worked properly.

I don't thing so, cause I have now working a .pem and a .key file:
'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', '/etc/letsencrypt/live/app.socialhub.pro/fullchain.pem'),

    'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', '/etc/letsencrypt/live/app.socialhub.pro/privkey.key'),

but my .pem is now a fullchain certificate, it mean it have two certificates in the same file!

Hope it help, because I spend precious time to get it working

Had a similar issue. Invested almost half a day and finally what worked?

[ I am using Letsencrypt > and https. FYI ]

as @ricardoperovano suggested,
sudo php artisan websockets:serve

Did the trick for me. Thanks mate.

Cheers

I get the same error. I found that if I symlinked to the certificate files or used the path directly, regardless of permissions, it would give the error. I got it to work by just copying fullchain.pem and privkey.pem to my config folder, changing user to www-data with 755 permission, it was able to work.

The only drawback I forsee is whenever the certificates are renewed, the files must be recopied. I can live with automating this in a script than mess with permissions and access in /etc.

export var echo_instance = new Echo({
//namespace: 'App.Events',
broadcaster: "pusher",
key: process.env.MIX_PUSHER_APP_KEY,
wsHost: window.location.hostname,
wsPort: 6001,
encrypted: false,
disableStats: true,
});

I get this error and i'm not even using wss. Get no errors on the laravel-websockets dashboard but once i go to another route this pops up and disconnects me.

export var echo_instance = new Echo({
//namespace: 'App.Events',
broadcaster: "pusher",
key: process.env.MIX_PUSHER_APP_KEY,
wsHost: window.location.hostname,
wsPort: 6001,
encrypted: false,
disableStats: true,
});

I get this error and i'm not even using wss. Get no errors on the laravel-websockets dashboard but once i go to another route this pops up and disconnects me.

you are still on local ? use forceTLS: false, and on broadcasting.js 'useTLS' => false,

Make sure the user you are running php artisan websockets:serve as can read both your key and certificate files on the server. If those files are scoped to root, you'll have to run the websockets:serve command as sudo.

I was also having the same issue after many try finally problem solved @senzlord your solution worked for me on local

please follow this comment and you will get successful solution
to upload websockets laravel project with beyondcode/laravel-websockets with https

1 - in bootstrap.js file
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'yourkey',
wsHost: window.location.hostname,
wsPort: 6001,
wssPort: 6001,
disableStats: true,

});
2 - in broadcasting.php

'options' => [

           'cluster' => env('PUSHER_APP_CLUSTER'),

              'encrypted' => true,

             'host' => 'domain.com',

             'port' => 6001,

            'scheme' => 'https'

            ]

3 - create ssl by let's encrypt
- sudo wget https://dl.eff.org/certbot-auto -O /usr/sbin/certbot-auto
- sudo chmod a+x /usr/sbin/certbot-auto
- sudo certbot-auto certonly --standalone -d example.com -d www.example.com
note change exampe text with your domain
if you got error after last command "Problem binding to port 80: Could not bind to IPv4 or IPv6"
this mean you must stop apache serve by this command "service httpd stop"
and repeat last command "sudo certbot-auto certonly --standalone -d example.com -d www.example.com"
and after this start httpd service again by " service httpd start"
4 - in websockets.php
'local_cert' => '/etc/letsencrypt/live/yourdomain/fullchain.pem',

'local_pk' => '/etc/letsencrypt/live/yourdomain/privkey.pem',
'verify_peer' => false,
5 - now all done and need to run php artisan websockets:server but work with ssl should run it with sudo

Hey Guys, i just solved the same problem by running websockets with sudo:
sudo php artisan websockets:serve

this solved my problem!
Thanks
@fahim152

thank you,
just run this
1_ php artisan websockets:serve
2_php aertisan serve

sloved .

Make sure the key and certificate do have permissions set to allow reading.

sudo php artisan websockets:serve

@ricardoperovano your solution works because letsencrypt certificate file doesn't have permission other than root. That may be causing the issue.

have anyone found a good solution for this issue?

im facing the same problem on live server
on local everything is good..

i used all the comments here..
im using ssl, running the command with sudo, nothing seems to fix it

This sometimes means that maybe the SSL cert permissions aren't correct. Do a chown $USER:$USER /etc/nginx/myssl.crt and /etc/nginx/myssl.key and it should fix the error.

At least it did for my specific case.

have anyone found a good solution for this issue?

im facing the same problem on live server
on local everything is good..

i used all the comments here..
im using ssl, running the command with sudo, nothing seems to fix it

I concur, no amount of permissions editing fixes this in my case, whether setting the cert permission to the user or root or running as root or the user, in various combinations, doesn't work. Have to disable verify peer

This worked for me

broadcasting.php
`
return [

/*
|--------------------------------------------------------------------------
| Default Broadcaster
|--------------------------------------------------------------------------
|
| This option controls the default broadcaster that will be used by the
| framework when an event needs to be broadcast. You may set this to
| any of the connections defined in the "connections" array below.
|
| Supported: "pusher", "redis", "log", "null"
|
*/

'default' => env('BROADCAST_DRIVER', 'null'),

/*
|--------------------------------------------------------------------------
| Broadcast Connections
|--------------------------------------------------------------------------
|
| Here you may define all of the broadcast connections that will be used
| to broadcast events to other systems or over websockets. Samples of
| each available type of connection are provided inside this array.
|
*/

'connections' => [

    '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' => '127.0.0.1',
            'port' => 8443,
            'scheme' => 'https',
            'curl_options' => [
                CURLOPT_SSL_VERIFYHOST => 0,
                CURLOPT_SSL_VERIFYPEER => 0,
            ]
        ],
    ],

    'redis' => [
        'driver' => 'redis',
        'connection' => 'default',
    ],

    'log' => [
        'driver' => 'log',
    ],

    'null' => [
        'driver' => 'null',
    ],

],

];
`

websockets.php
`
return [

/*
 * Set a custom dashboard configuration
 */
'dashboard' => [
    'port' => env('LARAVEL_WEBSOCKETS_PORT', 8443),
],

/*
 * This package comes with multi tenancy out of the box. Here you can
 * configure the different apps that can use the webSockets server.
 *
 * Optionally you specify capacity so you can limit the maximum
 * concurrent connections for a specific app.
 *
 * Optionally you can disable client events so clients cannot send
 * messages to each other via the webSockets.
 */
'apps' => [
    [
        'id' => env('PUSHER_APP_ID'),
        'name' => env('APP_NAME'),
        'key' => env('PUSHER_APP_KEY'),
        'secret' => env('PUSHER_APP_SECRET'),
        'path' => env('PUSHER_APP_PATH'),
        'capacity' => null,
        'enable_client_messages' => true,
        'enable_statistics' => true,
        'encrypted' => true,
    ],
],

/*
 * This class is responsible for finding the apps. The default provider
 * will use the apps defined in this config file.
 *
 * You can create a custom provider by implementing the
 * `AppProvider` interface.
 */
'app_provider' => BeyondCode\LaravelWebSockets\Apps\ConfigAppProvider::class,

/*
 * This array contains the hosts of which you want to allow incoming requests.
 * Leave this empty if you want to accept requests from all hosts.
 */
'allowed_origins' => [
    //
],

/*
 * The maximum request size in kilobytes that is allowed for an incoming WebSocket request.
 */
'max_request_size_in_kb' => 250,

/*
 * This path will be used to register the necessary routes for the package.
 */
'path' => 'laravel-websockets',

/*
 * Dashboard Routes Middleware
 *
 * These middleware will be assigned to every dashboard route, giving you
 * the chance to add your own middleware to this list or change any of
 * the existing middleware. Or, you can simply stick with this list.
 */
'middleware' => [
    'web',
    Authorize::class,
],

'statistics' => [
    /*
     * This model will be used to store the statistics of the WebSocketsServer.
     * The only requirement is that the model should extend
     * `WebSocketsStatisticsEntry` provided by this package.
     */
    'model' => \BeyondCode\LaravelWebSockets\Statistics\Models\WebSocketsStatisticsEntry::class,

    /**
     * The Statistics Logger will, by default, handle the incoming statistics, store them
     * and then release them into the database on each interval defined below.
     */
    'logger' => BeyondCode\LaravelWebSockets\Statistics\Logger\HttpStatisticsLogger::class,

    /*
     * Here you can specify the interval in seconds at which statistics should be logged.
     */
    'interval_in_seconds' => 60,

    /*
     * When the clean-command is executed, all recorded statistics older than
     * the number of days specified here will be deleted.
     */
    'delete_statistics_older_than_days' => 60,

    /*
     * Use an DNS resolver to make the requests to the statistics logger
     * default is to resolve everything to 127.0.0.1.
     */
    'perform_dns_lookup' => false,
],

/*
 * Define the optional SSL context for your WebSocket connections.
 * You can see all available options at: http://php.net/manual/en/context.ssl.php
 */
'ssl' => [
    /*
     * Path to local certificate file on filesystem. It must be a PEM encoded file which
     * contains your certificate and private key. It can optionally contain the
     * certificate chain of issuers. The private key also may be contained
     * in a separate file specified by local_pk.
     */
    'local_cert' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT', null),

    /*
     * Path to local private key file on filesystem in case of separate files for
     * certificate (local_cert) and private key.
     */
    'local_pk' => env('LARAVEL_WEBSOCKETS_SSL_LOCAL_PK', null),

    /*
     * Passphrase for your local_cert file.
     */
    'passphrase' => env('LARAVEL_WEBSOCKETS_SSL_PASSPHRASE', null),

    'verify_peer' => false,

    'allow_self_signed' => true,
],

/*
 * Channel Manager
 * This class handles how channel persistence is handled.
 * By default, persistence is stored in an array by the running webserver.
 * The only requirement is that the class should implement
 * `ChannelManager` interface provided by this package.
 */
'channel_manager' => \BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManagers\ArrayChannelManager::class,

];

`

bootstrap.js

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    encrypted: true,
    wsHost: window.location.hostname,
    wsPort: 8443,
    wssPort: 8443,
    forceTLS: true,
    disableStats: false,
    enabledTransports: ['ws', 'wss']
});

.env

BROADCAST_DRIVER=pusher
APP_URL_BASE=DOMAIN_NAME_HERE
APP_URL=https://${APP_URL_BASE}
LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT=/etc/letsencrypt/live/DIR_NAME_HERE/fullchain.pem
LARAVEL_WEBSOCKETS_SSL_LOCAL_PK=/etc/letsencrypt/live/DIR_NAME_HERE/privkey.pem

/etc/supervisorctl/conf.d/websockets.conf

[program:websockets]
process_name=%(program_name)s
command=sudo php artisan websockets:serve --port=8443
directory=/var/www/html/PROJECT_NAME_HERE
autostart=true
autorestart=true
user=root
redirect_stderr=true
stdout_logfile=/var/www/html/PROJECT_NAME_HERE/storage/logs/websockets.log

Hello,

I think it's a bad idea to execute code from the root user for security reasons.

You can use my way to avoid that, described there: https://github.com/beyondcode/laravel-websockets/issues/480#issuecomment-686412248

Basically:

  • create a websockets user
  • copy ssl cert & pk to another folder
  • make those files readable by the websockets user
  • configure supervisor to launch the queue with the websockets user

This guide worked well for me: https://alex.bouma.dev/posts/installing-laravel-websockets-on-forge/

This is Forge specific, but there is enough guidance in there to figure out what you have to do.

One important note: When using a cloud service like Google Cloud, make sure the port is open for the server in your cloud console as well.

I have tried everything mentioned in this thread. The websocket works fine with HTTP but after installing the free SSL certificate from AWS certificate manager on AWS EC2 it is not working.

I am not sure the path of the certificate that we have to mention in the .env file as there are no documents or reference on the internet abotu the path of the AWS free SSL certificate installed.

Can anyone suggest which path I have to set in .env file? I am talking about the following variable in .env file.

LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT
LARAVEL_WEBSOCKETS_SSL_LOCAL_PK

Thank you.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

myckhel picture myckhel  路  3Comments

fridzema picture fridzema  路  4Comments

connecteev picture connecteev  路  3Comments

NIkita-Kim picture NIkita-Kim  路  4Comments

stefandanaita picture stefandanaita  路  4Comments