Triển khai ứng dụng ASP.NET Core lên Web Server Nginx trên Ubuntu

Điều kiện cần:

Cài đặt .NET 5 trên Ubuntu

  • Kiểm tra phiên bản hệ điều hành Ubuntu:
    $ lsb_release -a
    # Output:
    No LSB modules are available.
    Distributor ID:	Ubuntu
    Description:	Ubuntu 20.04.2 LTS
    Release:	20.04
    Codename:	focal
  • Tương ứng với phiên bản hệ điều hành (bản ở ví dụ trên là 20.04) Ubuntu thực hiện lệnh sau:
    $ wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
    $ sudo dpkg -i packages-microsoft-prod.deb
    $ sudo apt update
    $ sudo apt install apt-transport-https
    $ sudo apt install dotnet-sdk
  • Kiểm tra danh sách .NET SDK đã được cài đặt thành công hay không sử dụng lệnh sau:
    $ dotnet --list-sdks
    # Output:
    3.1.409 [/usr/share/dotnet/sdk]
    5.0.301 [/usr/share/dotnet/sdk]
  • Kiểm tra phiên bản sử dụng mặc định của .NET SDK:
    $ dotnet --version
    # Output:
    5.0.301
  • Tạo ứng dụng ASP.NET Core:
    $ dotnet new mvc -o AspNetCoreApp

Cấu hình máy chủ Proxy đảo ngược

Proxy đảo ngược là một thiết lập phổ biến để cung cấp các ứng dụng Web động. Một Proxy đảo ngược chấm dứt yêu cầu của http và chuyển tiếp đến ứng dụng ASP.NET Core.

Sử dụng Proxy đảo ngược

Kestrel rất tuyệt vời để cung cấp nội dung động từ ASP.NET Core. Tuy nhiên, khả năng phục vụ web không phong phú về tính năng như các máy chủ như IIS, Apache hoặc Nginx. Máy chủ proxy ngược có thể giảm tải công việc như cung cấp nội dung tĩnh, yêu cầu bộ nhớ đệm, yêu cầu nén và kết thúc HTTPS từ máy chủ HTTP. Máy chủ proxy ngược có thể nằm trên một máy chuyên dụng hoặc có thể được triển khai cùng với máy chủ HTTP.
Với mục đích của hướng dẫn này, một phiên bản Nginx duy nhất được sử dụng. Nó chạy trên cùng một máy chủ, cùng với máy chủ HTTP. Dựa trên các yêu cầu, một thiết lập khác có thể được chọn.
Vì các yêu cầu được chuyển tiếp bằng proxy ngược, hãy sử dụng Phần mềm Trung gian Tiêu đề Chuyển tiếp từ gói Microsoft.AspNetCore.HttpOverrides. Phần mềm trung gian cập nhật Request.Scheme, sử dụng tiêu đề X-Forwarded-Proto, để các URI chuyển hướng và các chính sách bảo mật khác hoạt động chính xác.
Phần mềm trung gian được chuyển tiếp Headers phải chạy trước phần mềm trung gian khác. Thứ tự này đảm bảo rằng phần mềm trung gian dựa vào thông tin tiêu đề được chuyển tiếp có thể sử dụng các giá trị tiêu đề để xử lý. Để chạy Phần mềm trung gian đầu trang được chuyển tiếp sau khi chẩn đoán và xử lý lỗi phần mềm trung gian, hãy xem thứ tự Phần mềm trung gian dành cho đầu trang được chuyển tiếp.
Gọi phương thức UseForwardedHeaders ở đầu Startup.Configure trước khi gọi phần mềm trung gian khác. Định cấu hình phần mềm trung gian để chuyển tiếp các tiêu đề X-Forwarded-ForX-Forwarded-Proto:

using Microsoft.AspNetCore.HttpOverrides;
//...
public class Startup
{
  public void ConfigureServices(IServiceCollection services)
  {
    //...
    services.Configure<ForwardedHeadersOptions>(options =>
      {
          options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
          options.ForwardLimit = 2;
          options.ForwardedForHeaderName = "Header_Name_Used_By_Proxy_For_X-Forwarded-For_Header";
          options.ForwardedProtoHeaderName = "Header_Name_Used_By_Proxy_For_X-Forwarded-Proto_Header";
      });
    //...
  }
}

