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
}