Laravel + Nuxt + Nginx:WebSocket 在连接建立之前关闭

2023-12-09

通用方案和项目配置文件

该项目由两部分组成:

  • 服务器部分 - Laravel (api)
  • 客户部分-NuxtJs(客户端)

已为测试准备了最低项目配置:

Laravel

Websockets 软件包已安装:

  • 超越代码/laravel-websockets:https://beyondco.de/docs/laravel-websockets/getting-started/introduction
  • Pusher/Pusher-php 服务器:https://pusher.com/tutorials/web-notifications-laravel-pusher-channels

File 作曲家.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 软件包已安装:

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

File 包.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"
  },
...

所有文件已上传至VPS (Ubuntu 18.04 LTS)并已获得证书(https://certbot.eff.org/):

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

websockets 服务器已根据以下说明永久启动:https://beyondco.de/docs/laravel-websockets/basic-usage/starting

主管状态

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

已在全局范围内安装并启动了流程管理器,以自动启动并重新加载客户部分: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   │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

占用端口列表:

netstat -ntlp | 网络统计grep 听

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 | lsof -i -P -n | grep 听

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)

网络安全现状:

UFW 状态

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)

当客户端发出请求时,服务器部分的答案如下:

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

使用 websocket 会生成错误:

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

用于设置网络套接字的文件

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 广播.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/客户端

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

Nginx Web 服务器上的站点配置文件已创建并已连接:

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
}

解决办法已经找到了。我想分享我的设置,它起到了关键作用。

项目设置

Firewall

netstat -ntlp | 网络统计grep 听

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 | lsof -i -P -n | grep 听

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 状态

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 表演聆听

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
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Laravel + Nuxt + Nginx:WebSocket 在连接建立之前关闭 的相关文章

随机推荐