Xuất bản và chạy Ứng dụng Web ASP.NET Core

Nếu bạn đã có ứng dụng ASP.NET rồi, bạn nên đưa toàn bộ mã nguồn bạn viết lên một hệ thống quản lý phiên bản mã nguồn (source control) Github chẳng hạn, sau đó tải mã nguồn về máy hoặc VPS của bạn bằng cách sử dụng lệnh:

$ sudo git clone https://github.com/your-account/your-project.git
  • Sau khi viết mã lệnh và kiểm thử xong ứng dụng ASP.NET Core, để xuất bản ứng dung ASP.NET Core sử dụng lệnh sau:
    $ cd ./AspNetCoreApp
    $ sudo dotnet publish --configuration Release -o /var/www/AspNetCoreApp
  • Lệnh trên biên dịch ứng dụng ra thư mục với đường dẫn /var/www/AspNetCoreApp. Để chạy ứng dụng ASP.NET Core sử dụng lệnh sau:
    $ cd /var/www/AspNetCoreApp
    $ dotnet AspNetCoreApp.dll
    info: Microsoft.Hosting.Lifetime[0]
          Now listening on: http://localhost:5000
    info: Microsoft.Hosting.Lifetime[0]
          Now listening on: https://localhost:5001
    info: Microsoft.Hosting.Lifetime[0]
          Application started. Press Ctrl+C to shut down.
    info: Microsoft.Hosting.Lifetime[0]
          Hosting environment: Production
    info: Microsoft.Hosting.Lifetime[0]
  • Ấn Ctrl + X để thoát khỏi ứng dụng
  • Lưu ý thư mục /var/www/AspNetCoreApp chưa được cấp quyền chạy ứng dụng cũng như cho phép truy xuất tài nguyên trong thư mục này. Do vậy để đảm bảo tài nguyên được chia sẻ chúng ta thực hiện phân quyền cho ứng dụng này có khả năng chia sẻ tài nguyên này bằng lệnh sau:
    $ sudo chown -R $USER:$USER /var/www/AspNetCoreApp
    $ sudo chmod –R 755 /var/www/AspNetCoreApp

Tạo Dịch vụ (service) cho ứng dụng Web ASP.NET Core vừa biên dịch

Thực tế không bao giờ thực hiện việc chạy ứng dụng theo cách trên, thông thường chúng ta sẽ tạo ra một dịch vụ (service) để chạy ứng dụng đã được biên dịch để tiện cho việc quản lý.

  • Tạo tệp định nghĩa dịch vụ:
    $ sudo nano /etc/systemd/system/kestrel-asp.service
    Thực hiện mã cấu hình cho dịch vụ như sau: 
    [Unit]
    Description=Example .NET Web API App running on Ubuntu
    
    [Service]
    WorkingDirectory=/var/www/AspNetCoreApp
    ExecStart=/usr/bin/dotnet /var/www/AspNetCoreApp/AspNetCoreApp.dll
    Restart=always
    # Restart service after 10 seconds if the dotnet service crashes:
    RestartSec=10
    KillSignal=SIGINT
    SyslogIdentifier=dotnet-example
    User=www-data
    Environment=ASPNETCORE_ENVIRONMENT=Production
    Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false
    
    [Install]
    WantedBy=multi-user.target
    ấn Ctrl + X để thoát khỏi ứng dụng nano, ấn Enter để lưu lại tệp cấu hình
  • Để kích hoạt dịch vụ sử dụng lệnh sau:
    $ sudo systemctl enable kestrel-asp.service
  • Khởi động dịch vụ và xác minh rằng nó đang chạy thực hiện lệnh sau:
    $ sudo systemctl start kestrel-asp.service
    $ sudo systemctl status kestrel-asp.service
    
    ◝ kestrel-asp.service - Example .NET Web API App running on Ubuntu
        Loaded: loaded (/etc/systemd/system/kestrel-helloapp.service; enabled)
        Active: active (running) since Thu 2021-06-11 04:09:35 NZDT; 35s ago
    Main PID: 9021 (dotnet)
        CGroup: /system.slice/kestrel-asp.service
                └─9021 /usr/local/bin/dotnet /var/www/AspNetCoreApp/AspNetCoreApp.dll
  • Để xem được nhật ký của dịch vụ vừa tạo có thể thực hiện lệnh sau:
    $ sudo journalctl -fu kestrel-asp.service
    Để xem được nhật ký với thời gian tuỳ chỉnh có thể thực hiện lệnh sau:
    $ sudo journalctl -fu kestrel-asp.service --since "2021-06-11" --until "2021-06-11 14:00"
    hoặc xem nhật ký ngày hôm nay:
    $ sudo journalctl -fu kestrel-asp.service --since today
    $ sudo journalctl -fu kestrel-asp.service --since 1 hour ago
  • Các lệnh quản lý cơ bản cho dịch vụ vừa tạo:
    # Dừng chạy chạy dịch vụ
    $ sudo systemctl stop kestrel-asp.service
    # Khởi động lại dịch vụ
    $ sudo systemctl restart kestrel-asp.service

