Laravel + Nuxt + Nginx: WebSocket is closed before the connection is established

江枫思渺然 提交于 2021-02-08 06:38:48

问题


General scheme and project configuration files

The project consists of two parts:

  • Server part - Laravel (api)
  • Customer part - NuxtJs (client)

A minimum project configuration has been prepared for the test:

Laravel

Websockets packages have been installed:

  • beyondcode/laravel-websockets: https://beyondco.de/docs/laravel-websockets/getting-started/introduction
  • pusher/pusher-php-server: https://pusher.com/tutorials/web-notifications-laravel-pusher-channels

File composer.json:

...
    "require": {
        "php": "^7.3",
        "beyondcode/laravel-websockets": "^1.8",
        "fideloper/proxy": "^4.2",
        "fruitcake/laravel-cors": "^2.0",
        "guzzlehttp/guzzle": "^7.0.1",
        "laravel/framework": "^8.0",
        "laravel/tinker": "^2.0",
        "pusher/pusher-php-server": "^4.1"
    },
    "require-dev": {
        "facade/ignition": "^2.3.6",
        "fzaninotto/faker": "^1.9.1",
        "mockery/mockery": "^1.3.1",
        "nunomaduro/collision": "^5.0",
        "phpunit/phpunit": "^9.3"
    },
...

Nuxt

Websockets packages have been installed:

  • nuxtjs/laravel-echo: https://github.com/nuxt-community/laravel-echo
  • pusher-js: https://github.com/pusher/pusher-js

File package.json:

...
  "dependencies": {
    "@nuxtjs/axios": "^5.12.2",
    "@nuxtjs/dotenv": "^1.4.1",
    "@nuxtjs/laravel-echo": "^1.1.0",
    "@nuxtjs/proxy": "^2.0.1",
    "nuxt": "^2.13.0",
    "pusher-js": "^7.0.0"
  },
...

All files have already been uploaded to VPS (Ubuntu 18.04 LTS) and a certificate has been obtained (https://certbot.eff.org/):

root@dsde1032-21892:/var/www# ls
api  client  html

The websockets server has been launched on a permanent basis under this description: https://beyondco.de/docs/laravel-websockets/basic-usage/starting

supervisorctl status

root@dsde1032-21892:/var/www# supervisorctl status
websockets                       RUNNING   pid 1421, uptime 1:16:50

A process manager has been installed and launched globally to automatically start and reload the customer part: https://pm2.keymetrics.io

pm2 list

root@dsde1032-21892:/var/www# pm2 list
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name               │ mode     │ *    │ status    │ cpu      │ memory   │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ larastart          │ fork     │ 263… │ online    │ 0%       │ 52.8mb   │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

List of occupied ports:

netstat -ntlp | grep LISTEN

root@dsde1032-21892:/var/www# netstat -ntlp | grep LISTEN
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      968/mysqld
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      961/nginx: master p
tcp        0      0 0.0.0.0:6001            0.0.0.0:*               LISTEN      1421/php
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      945/sshd
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      12821/node
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      961/nginx: master p
tcp6       0      0 :::22                   :::*                    LISTEN      945/sshd

lsof -i -P -n | grep LISTEN

root@dsde1032-21892:/var/www# lsof -i -P -n | grep LISTEN
sshd      945     root    3u  IPv4   19310      0t0  TCP *:22 (LISTEN)
sshd      945     root    4u  IPv6   19314      0t0  TCP *:22 (LISTEN)
nginx     961     root    6u  IPv4   19430      0t0  TCP *:80 (LISTEN)
nginx     961     root   10u  IPv4  554283      0t0  TCP *:443 (LISTEN)
mysqld    968    mysql   31u  IPv4   19706      0t0  TCP 127.0.0.1:3306 (LISTEN)
php      1421     root    5u  IPv4 2352082      0t0  TCP *:6001 (LISTEN)
node    12821     root   18u  IPv4  581986      0t0  TCP 127.0.0.1:3000 (LISTEN)
nginx   32555 www-data    6u  IPv4   19430      0t0  TCP *:80 (LISTEN)
nginx   32555 www-data   10u  IPv4  554283      0t0  TCP *:443 (LISTEN)

Current status of network security:

ufw status

root@dsde1032-21892:/var/www# ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)

The answer from the server part, when requests are made from the client part, comes:

Request URL: https://larastart.site/api/
Request Method: POST
Status Code: 200 OK
Remote Address: 91.228.155.156:443
Referrer Policy: strict-origin-when-cross-origin

An error is generated with websockets:

Request URL: wss://larastart.site:6001/app/456?protocol=7&client=js&version=4.4.0&flash=false
WebSocket is closed before the connection is established.
WebSocket opening handshake timed out

Files for setting up web sockets

Laravel

File .env:

vim /var/www/api/.env

APP_NAME=Laranuxt
APP_ENV=production
APP_KEY=base64:cSTA4y9lIjmQDQ9b3+J2X+iSif8jqu6u3Oj9UNXdzIs=
APP_DEBUG=false
APP_SCHEME=https://
APP_HOST=larastart.site
APP_URL="${APP_SCHEME}larastart.site"
CLIENT_URL="${APP_SCHEME}larastart.site"
...
PUSHER_APP_ID=123
PUSHER_APP_KEY=456
PUSHER_APP_SECRET=789
PUSHER_APP_CLUSTER=test

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

File websockets.php:

vim /var/www/api/config/websockets.php

...
    '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' => false,
        ],
    ],
