Cách sử dụng Nginx làm Reverse Proxy cho Node.js Server – Phần 1

EminelEminel
10 min read

Node.js là công cụ hàng đầu để tạo ứng dụng server bằng JavaScript, cung cấp cả chức năng của web server và application server.

Tuy nhiên, Node.js có một số hạn chế và lỗ hổng có thể gây ra các vấn đề về hiệu suất và thậm chí là sự cố hệ thống. Ví dụ, các ứng dụng web dựa trên Node dễ bị chậm trong việc thực thi mã và gặp sự cố do các hoạt động IO-bound hoặc do tăng trưởng lưu lượng truy cập nhanh chóng. Node.js cũng đôi khi gặp khó khăn trong việc phục vụ nội dung tĩnh như hình ảnh và tệp JavaScript cũng như cân bằng tải giữa các server.

May mắn thay, chúng ta có thể cache nội dung tĩnh, reverse proxy và cân bằng tải giữa nhiều application server, và quản lý tranh chấp cổng giữa các client bằng cách sử dụng Nginx. Điều này làm cho Nginx trở thành một công cụ tuyệt vời để tăng hiệu suất của Node.js.

Trong hướng dẫn này, Tôi sẽ chỉ các bạn cách reverse proxy(Đọc thêm bài viết về proxy để hiểu hơn) một ứng dụng Node.js với Nginx. Chúng ta sẽ xây dựng một ứng dụng Node.js đơn giản chạy trên port 3000 và sử dụng Nginx như một reverse proxy server cho ứng dụng Node.js. Ứng dụng sẽ được truy cập thông qua một domain name:

Để tiện theo dõi bài viết, bạn cần chuẩn bị:

  • Hiểu biết về cách web, web server và web browser giao tiếp với nhau

  • Kiến thức cơ bản về JavaScript, Node.js, lập trình bất đồng bộ (asynchronous programming), mạng máy tính (computer networking) và DNS

  • Một máy ảo Ubuntu(VPS) của một trong các nhà cung cấp AWS, Google…, mở các port 22, 80, 443.

  • Node.js đã được cài đặt trên máy chủ của bạn

  • Một domain name từ một DNS registrar

  • Trình soạn thảo (vim, nano) đã được cài đặt máy chủ của bạn

Server và web server là gì?

Server là một máy tính giao tiếp với các máy tính khác để cung cấp thông tin theo yêu cầu của các máy tính này. Các máy tính này, còn được gọi là client, kết nối với server thông qua mạng cục bộ (LAN) hoặc mạng diện rộng (WAN).

Web server là một server trên internet sử dụng giao thức HTTP (Hypertext Transfer Protocol) để nhận các request từ client, chẳng hạn như trình duyệt. Sau đó nó trả về một HTTP response, có thể là một trang HTML hoặc dữ liệu ở định dạng JSON, như được sử dụng trong các API call.

Web server, cần thiết cho việc trao đổi dữ liệu, sử dụng HTTP để giao tiếp client-server. Chúng bao gồm cả phần cứng và phần mềm, rất quan trọng trong phát triển web. Phần mềm chịu trách nhiệm giải mã URL và quản lý quyền truy cập của người dùng vào các tệp được lưu trữ.

Nginx là gì?

Theo tài liệu, Nginx (đọc là “engine X”) là một HTTP và reverse proxy server, mail proxy server, và proxy server TCP/UDP chung, ban đầu được viết bởi Igor Sysoev.

Nginx được sử dụng cho nhiều tác vụ khác nhau giúp cải thiện hiệu suất của Node:

  • Reverse proxy server: Khi lưu lượng truy cập vào ứng dụng tăng lên, cách tốt nhất để cải thiện hiệu suất là sử dụng Nginx làm reverse proxy server phía trước Node.js server để cân bằng tải giữa các server. Đây là trường hợp sử dụng chính của Nginx trong các ứng dụng Node.js.

  • Stateless load balancing: Tính năng này cải thiện hiệu suất và giảm tải cho các dịch vụ backend bằng cách chuyển các yêu cầu client đến bất kỳ server nào có quyền truy cập vào tệp được yêu cầu.

  • Cache static contents: Phục vụ nội dung tĩnh trong một ứng dụng Node.js và sử dụng Nginx làm reverse proxy server có thể tăng gấp đôi hiệu suất của ứng dụng lên tới 1,600 yêu cầu mỗi giây.

  • Implement SSL/TLS và HTTP/2: Với sự chuyển đổi gần đây sang việc sử dụng SSL/TLS để bảo mật các tương tác của người dùng trong ứng dụng Node.js, Nginx cũng hỗ trợ các kết nối HTTP/2.

  • Performance tracking: Bạn có thể theo dõi hiệu suất tổng thể của ứng dụng Node.js trong thời gian thực bằng các chỉ số trên bảng điều khiển trực tiếp của Nginx.

  • Scalability: Tùy thuộc vào loại tài nguyên bạn đang phục vụ, bạn có thể tận dụng các tính năng load balancing HTTP, TCP, và UDP đầy đủ của Nginx để mở rộng ứng dụng Node.js.

