Laravel Forge 與 Soketi 環境架設,在專案裡導入 Websocket

本文使用 Soketi 1.0.16 版本。

Soketi 是一個基於 uWebSockets.js 的輕量 WebSocket 開源解決方案,由 C 語言移植到 Node.js。uWebSockets.js 經過實測的結果效能是 Socket.IO 的 8.5 倍,最重要的是它完全相容於 Pusher Protocol v7,因此可以作為完全免費的 Pusher 替代方案。如果實際要部署時,只需要開一台 5 美金的 1GB RAM, 1CPU 的虛擬機器就能同時接收 200k 的連線。

Soketi 可以透過 npm 以及 docker 進行安裝,官方文件有詳細的 CLI Installation、Docker、Helm Charts、Laravel Sail 的安裝方式。

FeaturePusherAblySoketiServerless
價格49 美金/月49 美金/月依 Server 計費12 美金
同時連線數500500無限制無限制
每月訊息數30,000,0006,000,000無限制無限制
訊息大小限制10 KiB64 KiB可自行設定可自行設定
最大頻道數100200無限制無限制
Lambda Webhooks
ProtocolPusherAbly/PusherPusherPusher
開源軟體非開源非開源開源不適用
Soketi 與其他解決方案比較表

如何導入 Soketi?

# npm 的安裝方式
npm install -g @soketi/soketi

# 啟動 Soketi
soketi start

# 用 pm2 啟動 Soketi
soketi-pm2

# 用 docker 的啟動方式
docker run -p 6001:6001 -p 9601:9601 quay.io/soketi/soketi:1.0-16-debian --name soketi

Soketi 有許多的設定,在設置時可以透過 .env 檔案或是 json 檔案。如果使用 .env 檔案設定的話,要將該檔案放在執行 soketi start 的相同資料夾底下,如果是使用 json 檔案設定時則要在指令上指定設定檔案的位置。

如何在 Laravel 導入 Soketi?

官方建議使用 Laravel Sail 的方式導入,可以在 docker-compose.yml 設定檔案裡加入該 image

# docker-compose.yml
soketi:
        image: 'quay.io/soketi/soketi:latest-16-alpine'
        environment:
            DEBUG: '1'
            METRICS_SERVER_PORT: '9601'
        ports:
            - '${SOKETI_PORT:-6001}:6001'
            - '${SOKETI_METRICS_SERVER_PORT:-9601}:9601'
        networks:
            - sail

如何在 Laravel Forge 建置 Soketi?

步驟一:在 Network 項目中加入 6002 Port

因為我們會上 SSL,所以會使用這個 Port,而非 6001

步驟二:建立一個新的 Website

步驟三:使用 Let’s Encrypt 加上 SSL

步驟四:修改 Nginx 的設定

當中的 {{ SITE }}{{ SSL_ID }} 要更換為自己實際的狀況,注意到當中有 listen 6002 ssl http2 這段以及 location / 會 proxy_pass 至 127.0.0.1:6001

# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/{{ SITE }}/before/*;

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    listen 6002 ssl http2;
    listen [::]:6002 ssl http2;
    server_name {{ SITE }};
    server_tokens off;
    root /home/forge/{{ SITE }}/public;

    # FORGE SSL (DO NOT REMOVE!)
    ssl_certificate /etc/nginx/ssl/{{ SITE }}/{{ SSL_ID }}/server.crt;
    ssl_certificate_key /etc/nginx/ssl/{{ SITE }}/{{ SSL_ID }}/server.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_dhparam /etc/nginx/dhparams.pem;

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

    index index.html index.htm index.php;

    charset utf-8;

    # FORGE CONFIG (DO NOT REMOVE!)
    include forge-conf/{{ SITE }}/server/*;

    access_log off;
    error_log  /var/log/nginx/{{ SITE }}-error.log error;

    location / {
        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;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

# FORGE CONFIG (DO NOT REMOVE!)
include forge-conf/{{ SITE }}/after/*;

步驟五:撰寫 start_soketi.sh

要注意先確認 forge 機器上已經裝有 soketi 指令,如果還沒安裝的話,可以先透過前面提到的 npm 方式進行安裝。

# 這邊 source 是因為有可能 npm 路徑沒進來導致找不到 soketi 指令
source ~/.bashrc
# 這邊指定 HOME 是因為這個啟動會透過 pm2,但 pm2 預設的資料夾是 /etc,會出現權限錯誤
HOME=/home/forge/soketi.demo soketi start

步驟六:設定 Daemon 執行 Bash Script

步驟七:確認啟動資訊

步驟八:使用 WebSocket Client 進行測試

可以使用 Chrome Extension WebSocket Client 進行連線測試,例如連線到 wss://example.com:6002/app/app-key

參考文件:

https://docs.soketi.app/v/soketi-docs/

https://laravel.com/docs/9.x/broadcasting