beyondcode / laravel-websockets

Websockets for Laravel. Done right.
https://beyondco.de/docs/laravel-websockets
MIT License
5.07k stars 613 forks source link

WebSocket connection to 'wss://domain/app/ Error in connection establishment: net::ERR_CONNECTION_REFUSED #651

Closed tingan closed 3 years ago

tingan commented 3 years ago

Hi,

the broadcasting is: 'pusher' => [ 'driver' => 'pusher', 'key' => env('PUSHER_APP_KEY'), 'secret' => env('PUSHER_APP_SECRET'), 'app_id' => env('PUSHER_APP_ID'), 'log' => true, 'options' => [ 'cluster' => env('PUSHER_APP_CLUSTER'), 'useTLS' => false, //'encrypted' => true, 'host' => '127.0.0.1', 'port' => 6001, 'scheme' => 'http', 'curl_options' => [ CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ] ], ], the boostrap.js is window.Echo = new Echo({ broadcaster: 'pusher', key: process.env.MIX_PUSHER_APP_KEY, cluster: process.env.MIX_PUSHER_APP_CLUSTER, wsHost: window.location.hostname, encrypted: false, wsPort: 6001, wssPort: 6001, disableStats: true, forceTLS: false, enabledTransports: ['ws', 'wss'], //disabledTransports: ['sockjs', 'xhr_polling', 'xhr_streaming'], //scheme: process.env.MIX_PUSHER_SCHEME });

even i set forTLS to false and encryption to false, the connection is still wss instead ws (but the site is https instead of http). but i enable TLS and set up the letsencrypt fulchain and privkey( copied to storage folder), it also fails. please help me, i stuck for whole day already. sometimes, the error is failed: Error in connection establishment: net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH . thx.

It seems many users have similar problem, if possible, please provide some example implementation code or gist. thx.

Ghostscypher commented 3 years ago

Can you try removing wss port and also ws from enabled transport and check if that works

tingan commented 3 years ago

Hi It seems that even i set encryption false, useTLS false, it still uses wss instead of ws. maybe it's because i use https in production?

I think the best way is to use nginx reverse proxy. but also didn't get it working. please provide complete documents for this. .g. how nginx configuration is and how bootstrap.js echo part and the broadcasting.php pusher part settings. I google a lots, seems many users stuck with it. it also works fine locally but not in prouction.

https://ma.ttias.be/deploying-laravel-websockets-with-nginx-reverse-proxy-and-supervisord/ , this article introduces a way of nginx reverse proxy. but it miss the broadcasting and boostrap.js echo part setttings.

tingan commented 3 years ago

Hi, I tried your suggestion, there is no error in chrome console, but laravel error: 2021-01-08 09:55:36] production.ERROR: Failed to connect to Pusher. {"userId":3,"exception":"[object] (Illuminate\Broadcasting\BroadcastException(code: 0): Failed to connect to Pusher. at vendor/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php:122)

Ghostscypher commented 3 years ago

I thought you were actually testing it locally if you are using on production, then you can check out this issue #635 and yes use a reverse proxy

tingan commented 3 years ago

hi, i finally get it working after 2 days struggling. I didn't use nginx reverse proxy. i use the laravel websockets serve 6001 with ssl . of letsencrypt . ` broadcasting.php 'options' => [ 'cluster' => env('PUSHER_APP_CLUSTER'), 'useTLS' => true, 'encrypted' => false, 'host' => '127.0.0.1', 'port' => 6001, 'scheme' => 'https', 'curl_options' => [ CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_SSL_VERIFYPEER => 0, ] ],

the bootstrap.js window.Echo = new Echo({ broadcaster: 'pusher', key: process.env.MIX_PUSHER_APP_KEY, cluster: process.env.MIX_PUSHER_APP_CLUSTER, wsHost: process.env.MIX_PUSHER_HOST, //window.location.hostname, wsPort: 6001, wssPort: 6001, disableStats: true, forceTLS: true, enabledTransports: ['ws','wss'], });

` it's important to add wssPort as it serve with wss instead of ws. thanks.

Ghostscypher commented 3 years ago

@tingan I am glad it worked

jameshappykang commented 3 years ago

@tingan I am glad it worked for you. But I still have some problem. Could you show about how to set config/websockets.php. below is my websocket.php please let me know is there anywhere need to be revising. `<?php

use BeyondCode\LaravelWebSockets\Dashboard\Http\Middleware\Authorize;

return [

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

/*
 * 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' => false,
        'enable_statistics' => 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' => "D:/xampp/ssl/ifa/certificate.pem",

    /*
     * Path to local private key file on filesystem in case of separate files for
     * certificate (local_cert) and private key.
     */
    'local_pk' => "D:/xampp/ssl/ifa/private.key",

    /*
     * Passphrase for your local_cert file.
     */
    'passphrase' => null,
],

/*
 * 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,

]; `

tingan commented 3 years ago

my websockets.php is always the same except one trivial difference: 'enable_client_messages' => true,

one key is that i copied the letsenccrypt privkey and public key files from /etc/ original default folder to laravel storage folder.

mahdi4187 commented 3 years ago

check open this port

sirdoro1 commented 3 years ago

@mahdi4187 were you able to make it work? I am having exact same issue.

sirdoro1 commented 3 years ago

I have not been able to get this stuff to work. here is my

broadcasting.php

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

        'ably' => [
            'driver' => 'ably',
            'key' => env('ABLY_KEY'),
        ],

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

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

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

    ],

];

bootstrap.js

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

.env

PUSHER_APP_ID=local
PUSHER_APP_KEY=local
PUSHER_APP_SECRET=local
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_HOST=mydomain.com

MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

LARAVEL_WEBSOCKETS_SSL_LOCAL_CERT="/var/www/html/mydomain.com/storage/fullchain.pem"
LARAVEL_WEBSOCKETS_SSL_LOCAL_PK="/var/www/html/mydomain.com/storage/privkey.pem"

I copied local_cert and local_pk from /etc to my laravel package storage.

Thanks

Ghostscypher commented 3 years ago

@sirdoro1 the best option so far was to use a reverse proxy, I'd highly recommend you try that, this way stripping of SSL certificates can be done by the server. In short run Laravel websockets on localhost, then set up a reverse proxy, either using nginx or apache mod_proxy.

sirdoro1 commented 3 years ago

Thanks @Ghostscypher for replying.

Please do you have any guide on using reverse proxy I am using VPS server

Ghostscypher commented 3 years ago

@sirdoro1 here is an article I wrote a while back, it should hopefully point you in the right directionRunning Laravel Websockets in production https://ghostscypher.medium.com/running-laravel-websockets-in-production-def368a84d56 In case of anything kindly reach out. I'll be happy to help

sirdoro1 commented 3 years ago

@Ghostscypher thanks, I checked out the article but I am still having issues here is my configurations

websockets-default.conf

<VirtualHost _default_:6001>
    ServerName ws.mysub.domain.co.uk  // also used it as "mysub.domain.co.uk"
        ProxyPass "/app/" "ws://127.0.0.1:6000/app/"
        ProxyPass "/apps/" "http://127.0.0.1:6000/apps/"
</VirtualHost>

//Listen 6001 <- when I added this "Listen 6001" it kept giving error that i was not able to restart apache2 until i removed it because I am using centOS.

broadcsting.php

'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
                'host' => 'mysub.domain.co.uk', //also tried '120.0.0.1'
                'cluster' => env('PUSHER_APP_CLUSTER'),
                'useTLS' => true,
                'port' => 6001,
                'scheme' => 'https',
            ],
        ],

boostrap.js

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    wsHost: 'mysub.domain.co.uk', //also tried '120.0.0.1'
    encrypted: false,
    wssPort: 6001,
    disableStats: true,
    forceTLS: false,
    enabledTransports: ['ws','wss'],
    disabledTransports: ['sockjs', 'xhr_polling', 'xhr_streaming']
});

websockets.conf

[program:websockets]
command=sudo php /var/www/html/mysub.domain.co.uk/artisan websockets:serve --host 127.0.0.1 --port 6000
numprocs=1
autostart=true
autorestart=true
user=root
redirect_stderr=true
stdout_logfile=/var/www/html/mysub.domain.co.uk/storage/logs/websockets.log

supervisor command is working fine

but still having the following errors from browsers Firefox : The connection to wss://mysub.domain.co.uk:6001/app/local?protocol=7&client=js&version=7.0.3&flash=false was interrupted while the page was loading.

Chrome: app.js:2 WebSocket connection to 'wss://mysub.domain.co.uk:6001/app/local?protocol=7&client=js&version=7.0.3&flash=false' failed:

Thanks for your time.

Ghostscypher commented 3 years ago

I believe @sirdoro the error is because mod proxy has been disabled. I'd your proxy module enabled? What error do you get when you try to run apache2? Kindly paste it here journalctl -xe

sirdoro1 commented 3 years ago

[root@localhost ~]# systemctl status httpd.service ● httpd.service - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled) Active: failed (Result: exit-code) since Thu 2021-04-15 05:58:42 BST; 1min 21s ago Docs: man:httpd(8) man:apachectl(8) Process: 31615 ExecStop=/bin/kill -WINCH ${MAINPID} (code=exited, status=0/SUCCESS) Process: 31620 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND (code=exited, status=1/FAILURE) Main PID: 31620 (code=exited, status=1/FAILURE)

Apr 15 05:58:41 localhost.localdomain httpd[31620]: AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using localhost.localdomain. Set the...his message Apr 15 05:58:41 localhost.localdomain httpd[31620]: (13)Permission denied: AH00072: make_sock: could not bind to address [::]:6001 Apr 15 05:58:41 localhost.localdomain httpd[31620]: (13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:6001 Apr 15 05:58:41 localhost.localdomain httpd[31620]: no listening sockets available, shutting down Apr 15 05:58:41 localhost.localdomain httpd[31620]: AH00015: Unable to open logs Apr 15 05:58:42 localhost.localdomain systemd[1]: httpd.service: main process exited, code=exited, status=1/FAILURE Apr 15 05:58:42 localhost.localdomain systemd[1]: Failed to start The Apache HTTP Server. Apr 15 05:58:42 localhost.localdomain systemd[1]: Unit httpd.service entered failed state. Apr 15 05:58:42 localhost.localdomain systemd[1]: httpd.service failed. Hint: Some lines were ellipsized, use -l to show in full.

if the websockets.conf is with Listen 6001 and restarting apache 'service apache2 restart' comes with error
Redirecting to /bin/systemctl restart apache2.service Failed to restart apache2.service: Unit not found.

Listen 6001

<VirtualHost _default_:6001>
    ServerName ws.asifor.nshub.co.uk
    ProxyPass "/app/" "ws://127.0.0.1:6000/app/"
    ProxyPass "/apps/" "http://127.0.0.1:6000/apps/"
</VirtualHost>

but if it is configured as

<VirtualHost _default_:6001>
    ServerName ws.asifor.nshub.co.uk
    ProxyPass "/app/" "ws://127.0.0.1:6000/app/"
    ProxyPass "/apps/" "http://127.0.0.1:6000/apps/"
</VirtualHost>

the apache restarts properly but the websockets still wont work.

Ghostscypher commented 3 years ago

Nice some progress, let's do one more test

  1. Make sure that apache2 is running the websockets netstat -tulpn | grep 6001
  2. Make sure that you allow TCP traffic through firewall on port 6001 (very important) Depending on the OS you are using, google your OS firewall command, might probably use iptables or firewallcmd
Ghostscypher commented 3 years ago

As I can see also you are using httpd not apache2 so your command to restart the service will probably be systemctl restart httpd or service httpd restart Also fix the pusher config as shown below

'pusher' => [
            'driver' => 'pusher',
            'key' => env('PUSHER_APP_KEY'),
            'secret' => env('PUSHER_APP_SECRET'),
            'app_id' => env('PUSHER_APP_ID'),
            'options' => [
                'host' => 'mysub.domain.co.uk', //also tried '120.0.0.1'
                'cluster' => env('PUSHER_APP_CLUSTER'),
                'useTLS' => false, // changed to this
                'port' => 6001,
                'scheme' => 'http', // changed
            ],
        ],

If you are using http then your configuration should reference http, no TLS, encryption is false, on the other hand if you are using an SSL certificate change your config to reflect this changes. For now we can try to make it work with no SSL cert first, though I'd encourage you to consider using an SSL certificate later.

sirdoro1 commented 3 years ago

I have been able to make Listen on port 8443

Listen 8443
<VirtualHost _default_:8443>
    ServerName ws.asifor.nshub.co.uk
        ProxyPass "/app/" "ws://127.0.0.1:6000/app/"
        ProxyPass "/apps/" "http://127.0.0.1:6000/apps/"
</VirtualHost>

and I changed the port accordingly on bootstrap.js and broadcasting.php

Ghostscypher commented 3 years ago

@sirdoro1 Nice, now we check

  1. Is the server running on that port
  2. Have you exposed that port to outside world since by default it is usually blocked from traffic to check this simply try to browse https://[your domain]:8443
sirdoro1 commented 3 years ago

I have check the port tcp LISTEN 0 128 [::]:8443 [::]:*

Tried this in my browser https://asifor.nshub.co.uk:8443/ and I got This site can’t be reached asifor.nshub.co.uk took too long to respond.

Ghostscypher commented 3 years ago

@sirdoro1 after you are done as a security precaution, kindly strip your log above except for the apache2 error, update all reference of your domain to some generic name such as mydomain.com this is to protect yourself and your domain identity. I'll do so on my end, after you've solved your issues on your end. Trust me it works, I use it myself.

sirdoro1 commented 3 years ago

Thanks @Ghostscypher. I still couldnt get it to work.

Ghostscypher commented 3 years ago

Thanks @Ghostscypher. I still couldnt get it to work.

@sirdoro1 hey can you contact me on bngetich69@gmail.com I believe I'll be able to be of help from there.

egbavou commented 2 years ago

Hello everyone I hope you are well. I have the same error to make the websocket work with ssl. Nothing I've read here helps.

Reof07 commented 2 years ago

hola.. tengo el siguiente problema

app.js:22846 WebSocket connection to 'wss://127.0.0.1:6001/app/5ad9d002d6375a1bd08b?protocol=7&client=js&version=7.4.0&flash=false' failed: WebSocket is closed before the connection is established.