Để chạy một dự án frontend sử dụng reactJs trên server chúng ta sẽ sử dụng PM2 để quản lý các ứng dụng Node.js. Pm2 giúp bạn khởi chạy, giám sát và tự động khởi động lại các ứng dụng Node.js một cách dễ dàng và hiệu quả.
Cài đặt pm2 sử dụng npm hoặc yarn
npm install pm2 -g
yarn global add pm2
Chạy dự án với pm2 thông qua file cấu hình.
// ecosystem.config.js
module.exports = {
apps: [
{
name: "demo1",
cwd: "/var/www/demo1/current",
script: "yarn",
args: "start",
env: {
PORT: 3001,
}
},
{
name: "demo2",
cwd: "/var/www/demo2/current",
script: "yarn",
args: "start",
env: {
PORT: 3002,
}
}
]
}
Run dự án bằng pm2
// Run project via config file
pm2 start ecosystem.config.js
// List project
pm2 list
// Restart project
pm2 restart demo1
// Check log
pm2 logs demo1
// Reload don't downtime
pm2 reload demo1
// Delete
pm2 delete demo1
Sau khi chạy được dự án trên server cần config nginx cho dự án.
Config nginx sử dụng load balancing
upstream demo_web_upstream {
server 127.0.0.1:3001;
keepalive 64;
}
server {
listen 81;
#server_name 10.0.11.22:81;
server_name demo.com;
location / {
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://demo_web_upstream/;
proxy_redirect off;
proxy_read_timeout 240s;
}
location ^~ /apple-app-site-association {
auth_basic off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://demo_web_upstream/apple-app-site-association;
proxy_redirect off;
proxy_read_timeout 240s;
}
location ^~ /.well-known/assetlinks.json {
auth_basic off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://demo_web_upstream/.well-known/assetlinks.json;
proxy_redirect off;
proxy_read_timeout 240s;
}
}
server {
server_name demo.com;
return 301 https://demo.com$request_uri;
}
server {
listen 80;
server_name demo.com;
#satisfy any;
#allow 153.125.130.77;
#deny all;
#auth_basic "Private Property";
#auth_basic_user_file /etc/nginx/.htpasswd;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://localhost:3000;
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;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
upstream react_web_upstream {
server 127.0.0.1:3000;
keepalive 64;
}
server {
index index.php index.html;
error_log /var/log/nginx/demo-error.log;
access_log /var/log/nginx/demo-access.log;
root /home/ftpuser/ftp/public_html;
client_max_body_size 50M;
server_name demo.com;
# Setup php nginx cho ftp user
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php8.2-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;
}
location / {
auth_basic "Authorized personnel only.";
auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
index index.html index.htm index.php;
try_files $uri $uri/ /index.php?$query_string;
}
# Setup nginx cho react site
# Rewrite url fore react site
location /app {
rewrite /app/(.*) /$1 break;
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Ssl on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://react_web_upstream/$1;
proxy_redirect off;
proxy_read_timeout 240s;
}
location ~ ^/(login|forgot-password) {
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Ssl on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://react_web_upstream/$1;
proxy_redirect off;
proxy_read_timeout 240s;
}
# Show file from other root directory
location ^~ /.well-known/assetlinks.json {
auth_basic off;
alias /var/www/html/demo-web/public/.well-known/assetlinks.json;
autoindex off;
}
location ^~ /apple-app-site-association {
auth_basic off;
alias /var/www/html/demo-web/public/apple-app-site-association;
autoindex off;
}
location /general {
rewrite /general/(.*)/(.*) /$1/$2 break;
if ($2 != "privacystatement") {
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
}
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Ssl on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://react_web_upstream/general/$1/$2;
proxy_redirect off;
proxy_read_timeout 240s;
}
# Setup static file
location /_next/static {
alias /var/www/html/demo-web/.next/static/;
autoindex off;
}
# Setup next image
location /_next/image {
rewrite /_next/image?url=(.*) /_next/image?url=$1 break;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Ssl on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://react_web_upstream;
proxy_redirect off;
proxy_read_timeout 240s;
}
location /api {
rewrite /api/(.*)/(.*) /api/$1/$2 break;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Ssl on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://react_web_upstream;
proxy_redirect off;
proxy_read_timeout 240s;
}
location /_next/data {
rewrite /_next/data/(.*)/(.*) /_next/data/$1/$2 break;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Ssl on;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://react_web_upstream;
proxy_redirect off;
proxy_read_timeout 240s;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/demo.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/demo.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = demo.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name demo.com;
return 404; # managed by Certbot
}
Config 2 trang web chạy cùng 1 domain, một trang chạy php, trang còn lại chạy bằng react. trang chạy bằng php là trang chính, trang chạy bằng react dùng pass proxy, alias lại các thư mục static để chạy.
Mở và chặn post
sudo ufw allow 81
sudo ufw deny 81
// Check allow and listen post
sudo lsof -i -P -n | grep LISTEN