...

File broadcasting.php:

vim /var/www/api/config/broadcasting.php

...
    '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' => false,
                'encrypted' => false,
                'host' => env('APP_HOST'),
                'port' => 6001,
                'scheme' => 'http',
                'curl_options' => [
                        CURLOPT_SSL_VERIFYHOST => 0,
                        CURLOPT_SSL_VERIFYPEER => 0,
                ]
            ],
        ],
    ...
    ],
...

Nuxt

cd /var/www/client

File .env:

vim /var/www/client/.env

SCHEME     = https://
BASE_URL   = "${SCHEME}larastart.site"
API_DOMAIN = "${SCHEME}larastart.site"
API_URL    = "${SCHEME}larastart.site/api"

BROADCAST_DRIVER   = pusher
PUSHER_APP_ID      = 123
PUSHER_APP_KEY     = 456
PUSHER_APP_SECRET  = 789
PUSHER_APP_CLUSTER = test

File echo.js:

vim /var/www/client/plugins/echo.js

import Echo from 'laravel-echo';

export default (app) => {
    window.Pusher = require('pusher-js');

    window.Echo = new Echo({
        broadcaster: process.env.BROADCAST_DRIVER,
        key: process.env.PUSHER_APP_KEY,
        cluster: process.env.PUSHER_APP_CLUSTER,

        forceTLS: false,
        encrypted: false,
        wsHost: window.location.hostname,
        wsPort: 6001,
        wssPort: 6001,
        disableStats: false,
        enabledTransports: ['ws', 'wss']
    });
}

File nuxt.config.js:

vim /var/www/client/nuxt.config.js

...
  plugins: [
    { src: '~/plugins/echo.js', ssr: false }
  ],
  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/proxy',
    '@nuxtjs/dotenv'
  ],
  axios: {
    baseURL: process.env.API_DOMAIN,
    credentials: true
  },
  proxy: {
    "/api": {
      target: process.env.API_DOMAIN,
      pathRewrite: { "^/api" : "/" }
    }
  },
...

Nginx

A configuration file for the site on the Nginx web server has been created and is connected:

ls /etc/nginx/sites-enabled/

root@dsde1032-21892:/var/www# ls /etc/nginx/sites-enabled/
larastart.site

vim /etc/nginx/sites-available/larastart.site

