Deploy ứng dụng chat realtime Laravel, VueJS, Laravel Echo và Laravel Reverb trên Ubuntu
Cập nhật gần nhất: 05/12/2024
Chào mừng các bạn đã quay trở lại với blog của mình 👋👋
Ở 2 bài trước chúng ta đã biết cách sử dụng Public, Private và Presence channel để xây dựng ứng dụng chat realtime với Laravel.
Giờ ở local đã chạy ngon, vấn đề là làm sao để có thể deploy ứng dụng ra server thật cho các anh chị em khác vào sử dụng. Vì việc deploy 1 ứng dụng Laravel ra production sẽ khá là khác so với lúc ta setup ở local và rất nhiều bạn đã comment cho mình là viết về 1 bài về việc này.
Cùng với đó mình thấy ứng dụng Chat realtime này cũng là 1 ví dụ điển hình cho một project Laravel chúng ta thường thấy khi đi làm với đầy đủ các components:
- Laravel
- MySQL
- VueJS
- Queue/Job
- Task Scheduling
- Laravel Reverb (websocket server)
- Laravel Telescope/Pulse cho monitoring
Ta bắt đầu thôi nhé 🚀🚀
Điều kiện tiên quyết
Nghe như học sinh cấp 2 😂😂
Ở bài này ta sẽ thực hành với project của mình với đầy đủ chức năng và sẵn sàng cho deploy trên server ở đây: https://github.com/maitrungduc1410/realtime-chatapp-laravelecho-socketio
Vì deploy trên server thật nên tất nhiên các bạn sẽ phải có server để thực hành, môi trường Ubuntu là oke nhất. Server các bạn có thể thuê ở bất kì nhà cung cấp nào: AWS, Google, Azure, Digital Ocean,... (Đây là 4 địa chỉ mà mình ưa thích và luôn recommend)
Các bạn chú ý là ta phải có Server (VPS, VM), chứ không phải Hosting thông thường nhé.
Nếu các bạn có domain thì đến cuối bài ta có thể setup được HTTPS xịn xò luôn. Mình khuyến khích các bạn bỏ ra ít tiền (mấy chục tới 1-200K) lên Goddady mua 1 cái domain lởm lởm về để học tập 😘
Ví dụ như ở đây của mình là 1 con VM Ubuntu trên Digital Ocean, phiên bản 24.10
Ta cũng có thể check bản phân phối Linux, version khi login vào server như sau:
cat /etc/os-release
>>>
PRETTY_NAME="Ubuntu 24.10"
NAME="Ubuntu"
VERSION_ID="24.10"
VERSION="24.10 (Oracular Oriole)"
VERSION_CODENAME=oracular
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=oracular
Tổng quan
Bài này chúng ta sẽ cùng nhau deploy ứng dụng realtime chat giống hệt như của mình ở đây: https://realtime-chat.jamesisme.com/
Đầu tiên ta cùng lắc não trước tổng hợp lại xem để chạy được project này thì ta cần những gì nhé:
- code Laravel thì server cần phải có PHP + Composer (tất nhiên rồi ☺️)
- MySQL
- NodeJS/npm để build code VueJS
- Crontab (Ubuntu có sẵn) để chạy Scheduled Task. Đợt đầu mới học Laravel mình ngây thơ lắm, đọc docs Laravel xong cứ nghĩ Task Scheduling cứ thế chạy với cái command được ghi trong docs cơ 🤪
- Process Manager để chạy tất cả những thứ bên trên, ở đây mình chọn Supervisor. Đây là cái gì lát nữa mình sẽ giải thích sau nhé
- Nginx làm webserver để chạy ứng dụng PHP. Các bạn chú ý là ở production ta không chạy
php artisan serve
nữa mà ta sẽ dùng một webserver để làm điều đó. - Cuối cùng là Certbot để lấy HTTPS
Ồi liệt kê ra cũng nhiều phết đấy chứ nhỉ 😁. Tiến hành thôi nào💪
Cài đặt
Đầu tiên đảm bảo là các bạn SSH vào được VM nha (không SSH vào được thì làm kiểu j đây 😂)
Đảm bảo là user các bạn đang dùng có quyền
sudo
nhé, như của mình là userroot
luôn
PHP
Giả sử ta mới tạo VM (VPS), mọi thứ còn mới tinh, thì đầu tiên ta update package list + upgrade các package sẵn có trước phát nhé:
sudo apt update -y && sudo apt upgrade -y
Sau đó ta cài PHP:
sudo apt install php8.3 -y
Hiện tại Laravel 11 cần PHP >= 8.3 rồi nha
Sau đó các bạn check thử xem php đã được cài thành công chưa nhé:
php -v
>>>
PHP 8.3.11 (cli) (built: Sep 30 2024 12:07:44) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.11, Copyright (c) Zend Technologies
with Zend OPcache v8.3.11, Copyright (c), by Zend Technologies
Tiếp theo ta cần cài thêm extenstions của PHP vì đó là những extension mà ứng dụng Laravel của chúng ta sẽ cần dùng tới:
sudo apt install libapache2-mod-php php8.3-common php8.3-cli php8.3-mbstring php8.3-bcmath php8.3-fpm php8.3-mysql php8.3-zip php8.3-gd php8.3-curl php8.3-xml -y
Composer
Tiếp theo ta tiến hành cài Composer nhé. Các bạn chạy command sau:
sudo apt-get install curl php7.3-cli git unzip
Ở trên ta cài curl
để download Composer về server, php7.3-cli
để cài đặt Composer, Git
để Composer có thể download các thành phần liên quan và cũng để sau này chúng ta clone code về luôn, unzip
để giải nén.
Tiếp theo ta chuyển tới thư mục ~
(home) và bắt đầu cài đặt nhé:
cd ~
Các bạn vào trang download của Composer: https://getcomposer.org/download, chúng ta sẽ thấy giao diện như sau:
Ở phần đầu tiên các bạn copy toàn bộ command ở trong ô textbox, ở đây là:
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === 'dac665fdc30fdd8ec78b38b9800061b4150413ff2e3b6f88543c636f7cd84f6db9189d43a81e5503cda447da73c7e5b6') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
Ta copy command đó đặt vào terminal VM và chạy nhé:
Sau đó thì ta đưa composer vào system PATH
, thì tí nữa ta đơn giản là gọi trực tiếp composer ...
từ terminal:
sudo mv composer.phar /usr/local/bin/composer
Sau khi quá trình cài đặt thành công, các bạn có thể gõ command sau ở terminal để check xem composer cài được hay chưa nha:
composer
Ở trên composer cảnh báo ta rằng không nên chạy
composer
vớiroot
user, cái này là lí do bảo mật vì khi ta cài PHP package, nhiều cái nó có thể chạy các script mà ta không biết. Nhưng thôi ở bài này cho đơn giản ta bỏ qua vấn đề này nha (chứ nói thêm vào thì lan man quá 😂
MySQL
Tiếp theo chúng ta tiến hành cài MySQL nhé. Các bạn chạy command sau:
sudo apt-get update
sudo apt install mysql-server -y
Cài xong ta kiểm tra:
mysql --version
>>>
mysql Ver 8.0.40-0ubuntu0.24.10.1 for Linux on x86_64 ((Ubuntu))
Ở trên ta có MySQL 8 😎
Tiếp đó ta kiểm tra trạng thái MySQL server:
service mysql status
Ta cũng có thể dùng command
systemctl status mysql
Ở trên thì MySQL đang active
và running
rồi
Tiếp theo ta chạy command sau để cấu hình cho MySQL:
sudo mysql_secure_installation
Khi được hỏi thì các bạn chọn như sau nhé:
VALIDATE PASSWORD PLUGIN: No
Remove anonymous users? y
Disallow root login remotely? y
Remove test database and access to it? y
Reload privilege tables now? y
>>>
All done!
Ta chạy command sau để MySQL có thể khởi động cùng với server nếu sau này server khởi động lại:
sudo systemctl enable mysql
Giờ ta thử login vô MySQL xem nha:
mysql -u root -p
Khi được hỏi Password thì ta để trống và bấm enter luôn, vô trong thì ta thử list các database xem:
show databases;
>>>
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)
Ngon rồi đó 😎😎
NodeJS
Tiếp theo ta tiến hành cài đặt NodeJS nhé, các bạn chạy command sau:
curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh
sudo -E bash nodesource_setup.sh
sudo apt install nodejs
Ở trên mình cài NodeJS bản 12 hiện tại đang là LTS (Long-term support - ý là bản nên dùng bản này ), sau này có thể thay đổi các bạn vào nodejs.org để xem bản LTS là bao nhiêu nhé.
Sau đó ta check xem nodejs đã cài thành công hay chưa nhé:
node -v
--->> v22.11.0
npm -v
--->> 10.9.0
Process manager - Supervisor
Trước khi cài đặt ta cùng tìm hiểu qua Process manager là gì nhé.
Khi ở local muốn chạy command nào thì ta chỉ cần mở 1 tab terminal và chạy command đó, ví dụ:
php artisan serve
php artisan queue:work
php artisan reverb:start
Mỗi command chạy trên 1 tab, nhưng nếu ta tắt terminal đi thì các command trên sẽ bị stop, bởi vì các command trên đang chạy ở foreground
, tức là khi ta bấm Enter
để chạy thì command sẽ treo luôn ở terminal, và khi ta tắt terminal thì các command kia sẽ bị stop. Lên server cũng vậy, ta có thể mở nhiều tab terminal, SSH vào server và chạy các command như vậy, nhưng cuối cùng thì cũng đến lúc ta phải tắt máy đi ngủ lúc đó thì terminal bị tắt và toàn bộ các command sẽ bị stop .
Do đó ta cần có process manager để có thể chạy được các command ở background
- chạy ngầm, chúng sẽ liên tục được chạy và ta không phải lo về việc terminal bị tắt nữa .
Và trên Ubuntu thì Supervisor
là một process manager rất được ưa chuộng. Ta tiến hành cài nhé:
sudo apt-get install supervisor
Sau đó ta kiểm tra xem supervisor chạy hay chưa nhen:
service supervisor status
Nginx
Cuối cùng là ta tiến hành cài Nginx (ối dồi ôi cài mệt nghỉ 😝😝)
sudo apt install nginx -y
Cài xong thì ta check version của nginx:
sudo nginx -version
>>>
nginx version: nginx/1.26.0 (Ubuntu)
Sau đó ta check xem Nginx chạy hay chưa nhé:
service nginx status
Từ từ, có lỗi xảy ra 🥹🥹. Nginx báo là cổng 80 đã bị 1 anh bạn nào đó chiếm mất.
Ta check thử xem các cổng nào đang chạy và ai dùng nó nhé:
sudo lsof -i -P -n | grep LISTEN
>>>
systemd 1 root 162u IPv4 6731 0t0 TCP *:22 (LISTEN)
systemd 1 root 164u IPv6 6733 0t0 TCP *:22 (LISTEN)
systemd-r 6567 systemd-resolve 16u IPv4 45719 0t0 TCP 127.0.0.53:53 (LISTEN)
systemd-r 6567 systemd-resolve 18u IPv4 45721 0t0 TCP 127.0.0.54:53 (LISTEN)
sshd 11151 root 3u IPv4 6731 0t0 TCP *:22 (LISTEN)
sshd 11151 root 4u IPv6 6733 0t0 TCP *:22 (LISTEN)
apache2 24224 root 4u IPv6 65825 0t0 TCP *:80 (LISTEN)
apache2 24229 www-data 4u IPv6 65825 0t0 TCP *:80 (LISTEN)
apache2 24230 www-data 4u IPv6 65825 0t0 TCP *:80 (LISTEN)
apache2 24231 www-data 4u IPv6 65825 0t0 TCP *:80 (LISTEN)
apache2 24232 www-data 4u IPv6 65825 0t0 TCP *:80 (LISTEN)
apache2 24233 www-data 4u IPv6 65825 0t0 TCP *:80 (LISTEN)
mysqld 25170 mysql 21u IPv4 70993 0t0 TCP 127.0.0.1:33060 (LISTEN)
mysqld 25170 mysql 23u IPv4 70995 0t0 TCP 127.0.0.1:3306 (LISTEN)
apache2 25487 www-data 4u IPv6 65825 0t0 TCP *:80 (LISTEN)
Ố ồ, thì ra là Apache đã chiếm mất cổng 80.
Giải thích cho các bạn Apache là gì, thì nó cũng là 1 webserver như Nginx vậy, được cài đặt kèm với Ubuntu, và chạy mặc định khi VM start.
Tại sao mình không không dùng Apache luôn, thì lí do là Nginx hiện tại cực kì phổ biến về tính dễ dùng và hiệu năng của nó. Và mình chỉ khuyến khích các bạn dùng những thứ phổ biến, nếu có gặp lỗi cũng sẽ dễ sửa hơn 😘
Âu cây vậy giờ ta tiến hành shutdown Apache đi để chạy Nginx nhé:
sudo service apache2 stop
sudo service nginx start
sudo service nginx status
Khi Webserver được chạy sẽ cho phép ta có khả năng truy cập từ bên ngoài vào server, hay cụ thể là ta có thể truy cập qua trình duyệt.
Các bạn thử mở trình duyệt ở địa chỉ là IP server của các bạn xem nhé. Cách xem IP là các bạn xem ở trên trang quản trị của nhà cung cấp nơi bạn mua server, ví dụ của mình là Digital Ocean thì sẽ như sau:
Chú ý phần IP v4
nhé, chính là nó. Các nơi khác (AWS, Google, Azure,...) chắc chắn có đó, các bạn đừng comment hỏi mình là ở đâu nhé ☺️
Chú ý rằng mình đang dùng Digital Ocean, mặc định họ để VPS "trần" luôn, traffic cho phép vào mọi cổng, nhưng với nhiều cloud provider khác, ví dụ Azure, mặc định họ không cho traffic vào port nào cả mà ta phải tự chỉ định từng port muốn mở, để bảo mật hơn, các bạn chú ý nha. Nếu cần phải làm thì ở bài này các bạn mở cho mình các port sau: 80, 443, 8080, 8081
Âu cây giờ mở trình duyệt ở địa chỉ SERVER_IP
coi xem Nginx lên chưa nha:
Truy cập được rồi mà ủa sao lại show trang của Apache zị nhỉ??? 🤔🤔
À thì ra ở mặc định nginx nó đọc folder /var/www/html
và load các file dạng index.html
hoặc index.nginx-debian.html
ở đó. Ta có thể kiểm chứng bằng cách xem cấu hình mặc định của nginx:
cat /etc/nginx/sites-available/default
>>>
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
Như các bạn thấy thứ tự nó đọc là index.html > index.nginx-debian.html
, mà file index.html
là của Apache.
Ta đơn giản là remove nó đi, nhưng để cho an toàn ta rename nó thôi nha 😁😁 (nhỡ sau này muốn dùng lại)
mv index.html index.html.bk
.bk
viết tắt của backup
Ngay sau đó ta quay lại trình duyệt F5 sẽ thấy trang của Nginx:
Bắt đầu
Ta có thể lưu source code ở bất kì đâu, ở bài này ta chọn luôn /var/www/html
nha
cd /var/www/html
Setup Laravel
Đầu tiên ta tiến hành clone source code:
git clone https://github.com/maitrungduc1410/realtime-chatapp-laravelecho-socketio
cd realtime-chatapp-laravelecho-socketio/
Sau đó ta tiến hành tạo file .env
và thiết lập giá trị:
cp .env.example .env
Thay thế một số mục trong file .env
thành như sau:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=realtime_chatapp
DB_USERNAME=myuser
DB_PASSWORD=myuserpass
VITE_REVERB_HOST="174.138.21.137"
VITE_REVERB_HOST
chính là IP VPS của các bạn.DB_USERNAME
vàDB_PASSWORD
thì tí nữa ta sẽ tạo nha
Tiếp theo ta tiến hành cài dependencies + build Frontend nha:
composer install
npm install
npm run build
Sau đó ta chạy generate key
nhé:
php artisan key:generate
Tiếp theo ta cần migrate
, nhưng trước hết ta cần tạo user + database trong MySQL đã nhé.
mysql -u root -p
create database realtime_chatapp;
CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'myuserpass';
GRANT ALL PRIVILEGES ON realtime_chatapp.* TO 'myuser'@'localhost';
show databases;
--->> In ra:
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| realtime_chatapp |
| sys |
+--------------------+
5 rows in set (0.00 sec)
exit;
Ở trên các bản để ý là sau khi tạo database mình tạo user myuser
với password là myuserpass
, sau đó gán cho user này có toàn quyền truy cập chỉ trong database realtime_chatapp
. Chạy production ta không dùng chỉ 1 user root
nữa nhé.
Note: ở trên lúc tạo user cho database nếu các bạn gặp lỗi your password does not satisfy the current policy requirements
thì ý MYSQL bảo là "password của chúng ta lởm quá đặt cái nào bảo mật hơn đi", thì các bạn cần đặt mật khẩu nào xịn hơn. Các bạn lên trang này tạo nhanh 1 password rồi làm lại nhé.
Sau đó ta tiến hành migrate nhé:
php artisan migrate --seed
Thấy như sau là oke nà 😘:
Sau đó ta tạo app key:
php artisan key:generate
Ổn rồi đó, đến bước này là ta đã có thể xem trực tiếp web của chúng ta như thế nào rồi, ta cùng cấu hình Nginx 1 chút nhé.
sudo nano /etc/nginx/sites-available/default
Ở đó ta thấy có sẵn nội dung mặc định, ta xoá hết đi và thay thế toàn bộ bằng nội dung sau nhé:
server {
listen 80;
listen [::]:80;
root /var/www/html/realtime-chatapp-laravelecho-socketio/public;
index index.php;
server_name _;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_hide_header X-Powered-By;
}
location /reverb {
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header SERVER_PORT $server_port;
proxy_set_header REMOTE_ADDR $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
# trailing slash is important to remove /echo from the url
proxy_pass http://localhost:8080/;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
- Ở trên các bạn để ý rằng
root
ta phải trỏ về folderpublic
vì ở đó ta có file entrypointindex.php
là nơi khởi nguồn cho app Laravel - chú ý đoạn
fastcgi_pass
ở đó ta proxy PHP request vào PHP-FPM (xử lý các request tới app Laravel) - đoạn
location /reverb
để proxy websocket request tới Laravel Reverb Websocket server
Sau đó ta kiểm tra xem cú pháp của file ta vừa thay đổi có đúng không, có lỗi gì không nhé:
sudo nginx -t
--->> in ra:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Oke thì ta tiến hành khởi động lại Nginx nhé:
sudo service nginx restart
Ổn rồi đó ta mở trình duyệt ở địa chỉ là IP server của chúng ta và xem nhé:
Âu cây đã lên rồi đó, nhưng lại bị dính lỗi Permission denied
, đây là 1 lỗi cực kì phổ biến khi deploy ứng dụng Laravel 😂
Lí do thì khá là đơn giản: khi ta truy cập từ trình duyệt, request gửi tới Nginx, nginx forward request vào PHP-FPM, sau đó tới project Laravel của chúng ta, sau đó sẽ được ghi ra file Log, bởi vì Nginx được chạy dưới quyền của user www-data
. Ta có thể kiểm tra bằng cách xem cấu hình của nginx:
cat /etc/nginx/nginx.conf
>>>
user www-data;
worker_processes auto;
worker_cpu_affinity auto;
....
Ở trên ta thấy rằng worker của Nginx chạy với user www-data
, worker chúng là những đứa mà xử lý request của chúng ta 😄
Vậy nên cuối cùng Nginx cần có quyền để ghi vào folder storage
, nhưng folder đó đang được đặt dưới quyền user mà ta đang thực hiện SSH (của mình là root
)
Do đó ta cần đổi lại quyền cho project Laravel của chúng ta nhé, các bạn quay trở lại folder gốc nơi chứa project và chạy command sau:
cd /var/www/html/realtime-chatapp-laravelecho-socketio
sudo chown -R www-data:www-data .
Sau đó quay trở lại trình duyệt, F5 và pằng pằng chíu chíu:
Ta thử đăng kí tài khoản mới, sau đó vào thử gửi vài tin nhắn xem nha
Ta để ý rằng gửi tin nhắn thì Oke, F5 lại thấy lưu vô database rồi, nhưng không có realtime, danh sách user Online không lên, browser console lỗi đỏ lòm:
Cái này là vì ta mới chạy được có Laravel main app à, còn mấy cái là Reverb, workers các thứ chưa lên 😂
Laravel Reverb
Để chạy reverb thì ta sẽ cần dùng tới Supervisor nha, vì nó cần được chạy ở background ấy 😊
Toàn bộ file chạy cho Supervisor sẽ được đặt ở folder /etc/supervisor/conf.d
. Ta chuyển tới folder đó để làm việc nhé:
cd /etc/supervisor/conf.d
Sau đó ta tạo 1 file cấu hình để chạy Laravel echo server:
sudo nano laravel-reverb.conf
Và ta thêm vào nội dung như sau:
[program:laravel_reverb]
command=php artisan reverb:start
user=www-data
directory=/var/www/html/realtime-chatapp-laravelecho-socketio
autostart=true
autorestart=true
stderr_logfile=/var/log/laravel_reverb.err.log
stdout_logfile=/var/log/laravel_reverb.out.log
Sau đó ta "bảo" Supervisor update lại nhé:
sudo supervisorctl reread
sudo supervisorctl update
>>> Thấy in ra
laravel_reverb: available
laravel_reverb: added process group
Mỗi khi ta update lại file cấu hình thì các bạn chạy lại 2 command trên là được nha 😘
Ổn rồi đó, giờ ta quay lại trình duyệt F5 thử xem:
Ta thử mở console, và..... BÙMMM
Vẫn lỗi như vậy???? lí do là sao nhỉ?? 🧐🧐
Lí do là khi trình duyệt gửi request tới địa chỉ IP ở cổng 8080, mà ở cấu hình nginx là ta muốn nó đi qua nginx ở path /reverb
mà, tức là cổng phải chung cổng với app Laravel, tức là cổng 80 🤪
Giờ ta quay lại app Laravel và update .env
:
cd /var/www/html/realtime-chatapp-laravelecho-socketio/
Sửa VITE_REVERB_PORT="80"
là oke nha, sau đó ta build lại frontend:
npm run build
Giờ ta quay lại trình duyêt, F5 và kiểm tra nhé:
Âu cây vậy là ổn rồi đó. Pằng pằng chíu chíu 🎉🎉
Nhưng nếu ta thử mở 2 tab chat thì sẽ không thấy realtime, đơn giản vì ta chưa chạy queue work (không có worker nào hoạt động để xử lý message ở trong queue).
Worker
Quay lại folder /etc/supervisor/conf.d
, các bạn tạo file cấu hình Laravel Horizon nhé:
sudo nano laravel-worker.conf
Và nội dung thì ta để như sau nhé:
[program:laravel_worker]
command=php artisan queue:work
user=www-data
directory=/var/www/html/realtime-chatapp-laravelecho-socketio
autostart=true
autorestart=true
stderr_logfile=/var/log/laravel_worker.err.log
stdout_logfile=/var/log/laravel_worker.out.log
Sau đó ta lại "nhắc" Supervisor update lại nhé:
sudo supervisorctl reread
sudo supervisorctl update
>>>
laravel_worker: available
laravel_worker: added process group
Sau đó ta quay trở lại trình duyệt mở 2 tab và thử chat là thấy đã Realtime được rồi nhé
Vậy là ứng dụng chat của ta đã được cài đặt thành công. Pằng pằng chíu chíu 🚀🚀
Task Scheduling (cronjob)
Ở ứng dụng chat này mình có 1 chức năng nữa là cứ đều đặt thì sẽ có 1 tin nhắn thông báo từ Bot gửi tới để hướng dẫn user sử dụng các tính năng chat
Và để làm được việc này thì ta cần chạy thêm 1 process nữa để chạy Scheduled Task (hay còn gọi là CronJob) cho Laravel nhé. Nhưng giờ ta không dùng supervisor nữa mà ta dùng luôn Crontab có sẵn của Ubuntu để chạy nha.
Các bạn chạy command sau:
sudo crontab -u www-data -e
Khi được hỏi dùng trình editor nào thì ta chọn nano
cho tiện
Tiếp đó ở màn hình nhập, các bạn thêm vào cuối file giá trị như sau:
* * * * * cd /var/www/html/realtime-chatapp-laravelecho-socketio && php artisan schedule:run
Ở trên ta thiết lập một crontab chạy mỗi phút
Màn hình cấu hình Crontab trông giống như sau nhé các bạn
Sửa xong thì ta lưu lại, terminal báo như sau là oke nà:
crontab: installing new crontab
Rồi ta quay lại trình duyệt, F5, và ngồi chờ nha 😂. Và khi nào tới đủ 1 phút ta sẽ thấy Bot thông báo:
Và cứ sau 1 phút thì lại có 1 thông báo như vậy 😎
Đến đây là ta đã có 1 ứng dụng Laravel đầy đủ hoàn chỉnh về mặt chức năng rồi đó 😘😘
HTTPS
Và đã chạy production thì thường là ta sẽ cần tới HTTPS thì mới đủ xịn xò và tăng tính bảo mật cho website của chúng ta.
Nếu các bạn chỉ search google: How to get SSL certificate thì khả năng cao là sẽ gặp phải nhiều tutorial họ hướng dẫn cách dùng self-signed certificate
, tức là chứng chỉ mà ta "tự kí", những loại chứng chỉ này khi chạy ở các tình duyệt hiện đại sẽ bị báo là chứng chỉ fake, tất nhiên đó không phải là thứ ta muốn đúng không nào 😉
Có một cách khác rất đơn giản và mọi người thường làm là lấy chứng chỉ HTTPS Free bằng certbot
và Lets Encrypt. Và ta sẽ dùng cách này nhen
Điều kiện cần là các bạn cần phải có 1 domain name nhé, vì Lets Encrypt yêu cầu phải có domain name chứ không dành cho IP.
Các bạn bỏ ra vài chục hoặc 1-2 trăm nghìn VND lên Goddady (Trang trên miền lớn nhất TG), mua 1 cái domain lởm lởm để học tập nhé. Nên mua domain ở các nhà cung cấp lớn thế này vì những công việc như cập nhập DNS, nameserver sẽ rất là nhanh và tiện. Mình đã và đang trải nghiệm cả những nhà cung cấp của VN (dành cho tên miền .vn
, và chất lượng thì thật sự là "ba chấm" 😁 )
Sau khi các bạn có tên miền, thì ta vào trang quản trị tên miền và trỏ về IP server của chúng ta là được nhé. Ví dụ ở đây tên miền của mình là jamesisme.com
và màn hình quản trị trên Cloudflare sẽ như sau nhé:
Mình dô tạo 1 bản ghi A, với subdomain là chat
, tức là tên đầy đủ là chat.jamesisme.com
, trỏ về IP là IP VPS của chúng ta
Bạn nào quen rồi thì có thể dùng CNAME các kiểu, miễn sao các bạn trỏ về cho đúng IP, và ta dùng nó nhất quán với cấu hình nginx 😊
Ngay sau đó ta quay trở lại trình duyệt, truy cập ở địa chỉ tên miền của chúng ta là có thể thấy kết quả ngay nha:
Chú ý rằng hiện tại thì Chrome nó có cái mặc định redirect HTTP -> HTTPS, nên ta có thể gặp lỗi, vì đoạn này ta vẫn chưa có HTTPS:
Sau đó kể cả ta có tự tay gõ http://chat.jamesisme.com
vào trình duyệt, thì nó vẫn cứ cache và dùng HTTPS, cay lắm 😂
Để khắc phục điều này thì ta mở Chrome ở địa chỉ chrome://net-internals/#hsts
và Delete domain security policies
> cho domain của ta đi:
Sau đó ta truy cập lại là oke, tự tay gõ http://...
vào trình duyệt là được (khuyến khích dùng tab ẩn danh) 💪💪
Tiếp tới là ta cần tạo chứng chỉ HTTPS với certbot nhé. Đầu tiên là ta cần cài certbot
, các bạn chạy command sau:
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Sau đó chúng ta sửa lại file cấu hình Nginx một chút nhé:
sudo nano /etc/nginx/sites-available/default
Các bạn chỉ cần sửa lại duy nhất đoạn server_name
với giá trị như sau nhé:
server_name chat.jamesisme.com;
Ở đây ý bảo là ta có thể truy cập ứng dụng Laravel bằng 2 địa chỉ bên trên. Sau đó ta khởi động lại Nginx nhé:
sudo service nginx restart
Sau đó ta tiến hành tạo chứng chỉ HTTPS nhé:
sudo certbot --nginx -d chat.jamesisme.com
Ở trên các bạn thay thế tên domain của các bạn vào nhé.
Chú ý ở cuối quá trình khi được hỏi có muốn tự động redirect HTTP sang HTTPS không thì các bạn chọn có (option 2) nhé. Vì thường ta muốn user truy cập ứng dụng của ta ở HTTPS thôi mà 😘
Ngay sau đó chúng ta quay lại trình duyệt load lại là sẽ thấy app của chúng ta đã có HTTPS nhé. Các bạn thử đăng nhập và test thử nhé.
Và.... BÙM, vẫn gặp lỗi 🥹🥹
Thì ra giờ không dùng domain nữa thì phải phải update .env
chút và build lại frontend 😁
Ta sửa lại 3 biến sau ở .env
:
VITE_REVERB_HOST="chat.jamesisme.com"
VITE_REVERB_PORT="443"
VITE_REVERB_SCHEME="https"
Nhớ thay tên domain của các bạn vào
VITE_REVERB_HOST
cho đúng nha
Sau đó ta build lại frontend:
npm run build
Sau đó ta quay lại trình duyệt F5 là lên HTTPS + realtime ngon luôn:
Pòm pòm chíu chíu 🎉🎉🎉🎉🎉
Đóng máy
Như các bạn thấy để chạy được một ứng dụng Laravel đầy đủ ở production ta cần phải setup mệt nghỉ, cộng thêm là debug khi gặp lỗi khá là hack não 😂
Giải pháp hiện đại hơn mình khuyên là dùng Docker cho nhàn, các bạn xem bài của mình ở đây, gọn hơn rấtttttttt nhiều: https://viblo.asia/p/deploy-ung-dung-docker-laravel-realtime-chat-aWj53WJ156m 😘
Một trong những điều mình thấy hạnh phúc khi làm việc với mỗi project đó là: từ quá trình viết design, viết code, tới khi deploy thành công ra production thấy đứa con cưng của mình chạy thành công cảm giác thật là sung sướng. 😘
Bài đến đây quá là dài rồi. Nếu các bạn có gì thắc mắc thì để lại comment cho mình nhé. Hẹn gặp lại các bạn ở những bài sau 👋👋
All rights reserved