WebSocket server

Image by Thomas Breher from Pixabay

Image by Thomas Breher from Pixabay

Websockets provide a significant next step to your dynamic web content. Not only can you retrieve and send data to and from your web server asynchronous using vanilla fetch or the npm packet Axios. You can also have the webserver push data to the client's web browser when needed.

This feature makes it possible to make applications that encourage collaboration where changes made by one user can instantly update another user's view of the webpage to reflect the changes.

In this guide, I will provide a simple step-by-step guide on how to run a web server using the PHP framework Laravel.

This guide assumes that you have some basic experience hosting websites using Nginx. In addition, it assumes a functioning installation of the Composer PHP packet manager. This guide also is based on Ubuntu 20.04 LTS.

Installation

Start by creating a project directory, and change the permissions on that directory so that you can make changes to it and that the PHP-FPM process can own the files inside it.

sudo mkdir /var/www/ws.haxor.test
sudo chown /var/www/ws.haxor.test
sudo chmod 774 /var/www/ws.haxor.test
cd /var/www/ws.haxor.test

Make sure that your user is added to the PHP-FPM user group.

sudo usermod -aG www-data stanley

Now that all user permissions are set, you can install Laravel, and make it create the basic project files, along with the WS service that will be managed by Laravel.

composer create-project laravel/laravel .
composer require beyondcode/laravel-websockets

Database

Once the dependencies are installed you must create a database and a database user that has full access to that database. Add the user and permissions to the .env file in the root of the project directory.

If you prefer to use SQLite, you can define the DB_CONNECTION to be sqlite, and comment out the rest of the database definitions. And add an empty file called database.sqlite in the database directory in your project root.

.env
...
DB_CONNECTION=sqlite
#DB_CONNECTION=mysql
#DB_HOST=127.0.0.1
#DB_PORT=3306
#DB_DATABASE=laravel
#DB_USERNAME=root
#DB_PASSWORD=
touch database/database.sqlite

Publish/Migrate

To build the tables and add basic content to your database run artisan migrate.

php artisan vendor:publish

# Choose: BeyondCode\LaravelWebSockets\WebSocketsServiceProvider
php artisan migrate

If your database configuration was correct you will now have a functioning Laravel project ready to be hosted.

Add WS apps

The WS server will require authentication of both the client that will receive data and the web server that will provide the data to the WS server. By default, this is defined in the webockets.php config file. This usually references data in the .env file. To make it a bit more modular I suggest that you make a few changes to the file. First, you include a new file that will basically provide an array of applications.

config/ws_apps.php
<?php
$apps = [
    [
        'id' => 1,
        'name' => "ws-project.test",
        'key' => "public-key-123",
        'secret' => "secret-key-123",
        'path' => null,
        'capacity' => null,
        'enable_client_messages' => false,
        'enable_statistics' => true,
    ],
];
?>

Secondly, you use that variable to return an array of apps that will be used by the web socket server.

config/websockets.php
..
include('ws_apps.php');
return [

...
'apps' => $apps,        
...

];

Serve!

Now everything is ready to have your own WebSockets server running. to start the application simply run:

php artisan websockets:serve

To stop the WS server simply stop it by pressing Ctrl+C.

Serve with supervisor

Supervisor is a fantastic program that works similarly to how systemctl works, but with a bit easier-to-use configuration files. To install it run this command:

sudo apt update
sudo apt install supervisor

Next add a configuration file that will tell supervisor to run the WS server and how to run it.

sudo vim /etc/supervisor/conf.d/ws.haxor.test.conf
/etc/supervisor/conf.d/ws.haxor.test.conf
[program:ws_haxor]
command=/usr/bin/php /var/www/ws.haxor.test/artisan websockets:serve
autostart=true
autorestart=true

Please note that Supervisor does require a full path to the application you want to run.

Now you just have to update the list of configuration files Supervisor uses and you will have the WS server running like a daemon on you system.

sudo supervisorctl update

To start, stop, restart and check for status on the deamon run by supervisor run it similarly to systemctl

sudo supervisorctl start ws_haxor
sudo supervisorctl stop ws_haxor
sudo supervisorctl restart ws_haxor
sudo supervisorctl status ws_haxor

Nginx Reverse Proxy

To make the WS server accessible over port 80 you can configure your Nginx webserver to act as a reverse proxy. To do so, simply add this location to your server block.

/etc/nginx/sites-available/ws.haxor.test
...
location /app {
                proxy_pass http://127.0.0.1:6001;
                proxy_read_timeout 60;
                proxy_connect_timeout 60;
                proxy_redirect off;

                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;
}
...

Now you can have all your web clients and web servers access the WS server over port 80. To have it run over TLS on port 443, simply run certbot, and everything will be taken care of.

sudo certbot --nginx -d ws.haxor.test

Congratulations! You now have your own production-ready WebSocket server secured by TLS! 🎉