Nginx hiện hỗ trợ bảy ngôn ngữ lập trình(Tính đến lúc tôi viết bài này): Go, Node.js, Perl, PHP, Python, Ruby, và Java Servlet Containers (đây là một module thử nghiệm). Nó cho phép bạn chạy các ứng dụng viết bằng các ngôn ngữ khác nhau trên cùng một server.

Bây giờ, chúng ta sẽ thiết lập ứng dụng Node.js của mình.

Tạo một Node.js application

Đối với ứng dụng Node.js đơn giản này, chúng ta sẽ xây dựng một máy chủ Node.js với mô-đun HTTP do Node.js cung cấp. Hãy bắt đầu bằng cách tạo một thư mục và khởi tạo dự án trên terminal:

mkdir nginx_server_project
cd nginx_server_project
npm init -y

Đoạn mã trên sẽ tạo thư mục nginx_server_project và chuyển vào thư mục đó. Sau đó, chúng ta khởi tạo một ứng dụng Node.js với npm, sử dụng cờ -y để đặt câu trả lời mặc định là “yes” cho tất cả các câu hỏi.

Bước tiếp theo là tạo tệp server.js chứa mã nguồn cho ứng dụng của chúng ta. Mở nó bằng bất kỳ IDE hoặc trình soạn thảo văn bản nào bạn chọn:

touch server.js
nano server.js

Bây giờ là lúc để xây dựng và khởi động server. Hãy định nghĩa hai subdomain bổ sung để kiểm tra rằng ứng dụng của chúng ta hoạt động hoàn toàn ổn định:

const http = require("http");
const server = http.createServer((req, res) => {
  const urlPath = req.url;
  if (urlPath === "/overview") {
    res.end('Welcome to the "overview page" of the nginX project');
  } else if (urlPath === "/api") {
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(
      JSON.stringify({
        product_id: "xyz12u3",
        product_name: "NginX injector",
      })
    );
  } else {
    res.end("Successfully started a server");
  }
});
server.listen(3000, "localhost", () => {
  console.log("Listening for request");
});

Chúng ta đã tạo một server với module HTTP của Node.js được nhập vào bằng hàm require trong đoạn code trên. Trong server, chúng ta sẽ hiển thị hai response khác nhau tùy thuộc vào route hiện tại. Hai route này là /overview/api.

Trên subdomain /overview, chúng ta sẽ hiển thị một đoạn text thuần túy, trong khi trên /api, chúng ta sẽ hiển thị một đối tượng JSON. Ứng dụng trên sẽ được truy cập qua địa chỉ Public IPv4 của máy ảo của bạn — ví dụ, 34.211.115.4 trên port 3000.

Bây giờ khi ứng dụng Node server đã sẵn sàng, hãy cài đặt Nginx và cấu hình nó.

Cài đặt Nginx

Chúng ta sẽ cài đặt Nginx bằng trình quản lý gói mặc định cho hệ điều hành dựa trên Debian, gọi là apt. Nginx cũng có sẵn trên hầu hết các hệ điều hành trong các kho lưu trữ mặc định của chúng.

Trước khi cài đặt Nginx, hãy chắc chắn rằng bạn đã cài đặt các yêu cầu cần thiết cho hệ điều hành Ubuntu. Tiếp theo, chúng ta sẽ cấu hình Nginx dựa trên các yêu cầu cụ thể của dự án, và sau đó sẵn sàng triển khai.

Sử dụng lệnh sau để cài đặt Nginx:

sudo apt update
sudo apt install nginx

Sau khi cài đặt xong kiểm tra Nginx đã hoạt động chưa

sudo service nginx status

// kết quả như sau
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2025-02-28 08:46:24 +07; 7h ago
       Docs: man:nginx(8)
    Process: 393 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 458 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
   Main PID: 463 (nginx)
      Tasks: 13 (limit: 19104)
     Memory: 14.6M

