Closed eldair closed 5 years ago
I have the same situation. I got it working on local with my self signed certs from valet, but can't get it working on my forge server. I also tried to open port 6001 on the forge firewall setup, but: "WebSocket connection to 'wss://xxx:6001/app/a8f4975fa8b8dd5da1ca?protocol=7&client=js&version=4.3.1&flash=false' failed: WebSocket opening handshake timed out"
Disclosure, I am a RunCloud owner. Since I saw this package, we have modified our nginx config to allow a user to add their own proxy setting. In this case, Let's Encrypt will work on port 443 which proxying port 6001. I think you can suggest forge to allow this kind of modification.
Hey @Eldair and @sudden-break
I'm still trying to get things working locally (windows + homestead). I got a similar error as you guys. So I tried to connect to my local homestead server on port 6001 using telnet. This didn't work. However, if I run the sockets server on my "external" ip address I am able to connect:
artisan websockets:serve --host=192.168.10.10
I am getting other errors now, but that's inside php code, so getting closer... Also, I don't know the implications of running it this way since I'm not a server specialist. So I'll have to read up on server stuff I guess :-)
I think that the easiest solution would be to replace forge's current let's encrypt system with certbot, which would let us have a permanent cert. path instead of the current (ever changing) one.
I think the easiest method is to add a new host to forge (socket.yourdomain.tld for example) which has it's own cert and add the nginx rules to it to proxy the traffic from your server running on port 6001 (plain, no https) and let nginx do all the https stuff: https://docs.beyondco.de/laravel-websockets/1.0/basic-usage/ssl.html#usage-with-a-reverse-proxy-like-nginx
The webroot for this webhost can be empty since you will be replacing it with a reverse proxy config (serving the websockets server) instead of serving content from the webroot, it also does not have to point to your apps webroot.
Replae the location /
in the Forge nginx config for that new domain/subdomain with (assuming you are running the websocket server on port 6001 which should be the default):
location / {
proxy_pass http://127.0.0.1:6001;
proxy_set_header Host $host;
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;
}
This way Forge can manage the certificate itself and you don't have to worry about it 👍 (and also don't have to open any special ports on the server).
Your app can use 127.0.0.1:6001 to connect (plain, no https) to the server to submit it's broadcasts (throught the HTTP API) and your app can use socket.yourdomain.tld:443 (with ssl) from Pusher.JS/Laravel Echo.
Hello,
One question: how can I test I'have configured Reverse Proxy ok? For example with following config:
$ cat /etc/nginx/sites-enabled/00_socket.scool.cat
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name socket.scool.cat;
# Start the SSL configurations
# ssl on;
ssl_certificate /etc/nginx/ssl/scool.cat/412609/server.crt;
ssl_certificate_key /etc/nginx/ssl/scool.cat/412609/server.key;
location / {
proxy_pass http://127.0.0.1:6001;
proxy_set_header Host $host;
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;
}
}
If i visit:
thows my a 502 Bad Gateway error.
@stayallive thank you for your explanation.. but honestly my head is spinning trying to wrap my head around all this! I think your solution seems the best and cleanest.. but can you please see if I understand correctly
currently on my dev, using laravel valet with the --secure flag
I have 3 apps
all 3 sites were https through Valet and it works great
now I tried to move all of this to my forge server and I can't connect. I realized the websocket ssl config was still pointing to my dev's .crt/.key so that was surely problem #1, and problem #2 is that I probably need to open up port 6001 first
But then I came here and saw your solution and it seems great since I may not have to do either of those things above.. worry about certs and open up a port
I already set up my 3 subdomains and made them all https through letsencrypt
Now is it my understanding that you're suggesting I set up a 4th subdomain, http only, and use the nginx block you provided to proxy to my internal port 6001 ?
Does this 4th domain need to be https with let's encrypt?
And then inside my socket.tld websocket's config I can leave the ssl config blank ?
And then in my vue-frontend I would set the host to https of this 4th domain?
This way all my domains are still https, and I can access my debug dashboard on the socket.tld, but the websocket config itself is not "SSL" thanks to the proxy trick?
@vesper8 you're almost there. The socket.tld.dev app you have should be it's own subdomain (with https) with that nginx block I mentioned earlier.
You will also need to run the php artisan websockets:serve
command in Supervisor using the Daemons tab on your Forge server dashboard.
This way the websockets server runs on 127.0.0.1:6001 on your Forge box (do not configure SSL in your websockets.php file for the sockets server).
Then any app on your server (a server side app) can talk to your websockets server on http://127.0.0.1:6001 (no https) or socket.tld.dev:443 (with ssl). The internal non-http path will be slightly faster since it doesn not go via the internet but only local network.
Your front-end clients should connect to socket.tld.dev:443 (with http).
That should be it 👍
A reverse proxy... proxies traffic, you might already guessed that but a default https host listens on port 443 and what that proxy_pass http://127.0.0.1:6001;
does in the nginx config is pass any traffic on to http://127.0.0.1:6001
which is your local php artisan websockets:serve
. So nginx handles the SSL/TLS stuff and passes un-encrypted content through to your websockets server which handles the connections. This way port 6001 does not need to be exposed and your websockets server does not have to handle the SSL/TLS handshakes itself.
Hope this makes more sense now for everyone 👍
@acacha if your are getting a 502 the proxy_pass
failed. Make sure you have the php artisan websockets:serve
running and it's running on 127.0.0.1 and port 6001. The config looks fine at a glance.
@stayallive no matter if php artisan websockets:serve is executed or no the 502 bad gateway error persists...
Let's suppose my Nginx proxy config is correct so maybe it's a package configuration error:
$ cat /home/forge/scool.cat/config/websockets.php
<?php
use App\LaravelWebSockets\ConfigAppProvider;
return [
/*
* 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 can disable client events so clients cannot send
* messages to each other via the webSockets.
*/
// IMPORTANT SEE NEXT VARIABLE -> We use custom ConfigAppProvider.
'apps' => [],
/*
* 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' => 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',
'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,
/*
* 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,
],
/*
* 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('WEBSOCKETS_LOCAL_CERT','/home/sergi/.valet/Certificates/scool.test.crt'),
/*
* Path to local private key file on filesystem in case of separate files for
* certificate (local_cert) and private key.
*/
'local_pk' => env('WEBSOCKETS_LOCAL_PK','/home/sergi/.valet/Certificates/scool.test.key'),
/*
* Passphrase for your local_cert file.
*/
'passphrase' => null,
'verify_peer' => env('WEBSOCKETS_VERIFY_PEER',false),
],
];
It coulb be really useful to see a complete working configuration....
Current Envirnment values:
$ php artisan tinker
Psy Shell v0.9.9 (PHP 7.2.13-1+ubuntu18.04.1+deb.sury.org+1 — cli) by Justin Hileman
>>> env('WEBSOCKETS_LOCAL_CERT')
=> "/etc/nginx/ssl/scool.cat/412609/server.crt"
>>> env('WEBSOCKETS_LOCAL_PK')
=> "/etc/nginx/ssl/scool.cat/412609/server.key"
>>> env('WEBSOCKETS_VERIFY_PEER')
=> true
So using current SSL certificates for Laravel Forge site.
An any errors when running:
$ /usr/bin/php /home/forge/scool.cat/artisan websockets:serve --verbose
Starting the WebSocket server on port 6001...
Again, you should not add the certificate in websockets.php 👍
Let nginx handle the SSL, run the websockets server as a plain one.
You are doing a proxy_pass http://127.0.0.1:6001;
but that will fail if your websockets server expects a https connection.
Oh thanks I'm sure I've tried this combination but not at least no more 502 gateway errors now. Thanks! Let met try it in deep and If it works i will try to put here my full config for anybody like me with similar problems.
Working on it but now I have a 504 timeout error instead of 502 Bad gateway:
curl https://socket.scool.cat/
<html>
<head><title>504 Gateway Time-out</title></head>
<body>
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx/1.15.6</center>
</body>
</html>
Also not working with Laravel Echo:
Laravel Echo config:
window.Echo = new Echo({
broadcaster: 'pusher',
key: '6f627646afb1261d5b50',
wsHost: 'socket.scool.cat',
disablestats: true,
encrypted: true
})
Chrome Console error:
app.js:38721 WebSocket connection to 'wss://socket.scool.cat/app/6f627646afb1261d5b50?protocol=7&client=js&version=4.3.1&flash=false' failed: WebSocket is closed before the connection is established.
Sorry 504 Gateway error solved:
Changed in /etc/nginx/sites-available/00_socket.scool.cat:
location / {
proxy_pass https://127.0.0.1:6001;
....
to http://127.0.0.1:6001; (without s)
@stayallive thank you very much for your help! I have it all working perfectly now using your solution!
I did end up creating a 4th subdomain for the proxy pass, because the socket.tld domain still needs to be accessible for the sole purpose of accessing the debug dashboard
@vesper8 ah yeah, ofcourse! Happy you got it working 🤘
Hello!
I seem to be having trouble with the same thing. I am trying to setup the reverse proxy as explained in these posts, and am getting a 502 error. I have created another Site in Forge, with the domain socket.domain.tld and this is the nginx config for that site:
include forge-conf/socket.domain.com/before/*;
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name socket.domain.com;
ssl on;
ssl_certificate /etc/nginx/ssl/socket.domain.com/471603/server.crt;
ssl_certificate_key /etc/nginx/ssl/socket.domain.com/471603/server.key;
include forge-conf/socket.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;
}
}
include forge-conf/socket.domain.com/after/*;
In my config/websockets.php file, the local_cert and local_pk are both set to null.
My pusher connection config in config/broadcasting.php looks like this:
'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' => env('WS_HOST', '127.0.0.1'),
'port' => env('WS_PORT', '6001'),
'scheme' => env('WS_SCHEME', 'http'),
'encrypted' => env('WS_ENCRYPTED', 'false'),
],
],
With my .env file looking like:
WS_HOST=127.0.0.1
WS_POST=6001
WS_SCHEME='https'
WS_ENCRYPTED=true
My Echo config:
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'PUSHE_KEY',
encrypted: true,
wsHost: socket.domain.com,
wsPort: 443,
wssPort: 443,
disableStats: true,
authEndpoint: environment.url + '/broadcasting/auth',
auth: {
headers: {
Authorization: 'Bearer ' + this.authService.getBearer(),
},
},
});
And the exact error I get in the Chrome console:
WebSocket connection to 'wss://socket.domain.com/app/b7c07386f4d71d126430?protocol=7&client=js&version=4.3.1&flash=false' failed: Error during WebSocket handshake: Unexpected response code: 502
Oh, and I have the php artisan websockets:serve
command setup as a Forge Daemon.
Any pointers on this will be more than appreciated, thanks in advance
@stayallive since a lot of us is experiencing the same problem, i think it would be great if there is a blog post / gist that goes through an end-to-end configuration to get it working properly. I've been digging in such issue for almost a week now.
Appreciated!
@jafar-albadarneh how about: https://alex.bouma.me/installing-laravel-websockets-on-forge/
Thanks @stayallive ! Your guide helped me get it working 🎉
@stayallive You made my day! Working Great now. Thanks a lot
Your comments helped me a lot @stayallive Thank you.
@jafar-albadarneh how about: https://alex.bouma.me/installing-laravel-websockets-on-forge/
Thank you you helped me a lot
Hello,
Could someone help with how to configure the app to work on laravel forge w/ let's encrypt? The app would host it's own websocket, so it's not a separate subdomain.