server {
        server_name     larastart.site;
        root            /var/www/api/public;

        add_header X-Frame-Options              "SAMEORIGIN";
        add_header X-XSS-Protection             "1; mode=block";
        add_header X-Content-Type-Options       "nosniff";

        # Priority file extensions
        index index.php index.html index.htm index.nginx-debian.html;

        charset utf-8;

        # Check for the existence of files matching a provided url, forward to 404 if not found
        location /api {
                try_files $uri $uri/ /index.php?$query_string;
        }

        # Serve static files directly
        location ~* ^/storage/(.*)\.(jpg|jpeg|gif|bmp|png|ico)$ {
                access_log off;
        }

        location / {
                proxy_pass                          http://127.0.0.1:3000;
                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  $scheme;
                proxy_set_header X-VerifiedViaNginx yes;
                proxy_read_timeout                  300;
                proxy_connect_timeout               300;
        }

        location /app {
                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  $scheme;
                proxy_set_header X-VerifiedViaNginx yes;
                proxy_read_timeout                  300;
                proxy_connect_timeout               300;

                # Specific for websockets: force the use of HTTP/1.1 and set the Upgrade header
                proxy_http_version      1.1;
                proxy_set_header        Host            $host;
                proxy_set_header        Upgrade         $http_upgrade;
                proxy_set_header        Connection      'upgrade';
                proxy_cache_bypass      $http_upgrade;
        }

        error_page 404 /index.php;

        # pass PHP scripts to FastCGI server
        location ~ \.php$ {
                fastcgi_pass  unix:/var/run/php/php7.4-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
                include fastcgi_params;
        }

        # deny access to .htaccess files, if Apache's document root concurs with nginx's one
        location ~ /\.(?!well-known).* {
               deny all;
        }

    listen 443 ssl; # managed by Certbot
    
    ssl_certificate     /etc/letsencrypt/live/larastart.site/fullchain.pem;     # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/larastart.site/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
}

server {
    if ($host = larastart.site) {
            return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name larastart.site;
    return 404; # managed by Certbot
}

回答1:


The solution has been found. I want to share my settings, which played a key role.

Project settings

Firewall

netstat -ntlp | grep LISTEN

root@dsde1032-21892:~# netstat -ntlp | grep LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1066/nginx: master
tcp        0      0 0.0.0.0:6001            0.0.0.0:*               LISTEN      7768/php
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1064/sshd
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      1173/node
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      1066/nginx: master
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      1078/mysqld
tcp6       0      0 :::22                   :::*                    LISTEN      1064/sshd

lsof -i -P -n | grep LISTEN

root@dsde1032-21892:~# lsof -i -P -n | grep LISTEN
sshd     1064     root    3u  IPv4  20044      0t0  TCP *:22 (LISTEN)
sshd     1064     root    4u  IPv6  20138      0t0  TCP *:22 (LISTEN)
nginx    1066     root    6u  IPv4  20168      0t0  TCP *:443 (LISTEN)
nginx    1066     root    7u  IPv4  20169      0t0  TCP *:80 (LISTEN)
mysqld   1078    mysql   31u  IPv4  20463      0t0  TCP 127.0.0.1:3306 (LISTEN)
node     1173     root   18u  IPv4  20902      0t0  TCP 127.0.0.1:3000 (LISTEN)
nginx    7402 www-data    6u  IPv4  20168      0t0  TCP *:443 (LISTEN)
nginx    7402 www-data    7u  IPv4  20169      0t0  TCP *:80 (LISTEN)
php      7768     root    5u  IPv4 110549      0t0  TCP *:6001 (LISTEN)

ufw status

root@dsde1032-21892:~# ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
6001                       ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)
6001 (v6)                  ALLOW       Anywhere (v6)

ufw show listening

root@dsde1032-21892:~# ufw show listening
tcp:
  22 * (sshd)
   [ 1] allow OpenSSH

  443 * (nginx)
   [ 2] allow 'Nginx Full'

  6001 * (php7.4)
   [ 3] allow 6001

  80 * (nginx)
   [ 2] allow 'Nginx Full'

tcp6:
  22 * (sshd)
   [ 4] allow OpenSSH

Laravel

vim /var/www/api/config/websockets.php

...
    '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' => false,
        ],
    ],
