Get Rewarded! We will reward you with up to €50 credit on your account for every tutorial that you write and we publish!

Setting up a Soketi WebSocket Server behind a Reverse Proxy (NGINX)

profile picture
Author
crocodile2024
Published
2024-08-18
Time to read
7 minutes reading time

Introduction

In this tutorial, you will learn how to operate a Soketi WebSocket server behind an NGINX reverse proxy server, which will be protected by SSL encryption. The SSL certificate will be created using Let's Encrypt and is thus free. The renewal of this certificate is automated with the help of the command-line program acme.sh.

Official Documentation: https://docs.soketi.app/
Project Website: https://soketi.app/

Prerequisites

  • Domain name (a subdomain is sufficient)
  • Some experience with NodeJS and NPM
  • A server (for example, with Hetzner Cloud)
    • Debian 12 or Ubuntu 24.04 as operating system
    • SSH key is recommended (see this article)
    • Access to the root user or a user with sudo permissions

Example terminology

  • Domain: ws.example.com
  • IPv4: 203.0.113.1
  • IPv6: 2001:db8:1234::1

Step 1 - Install updates and necessary packages

Connect to the server via SSH using your IP address.

Update package lists and install updates:

sudo apt update && sudo apt upgrade -y

Then restart the server to load any updated kernel.

Next, install all necessary packages:

  • Install prerequisites

    sudo apt install git python3 gcc build-essential apparmor nginx
  • Install NodeJS

    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
    source ~/.bashrc
    nvm install 18 && nvm use 18
  • Install the two NodeJS packages soketi and pm2:

    npm install -g @soketi/soketi
    npm install -g pm2

Step 2 - Create configuration for Soketi

Create a new configuration file:

nano ~/config.json

Add the following content and adjust it to your needs:

{
  "host": "127.0.0.1",
  "port": 6001,
  "appManager": {
    "driver": "array",
    "options": {
      "apps": [
        {
          "id": "my-app-id",
          "key": "my-app-key",
          "secret": "my-app-secret",
          "name": "My App",
          "enableClientMessages": true,
          "enableStatistics": true
        }
      ]
    }
  }
}

Save it with the key combination CTRL+O.

If this configuration file is used, no further configuration is required before the first start.

Step 3 - First start of the Soketi server (without PM2)

Now start the Soketi server by running the following command in a terminal:

soketi start --config="~/config.json"

Step 4 - First test of the WebSocket server with Laravel 11

Make sure you have Laravel installed.

If Laravel isn't installed yet, click here and install it now
sudo apt update && sudo apt install php php-{mbstring,xml,bcmath,mysql} mariadb-server
cd ~ && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
echo 'alias composer="php ~/composer.phar"' >> ~/.bashrc && source ~/.bashrc
composer create-project --prefer-dist laravel/laravel ~/example
cd ~/example

And setup a database:

sudo mysql
MariaDB [(none)]> CREATE USER 'laravel'@'localhost' IDENTIFIED BY 'secure-password';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON laravel.* TO 'laravel'@'localhost';
MariaDB [(none)]> CREATE DATABASE laravel;
MariaDB [(none)]> exit

Add the database information in the ~/example/.env file:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=secure-password

Now run:

cd ~/example && php artisan migrate

Now, configure Soketi with Laravel.


Change the following values in the ~/example/.env file:

Add the same app ID, app key, and app secret, you also used in ~/config.json.

BROADCAST_DRIVER=pusher
PUSHER_APP_ID=my-app-id
PUSHER_APP_KEY=my-app-key
PUSHER_APP_SECRET=my-app-secret
PUSHER_APP_CLUSTER=mt1

Check the settings in the file ~/example/config/broadcasting.php:

<?php

return [
    '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,
            ],
        ],
        // other connections...
    ],
];

Step 5 - Trigger first events

You can now send the first events with your WebSocket server.

Step 6 - Configure auto-start for the Soketi server

To ensure the Soketi server starts automatically after a reboot of the server, we need to configure pm2:

Run the following commands:

pm2 start soketi --name WebSocket-Server -- start --config="~/config.json"
pm2 startup         # This activates the autostart. Follow the instructions on the screen.

Step 7 - Set up reverse proxy

Now we need to set up the reverse proxy server. This will provide the SSL connection and then forward it to the soketi server. Create a new file in the /etc/nginx/sites-available/ directory.

sudo mkdir /etc/nginx/ssl
sudo nano /etc/nginx/sites-available/soketi

Add the following content to the file:

Replace ws.example.com with your own domain.

server {
    listen 443 ssl;
    server_name ws.example.com;

    ssl_certificate /etc/nginx/ssl/ws.example.com.cer;
    ssl_certificate_key /etc/nginx/ssl/ws.example.com.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://localhost:6001;  # Replace the port if Soketi is running on a different port
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;
    }
}

server {
    listen 80;
    server_name ws.example.com;

    location / {
        return 301 https://$host$request_uri;
    }
}

Click here if you don't want to setup SSL

Replace 203.0.113.1 with your own IP address.

server {
    listen 80;
    server_name 203.0.113.1;

    location / {
        proxy_pass http://localhost:6001;  # Replace the port if soketi is running on a different port
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;
    }
}

sudo ln -s /etc/nginx/sites-available/soketi /etc/nginx/sites-enabled/soketi
sudo rm /etc/nginx/sites-available/default && sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginx

Step 8 - Create SSL certificate

Before you create an SSL certificate, make sure you have DNS entries that point the IP addresses of you server to your domain name.

Your DNS configuration should look like this:

# Name              Type       Value
ws.example.com      IN A       203.0.113.1
ws.example.com      IN AAAA    2001:db8:1234::1

If dig ws.example.com shows the correct IP address, you can create the certificate. Propagation can take a while.

To create the certificate, we use the shell script acme.sh. Install it with the following command:

curl https://get.acme.sh | sh -s email=<your-email-address>

You will receive reminders at this email address when a certificate expires or if there are issues with renewal.

systemctl stop nginx && acme.sh --issue -d ws.example.com --standalone --server letsencrypt
acme.sh --install-cert -d ws.example.com --cert-file /etc/nginx/ssl/ws.example.com.cer --key-file /etc/nginx/ssl/ws.example.com.key --fullchain-file /etc/nginx/ssl/fullchain.pem --reloadcmd "systemctl reload nginx"
sudo systemctl restart nginx

Your WebSocket server is now equipped with SSL encryption. In the Laravel configuration, you need to change the port to 443.

Conclusion

You have successfully installed Soketi and setup an SSL certificate. When you access ws.example.com in a web browser, you should get "OK" which means that the web socket is available.

License: MIT
2024. Hetzner Online GmbH. All Rights Reserved.