Cấu hình Nginx

Đểginx có thể chuyển hướng đến ứng dụng Node.js đang lắng nghe trên port 3000, trước tiên chúng ta cần bỏ liên kết cấu hình mặc định của Nginx và sau đó tạo một cấu hình mới để sử dụng cho ứng dụng Node.js của chúng ta.

Để bỏ liên kết cấu hình mặc định của Nginx, chúng ta có thể sử dụng lệnh sau:

sudo unlink /etc/nginx/sites-available/default

Cấu hình Nginx được lưu trữ trong thư mục /etc/nginx/sites-available. Để tạo một cấu hình mới, chúng ta hãy chuyển đến thư mục này và tạo một tệp cấu hình trỏ đến server Node.js của chúng ta:

cd /etc/nginx/sites-available
touch myserver.config

Sau khi thay đổi thư mục đến /etc/nginx/sites-available, lệnh thứ hai sẽ tạo một tệp cấu hình Nginx có tên myserver.config.

Tiếp theo, mở file myserver.config

sudo nano /etc/nginx/sites-available/myserver.config

Viết code theo mẫu sau:

#The Nginx server instance
server{
    listen 80;
    server_name wach.quest;
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        # location /overview {
        #     proxy_pass http://127.0.0.1:3000$request_uri;
        #     proxy_redirect off;
        # }
    }
}

Cấu hình trên yêu cầu Nginx lắng nghe trên cổng 80 của your-domain.com. Dấu / là Uniform Resource Identifier (URI) của chúng ta với các thuộc tính sau:

  • proxy_set_header: Thiết lập header host thành header của máy chủ Nginx.

  • proxy_pass HTTP: Chỉ dẫn Nginx chuyển tiếp tất cả các request phù hợp với mẫu location đến một upstream server (máy chủ backend)

  • proxy_http_version: Chuyển đổi kết nối đến HTTP 1.1.

  • proxy_set_header Upgrade: Chuyển đổi kết nối proxy thành loại Upgrade vì WebSockets chỉ giao tiếp trên các kết nối đã nâng cấp.

  • proxy_set_header Connection: Đảm bảo giá trị header kết nối là Upgrade.

Lưu các thay đổi và thoát tệp bằng cách nhấn tổ hợp phím ctrl + x. Sau đó có 1 hộp thoại hỏi bạn có muốn lưu các thay đổi hay không bạn chọn yes(y).(lưu ý đây là tôi đang sử dụng trình soạn thảo nano)

Tiếp theo, hãy kích hoạt file trên bằng cách tạo một symbolic link từ nó đến thư mục sites-enabled, nơi mà Nginx đọc trong quá trình khởi động:

sudo ln -s /etc/nginx/sites-available/myserver.config /etc/nginx/sites-enabled/

Server hiện đã được kích hoạt và cấu hình để trả về các response cho các request dựa trên port listen và đường dẫn location.

Bây giờ đã đến lúc khởi động cả Node.js application và dịch vụ Nginx để kích hoạt các thay đổi gần đây. Nhưng trước tiên, hãy kiểm tra trạng thái của Nginx để xác nhận rằng cấu hình đang hoạt động đúng cách:

sudo nginx -t

Đầu ra khi chạy lệnh trên sẽ trông như thế này:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Kết quả đầu ra ở trên xác nhận rằng cấu hình của chúng ta đã thành công. Tiếp theo, khởi động lại Nginx để kích hoạt các thay đổi của bạn:

sudo service restart nginx

Khi Nginx khởi động lại, hãy cho phép truy cập đầy đủ thông qua firewall của Nginx:

sudo ufw allow 'Nginx Full'

Tiếp theo, điều hướng đến thư mục của ứng dụng Node.js:

cd ~/nginx_server_project

Khởi động ứng dụng máy chủ Node.js bằng lệnh sau:

node server.js

Mở trình duyệt và truy cập vào ứng dụng Node.js sử dụng your-domain.com:

Tiếp theo, trên trình duyệt chúng ta truy cập vào your-domain.com/overview.

Để kiểm tra xem các đường dẫn còn lại của node.js server của chúng ta có hoạt động hay không, trên trình duyệt chúng ta truy cập vào your-domain.com/api.

Còn tiếp…

0
Subscribe to my newsletter

Read articles from Eminel directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Eminel
Eminel

Hello, my name is Eminel a software engineer specializing in scalable software architecture, microservices, and AI-powered platforms. Passionate about mentoring, performance optimization, and building solutions that drive business success.