Cài đặt server websockets trên AWS EC2 với Laravel WebSockets

Bạn là người chơi hệ PHP nhưng lại muốn realtime thì đây là bài viết dành cho bạn. Trước khi vào bài viết thì các bạn cần biết websockets. Mình đã dựng lên con websockets này trong hoàn cảnh:
- Khách hàng muốn làm 1 ứng dụng chat realtime nhưng lại lại không cho dùng Pusher vì phí khá đắt.
- Firebase Cloud Messaging thì ổn nhưng lại bị dính đến quyền browser (nếu không bật notice ở browser thì không chat được).
- Socket I.O là giải pháp hay nhưng mình nói từ đầu rồi đấy "do là người chơi hệ PHP".

Nói chung cuộc sống éo le đưa mình tới websockets nhưng sau khi cài xong thì thấy "ok" cũng ko tệ :)).

Để cài đặt ta việc ta cần làm:
Bước 1. Dựng con instance EC2, có source code để keep 1 con websockets đảm nhiệm connect tới tất cả client.
Bước 2. Nếu ứng dụng của bạn dùng HTTPS thì bạn phải cài TLS cho websocket ở đây mình dùng ALB của AWS để tạo.
Bước 3. Cần 1 subdomain để connect đến ALB ở đây mình dùng Route 53 để tạo rồi connect với ALB.


Ở đây mình con như bạn đã có 1 con server web hoàn chỉnh chỉ còn cần cài websocket nữa thôi. Chúng ta sẽ đi vào từng bước:

Bước 1: Cài đặt trên EC2


Cài đặt package

composer require beyondcode/laravel-websockets

Gói sẽ tự động đăng ký nhà cung cấp dịch vụ.
Gói này đi kèm với một sự di chuyển để lưu trữ thông tin thống kê trong khi chạy máy chủ WebSocket của bạn. Bạn có thể xuất bản tệp di chuyển bằng cách sử dụng:

php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"

chạy migrate:

php artisan migrate

Tiếp theo, bạn cần xuất bản tệp cấu hình WebSocket:

php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"

Cài đặt Pusher ( ở đây chúng ta vẫn dùng config như Pusher chỉ là không connect đến server của Pusher thôi nhé :D)

composer require pusher/pusher-php-server

trong file .env  thêm những phần mà config trong pusher bạn có thể điền gì vào đó cũng được sau này chỉ có PUSHER_APP_KEY là sẽ cần khớp phần cài đặt phía client để hứng event thôi.

PUSHER_APP_ID=<id tự định nghĩa là 1 string>
PUSHER_APP_KEY=<KEY tự định nghĩa là 1 string>
PUSHER_APP_SECRET=<SECRET tự định nghĩa là 1 string>
PUSHER_APP_CLUSTER=<CLUSTER tự định nghĩa là 1 string>
BROADCAST_DRIVER=pusher
PUSHER_SCHEMA=https
PUSHER_USE_TLS=true
PUSHER_HOST='subdomain tạo ở bước 3'


trong config/broadcasting.php ta config

'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' => env('PUSHER_USE_TLS', 'false'),
        'encrypted' => env('PUSHER_ENCRYPTED', 'true'),
        'host' => env('PUSHER_HOST', '127.0.0.1'),
        'port' => env('PUSHER_PORT', '6001'),
        'scheme' => env('PUSHER_SCHEMA', 'http'),
    ],
],

Để nhận và gửi gói tin qua cổng 6001

php artisan websockets:serve --port=6001

Theo mặc định, máy chủ Laravel WebSocket sẽ lắng nghe 0.0.0.0và cho phép các kết nối đến từ tất cả các mạng. Nếu bạn muốn hạn chế điều này, bạn có thể khởi động máy chủ bằng một --hosttùy chọn, sau đó là IP.

Ví dụ: bằng cách sử dụng 127.0.0.1, bạn sẽ chỉ cho phép các kết nối WebSocket từ localhost.

Để keep proccess này ta nên dùng supervisor để đảm bảo nó luôn luôn chạy:

Sau khi cài đặt supervisor , hãy thêm một quy trình mới supervisorcần tiếp tục chạy. Bạn đặt cấu hình của mình trong thư mục /etc/supervisor/conf.d(Debian / Ubuntu) hoặc /etc/supervisord.d(Red Hat / CentOS).

Trong thư mục đó, hãy tạo một tệp mới có tên websockets.conf.

[program:websockets]
command=/usr/bin/php /home/laravel-websockets/artisan websockets:serve
numprocs=1
autostart=true
autorestart=true
user=ubuntu

Sau khi được tạo, hãy hướng dẫn supervisortải lại các tệp cấu hình của nó (mà không ảnh hưởng đến các supervisorcông việc đang chạy).

supervisorctl update
supervisorctl start websockets

Phía server cần mở port cho cổng 6001 trên cả (aws) network sercurity group

sg!

và trong iptables

sudo ufw allow 6001

Bước 2: Cài TLS với ALB

Tạo 1 target group trỏ đến instance ec2 qua port 6001

sg!

Enabled Stickiness trong tab Attributes

sg!

Tạo 1 network load balancer và trỏ vào target group qua cổng 6001 nhớ phải add certificates cho nó nhé các bạn.

sg!

Bước 3: Trong route 53 tạo 1 subdomain trỏ đến ALB

Vậy là đã setup xong 1 con server websockets

Để hứng được event bên client bạn sẽ cần dùng Laravel Echo

VD: nếu dùng VueJs

import Echo from "laravel-echo"

window.Pusher = require('pusher-js');

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'your-pusher-key', // chính là PUSHER_APP_KEY trong .env
    wsHost: window.location.hostname, // là subdomain bạn tạo ra
    wsPort: 6001,
    wssPort: 6001,
    forceTLS: true, // nếu là wss
    disableStats: true,
});

Hy vọng bài viết có ích cho các bạn :D bye bye :))