...
    'ssl' => [
        'local_cert' => '/etc/letsencrypt/live/larastart.site/fullchain.pem',
        'local_pk' => '/etc/letsencrypt/live/larastart.site/privkey.pem',
        'passphrase' => null,
        'verify_peer' => false
    ],
...

vim /var/www/api/config/broadcasting.php

...
    '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,
                ]

            ],
        ],
...
    ],
...

Nuxt

vim /var/www/client/package.json

{
  "name": "frontend",
  "version": "1.0.0",
  "private": true,
  "config": {
    "nuxt": {
      "port": "3000"
    }
  },
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "export": "nuxt export",
    "serve": "nuxt serve"
  },
  "dependencies": {
    "@nuxtjs/axios": "^5.12.2",
    "@nuxtjs/dotenv": "^1.4.1",
    "@nuxtjs/laravel-echo": "^1.1.0",
    "@nuxtjs/proxy": "^2.0.1",
    "nuxt": "^2.13.0",
    "pusher-js": "^4.4.0"
  },
  "devDependencies": {}
}

vim /var/www/client/plugins/echo.js

import Echo from 'laravel-echo';

export default (app) => {
    window.Pusher = require('pusher-js');

    window.Echo = new Echo({
        broadcaster: process.env.BROADCAST_DRIVER,
        key: process.env.PUSHER_APP_KEY,
        cluster: process.env.PUSHER_APP_CLUSTER,

        forceTLS: true,
        encrypted: false,
        wsHost: window.location.hostname,
        wsPort: 6001,
        wssPort: 6001,
        disableStats: true,
        enabledTransports: ['ws', 'wss']
    });
}

Nginx

vim /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        types_hash_max_size 2048;
        # server_tokens off;

        # server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # SSL Settings
        ##

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
        ssl_prefer_server_ciphers on;

        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        ##
        # Gzip Settings
        ##

        gzip on;

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
}


#mail {
#       # See sample authentication script at:
#       # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
#       # auth_http localhost/auth.php;
#       # pop3_capabilities "TOP" "USER";
#       # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
#       server {
#               listen     localhost:110;
#               protocol   pop3;
#               proxy      on;
#       }
#
#       server {
#               listen     localhost:143;
#               protocol   imap;
#               proxy      on;
#       }
#}

vim /etc/nginx/sites-available/larastart.site

server {
        server_name     larastart.site;
        root            /var/www/api/public;

        add_header X-Frame-Options              "SAMEORIGIN";
        add_header X-XSS-Protection             "1; mode=block";
        add_header X-Content-Type-Options       "nosniff";

        # Priority file extensions
        index index.php index.html index.htm index.nginx-debian.html;

        charset utf-8;

        # Check for the existence of files matching a provided url, forward to 404 if not found
        location /api {
                try_files $uri $uri/ /index.php?$query_string;
        }

        # Serve static files directly
        location ~* ^/storage/(.*)\.(jpg|jpeg|gif|bmp|png|ico)$ {
                access_log off;
        }

        location / {
                proxy_pass                          http://127.0.0.1:3000;
                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  $scheme;
                proxy_set_header X-VerifiedViaNginx yes;
                proxy_read_timeout                  300;
                proxy_connect_timeout               300;
        }

        location /app {
                proxy_pass             https://larastart.site: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;
        }

        error_page 404 /index.php;

        # pass PHP scripts to FastCGI server
        location ~ \.php$ {
                fastcgi_pass  unix:/var/run/php/php7.4-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
                include fastcgi_params;
        }

        # deny access to .htaccess files, if Apache's document root concurs with nginx's one
        location ~ /\.(?!well-known).* {
               deny all;
        }

        listen 443 ssl; # managed by Certbot

        ssl_certificate     /etc/letsencrypt/live/larastart.site/fullchain.pem;     # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/larastart.site/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
}

server {
        if ($host = larastart.site) {
                return 301 https://$host$request_uri;
        } # managed by Certbot

        listen 80;
        server_name larastart.site;
        return 404; # managed by Certbot
}


来源:https://stackoverflow.com/questions/64477776/laravel-nuxt-nginx-websocket-is-closed-before-the-connection-is-established

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!