PHP và NodeJS sống chung một nhà

Discussion in 'Linux - PHP - Python - C# - Java' started by sad_logger, Jun 11, 2019.

Tags:
  1. sad_logger

    sad_logger Sơ Nhập Giang Hồ

    Cấu hình này em đang sử dụng, nếu có gì sai sót, anh em chỉ bảo để em fix lại hoặc tối ưu thêm:
    0. Bài toán
    test1.com => site chính sử dụng php
    sub1.test1.com => xử lý vào ra sử dụng nodejs
    sub2.test1.com => xử lý vào ra sử dụng nodejs
    ...
    1. Cloudflare:
    thêm các sub domain tương tự như đối với sub1
    [​IMG]
    **note**: thậm chí các ipv4 có thể khác nhau nếu như có nhiều vps


    2. apache/nginx:
    Cài đặt apache hoặc nginx, ở đây em dùng apache
    Đối với apache, cần kích hoạt chế độ proxy (với nginx thì không cần)
    Code:
    sudo a2enmod proxy
    sudo a2enmod proxy_http
    sudo a2enmod proxy_balancer
    sudo a2enmod lbmethod_byrequests
    Q1: Tại sao app chạy rồi mà ta vẫn phải cần apache hoặc nginx?
    Vì: apache hoặc nginx là phần mềm web server, có tính toán sẵn các cơ chế cân bằng, giúp vận hành website của một cách ổn định so với việc chạy nodejs hoặc php 1 cách thẳng thừng, nhất là đối với nodejs, 1 vài đánh giá trên mạng nói rằng tích hợp apache cho phép nodejs xử lý các truy nhập cùng lúc tốt hơn.

    Q2: Tại sao lại cấu hình proxy cho apache hay nginx?
    Vì: Đối với các phiên bản hiện tại của apache hay nginx, chưa có cách cấu hình nào để tích hợp với ứng dụng nodejs ngoài chế độ proxy.

    Q3: Chế độ proxy này hiểu như thế nào?
    Hiểu là: khi user tạo 1 request (req) A hợp lệ kết nối tới vps, apache phụ trách phân tích req A này và gửi 1 req B khác tới nodejs, sau đó trả lại thông tin cho user. Các headers trong req A và req B có sự ràng buộc, ví dụ ở A: req.headers.host = 'sub1.test1.com', ở B: req.headers.host = 'localhost' còn req.headers['x-forwarded-host']= 'sub1.test1.com'.
    Tuy nhiên khi sử dụng nginx, tôi có thể cấu hình để req A và req B giống nhau 1 cách tương đối: ví dụ như ở đây reqA.header.host= reqB.header.host, ip của user có thể lấy trực tiếp trên headers của reqB 'X-Real-IP' thông qua cấu hình:
    Code:
    location / {
    proxy_pass http://localhost:<port_của_app>/;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # .....
    }
    
    3. Chạy thử
    Cài đặt nodejs, php ... và chạy thử trên localhost, nếu như vps ko có vncserver, có thể cài đặt apache và cấu hình nhanh, rồi vào http://<ip_của_vps>/ để kiểm thử
    Code:
    <VirtualHost *:80>
    ServerName <ip_của_vps>
    ServerAlias <ip_của_vps>
    ProxyRequests on
    ProxyPass / http://localhost:<port_của_app>/ #có thể thay localhost bằng 127.0.0.1
    </VirtualHost>
    
    Đối với app chạy php, chưa vội thiết lập dạng Directory, cứ thiết lập kiểu proxy như trên, và "cd <thư_mục_app>", rồi chạy app dạng "php artisan serve".
    Đối với app chạy nodejs, "cd <thư_mục_app>", rồi chạy "node <file_app.js>"

    4. Triển khai mã:
    mã php để ở: /var/www/html/app_php_1/
    mã nodejs để ở /home/app1/
    Với php, cấu hình dạng Directory, không cần chạy app, chỉ cần chạy apache, app tự bật
    Với nodejs, cấu hình dạng ProxyPass, do đó app phải chạy sẵn, sử dụng npmjs[dot]com/package/forever để nodejs chạy dạng service
    5. Cấu hình apache:
    Code:
    sudo nano /etc/apache2/sites-available/cau_hinh_1.conf
    
    Nội dung file: cau_hinh_1.conf
    Code:
    <VirtualHost *:80>
    <Directory /var/www/html/app_php_1/>
    Options FollowSymlinks
    AllowOverride All
    Require all granted
    </Directory>
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    <Directory /var/www/html/app_php_1/>
    RewriteEngine on
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*) index.php [PT,L]
    </Directory>
    DocumentRoot /var/www/html/app_php_1
    ServerName test1.com
    ServerAlias test1.com
    </VirtualHost>
    <VirtualHost *:80>
    ServerName test1.com
    ServerAlias sub1.test1.com
    ProxyRequests on
    ProxyPass / http://localhost:<port_của_app>/
    </VirtualHost>
    <VirtualHost *:80>
    ServerName test1.com
    ServerAlias sub2.test1.com
    ProxyRequests on
    ProxyPass / http://localhost:<port_của_app>/
    </VirtualHost>
    
    Kích hoạt cau_hinh_1.conf, khởi động lại apache
    Code:
    cd /etc/apache2/sites-available/
    sudo a2ensite cau_hinh_1.conf
    sudo a2enmod rewrite
    sudo systemctl restart apache2.service
    
    Tuy cấu hình giống nhau ở ServerAlias sub1.test1.com và sub2.test1.com, nhưng trong app của nodejs, ta tách ra:
    Cách 1: tách theo path url, ví dụ sub1.test1.com/sub1/...., sub2.test1.com/sub2/....
    Code:
    // in app.js
    app.use('/sub1', require('./routes/sub1.js'));
    app.use('/sub2', require('./routes/sub2.js'));
    
    // in ./routes/sub1.js
    router.use('*', function(req, res, next){
    if(req.headers['x-forwarded-host']!= 'sub1.test1.com') res.redirect(301, 'https://test1.com/');
    else next();
    })
    
    // in ./routes/sub2.js
    router.use('*', function(req, res, next){
    if(req.headers['x-forwarded-host']!= 'sub2.test1.com') res.redirect(301, 'https://test1.com/');
    else next();
    })
    Cách 2: Không tách theo path url
    Code:
    // in app.js
    app.use('*', function(req, res, next){
    if(req.headers['x-forwarded-host']!= 'sub1.test1.com') {
    // luật logic 1 ...
    res.end('sub1 here');
    } else if(req.headers['x-forwarded-host']!= 'sub2.test1.com') {
    // luật logic 2 ...
    res.end('sub2 here');
    } else next();
    });
    
    6. Lưu ý:
    mặc định apache triển khai mã từ: /var/www/html/, ta để mã php ở /var/www/html/app_php_1/,
    nên ở thư mục /var/www/html/, có thể tạo nhanh file index.php để tránh các truy cập bất cần đời như http:// <ip_của_vps> /
    Code:
    <?php
        header("HTTP/1.1 301 Moved Permanently");
        header("Location: https://google.com/");
    ?>
    
     
    Last edited: Jun 11, 2019