Cấu hình máy chủ Nginx trỏ vào ứng dụng vừa tạo

  • Cài đặt được máy chủ Nginx và hiểu cách cấu hình cơ bản của máy chủ Nginx xem chi tiết tại đây.
  • Để định cấu hình Nginx làm proxy ngược để chuyển tiếp các yêu cầu HTTP tới ứng dụng ASP.NET Core của bạn, hãy sửa đổi tệp với đường dẫn /etc/nginx/sites-available/default với lệnh sau:
    $ sudo nano /etc/nginx/sites-available/default
    Thay thế nội dung bằng đoạn mã cấu hình sau:
    server {
        listen        80;
        server_name   example.com *.example.com;
        location / {
            proxy_pass         http://127.0.0.1:5000;
            proxy_http_version 1.1;
            proxy_set_header   Upgrade $http_upgrade;
            proxy_set_header   Connection keep-alive;
            proxy_set_header   Host $host;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto $scheme;
        }
    }
    Thực hiện mã cấu hình xong ấn Ctrl + X để thoát khỏi ứng dụng nano:
    $ File Name to Write: /etc/nginx/sites-available/default_
    ^G Get Help         M-D DOS Format      M-A Append          M-B Backup File
    ^C Cancel           M-M Mac Format      M-P Prepend         ^T To Files
    Ấn phím Enter để lưu lại tệp vừa cấu hình
  • Kiểm tra lại cấu hình của Nginx:
    $ sudo nginx –t
    # Output:
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
  • Nếu kiểm tra không có lỗi tiến hành khởi động lại Nginx:
    $ sudo systemctl restart nginx

Kiểm tra ứng dụng chạy trên trình duyệt

  • Kiểm tra địa chỉ IP bên ngoài (External IP) của máy:
    $ curl -4 icanhazip.com
    # Output:
    157.245.204.118
  • Vào trình duyệt nhập địa chỉ IP bên ngoài của máy (http://157.245.204.118) sẽ thấy kết quả hiển thị như sau:

Một vài tuỳ chỉnh khác khi chạy ứng dụng ASP.NET Core

  • Thay đổi cổng chạy mặc định của ASP.NET Core:
    Trong thư mục khi xuất bản ra có tệp appsettings.json để thiết lập cấu hình chạy ứng dụng. Để thay đổi cổng mặc định 5000 khi chạy ứng dụng ASP.NET Core sang cổng 2013 thực hiện lệnh như sau:
    $ sudo nano /var/www/AspNetCoreApp/appsetting.json
    Thay đổi nội dung cấu hình như sau:
    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*",
      "Urls": "http://localhost:2013"
    }
    ấn Ctrl + X để thoát khỏi ứng dụng nano, ấn Enter để lưu lại tệp cấu hình.
    Lưu ý: Sau khi thực hiện đổi cổng ứng dụng thì chúng ta nên khởi động lại dịch vụ của ứng dụng cũng như thay đổi cấu hình của Nginx sang cổng mà chúng ta vừa cấu hình rồi khởi động lại Nginx thì hệ thống Web mới chạy sang cổng mới.