- Kestrel Server trong asp.net core
- Cấu hình Kestrel cơ bản
- Publish ứng dụng asp.net core
- Cài đặt .NET Core SDK
- Giám sát ứng dụng ASP.NET với systemd
- Sử dụng máy chủ Apache chạy ASP.NET core
- Sử dụng nginx với ASP.NET Core Kestrel
Kestrel Server trong asp.net core
Kestrel là một máy chủ web đa nền tảng nó được tích hợp sẵn và chạy mặc định trong các ứng dụng asp.net khởi tạo từ các template (Asp.net core mvc, asp.net razor page ... đã biết). Có nghĩa khi bạn build ứng dụng asp.net, chạy nó thì sẽ tự động chạy web server Kestrel
Trong phần này, tìm hiểu một số cấu hình cơ bản để có thể áp dụng làm cơ sở chuẩn bị cho việc publish ứng dụng, triển khai ứng dụng trên môi trường product.
Có thể cấu hình sử dụng Kestrel với hai trường hợp:
Dùng Kestrel trực tiếp nhận các yêu cầu Http gửi đến
Sử dụng Kestrel sau reverse proxy server (IIS, Apache, Nginx) - các reverse proxy server nhận các yêu cầu Http gửi đến, rồi chuyển cho Kestrel
Ở môi trường product thì không nên sử dụng trực tiếp Kestrel mà hãy dùng Reverse Proxy Server (apache,nginx) vì nó cung cấp nhiều chức năng cao cấp cho một máy chủ web, dễ dàng cấu hình https, dễ dàng tích hợp trên hạ tầng có sẵn, cung cấp nhiều lớp bảo mật ...
Cấu hình Kestrel trong ASP.NET core
Khi khởi tạo ứng dụng ASP.NET từ các template, bao giờ cũng có file Program.cs
trong đó định nghĩa hàm Main - gọi CreateHostBuilder để chạy ứng dụng, code mặc định này đã
sử dụng và chạy Kestrel
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); }
Phụ thuộc vào môi trường chạy ứng dụng mà Kestrel chạy và lắng nghe ở các cổng khác nhau theo
cấu hình của môi trường. Trong môi trường phát triển, thường nó sẽ lắng nghe ở cổng 5000 (http)
và cổng 5001 (https). Cổng này có thể thiết lập qua biến môi trường hệ thống ASPNETCORE_URLS
(ví dụ trong khi đóng gói vào docker có thiết lập biến môi trường ASPNETCORE_URLS=https://+:443;http://+:80
thì Kestrel chạy và lắng nghe cổng 443 và 80)
Để tùy biến Kestrel với các thiết lập cụ thể sử dụng đối tượng KestrelServerOptions
như sau:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseKestrel(kestrelServerOptions => { // Các thiết lập cho Kestrel tại đây // sử dụng KestrelServerOptons để thiết lập }) webBuilder.UseStartup<Startup>(); });
Bind IP - thiết lập Kestrel lắng nghe trên cổng và IP
Bạn có thể sử dụng các phương thức KestrelServerOptions.Listen
,
KestrelServerOptions.ListenAnyIP
, KestrelServerOptions.ListenLocalhost
ví dụ:
webBuilder.UseKestrel(kestrelServerOptions => { // Thiết lập lắng nghe trên cổng 8090 với IP bất kỳ kestrelServerOptions.Listen(IPAddress.Any, 8090); // Lắng nghe trên cổng 8091 trên server chạy ứng dụng kestrelServerOptions.ListenLocalhost(8091); kestrelServerOptions.Listen(IPAddress.Loopback, 8092, listenOptions => { // Thiết lập sử dụng SSL - file xác thực SSL testCert.pfx listenOptions.UseHttps("testCert.pfx", "testPassword"); }); });
Thiết lập một số giới hạn của Kestrel với KestrelServerLimits
Nếu muốn thay đổi các giới hạn mặc định thì có thể dùng, KestrelServerLimits với các thuộc tính đặt giới hạn,
ví dụ thiết lập keep-alive timeout
webBuilder.UseKestrel(kestrelServerOptions => { /... kestrelServerOptions.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2); });
Các thiết lập khác tham khảo tại: kestrelserverlimits
Nhanh chóng thiết Bind IP cho Server
Bạn có thể nhanh chóng dùng webBuilder.UseUrls
để thiết lập IP và cổng của Kestrel,
dùng địa chỉ Url để thiết lập Kestrel lắng nghe trên nó. Trong đó có chỉ ra giao thức (http, https), địa chỉ IP,
và cổng. Ví dụ:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseUrls("http://0.0.0.0:8090", "https://0.0.0.0:8091"); webBuilder.UseStartup<Startup>(); });
Sử dụng Kestrel phía sau các Http Server khác
(Http Apache, Nginx, IIS) thì nên sử dụng cách này (UseUrls
),
và chỉ cần lắng nghe ở giao thức http, còn https được cấu hình ở server phía trước (nginx
, apache
).
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { // Chỉ nhận http (không https) webBuilder.UseUrls("http://0.0.0.0:5000"); webBuilder.UseStartup<Startup>(); });
Ngoài ra cũng chú ý, để sử dụng chính xác Kestrel với nginx, apache cần thêm vào đầu
Startup.configure
... // using Microsoft.AspNetCore.HttpOverrides; app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); ...
Publish ứng dụng ASP.NET core
Để biên dịch mã nguồn chạy ở môi trường Product, có thể thực hiện các lệnh như sau:
# phục hồi các dependency từ Nuget dotnet restore # build dotnet build -c Release -o app/build # publish dotnet publish -c Release -o app/publish
Kết quả là xuất ra ứng dụng ra thư mục app/publish
, bạn dùng thư mục này để phân phối - triển
khai chạy ứng dụng. Trong thư mục có file dll tên ứng dụng dùng để chạy ứng dụng
dotnet tên-ứng-dụng.dll
Chú ý, server chạy ứng dụng phải cài .NET Core SDK và .NET Core Runtime
Kèm thư mục khi publish
Trong dự án có thể có các thư mục tài nguyên, ví dụ thư mục Uploads, nếu muốn thư mục này được copy vào
publish thì trong file: .csproj
thêm vào đoạn mã:
<ItemGroup> <Content Include="Uploads\**"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> </ItemGroup>
Cài đặt .Net Core SDK trên Server Linux, môi trường chạy ASP.NET
Cài đặt trên CentOS 7
# cài .net3 sdk sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm sudo yum install dotnet-sdk-3.1 -y sudo yum install aspnetcore-runtime-3.1 -y
# cài .net6 sdk sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm sudo yum install dotnet-sdk-6.0 -y sudo yum install aspnetcore-runtime-6.0 -y
Cài đặt trên CentOS 8
sudo dnf install dotnet-sdk-3.1 sudo dnf install aspnetcore-runtime-3.1
SQL Server
Nếu cần triển khai SQL Server trên Linux thì thực hiện
# Cài đặt MS SQL Server 2017 trên CentOS 7 sudo alternatives --config python sudo yum install python2 -y sudo yum install compat-openssl10 sudo alternatives --config python sudo curl -o /etc/yum.repos.d/mssql-server.repo https://packages.microsoft.com/config/rhel/7/mssql-server-2017.repo sudo yum install -y mssql-server # cấu hình phiên bản, password sa sudo /opt/mssql/bin/mssql-conf setup
Cài đặt trên Ubuntu
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-get update; \ sudo apt-get install -y apt-transport-https && \ sudo apt-get update && \ sudo apt-get install -y dotnet-sdk-3.1 sudo apt-get update; \ sudo apt-get install -y apt-transport-https && \ sudo apt-get update && \ sudo apt-get install -y dotnet-sdk-3.1
Giám sát ứng dụng ASP.NET với systemd
Giả sử ứng dụng lưu trên Server Linux ở đường dẫn /home/userasp/mvcblog
(đã copy nội dung
thư mục app/publish
vào mvcblog
), file chạy ứng dụng là mvcblog.dll
,
nó được publish và lắng nghe ở cổng http 8090 (cổng này do bạn đặt trong ứng dụng ở phần trên)
Bạn hoàn toàn có thể vào thư mục, chạy ứng dụng với lệnh:
cd /home/userasp/mvcblog/ dotnet mvcblog.dll
Chú ý, bạn tạo ra user linux để chạy ứng dụng (dùng lệnh useradd) - ở ví dụ trên user là userasp
useradd userasp
Lệnh này tạo ra trong hệ thống Linux một user tên userasp, với thư mục home của user này là: /home/userasp/
Khi bạn chạy trực tiếp như vậy, nếu ứng dụng bị crash vì một sự cố nào đó - thì nó sẽ dừng hẳn và không
được khởi động lại. Giải quyết trường hợp này hãy sử dụng systemd
của Linux, giúp giám
sát tình trạng ứng dụng, khởi động ứng dụng nếu chưa chạy hoặc bị crash.
Tạo ra file dịch vụ trong thư mục /etc/systemd/system/
, ví dụ ứng dụng là mvcblog, tạo
ra file /etc/systemd/system/mvcblog.service
(dùng lệnh vi),
sau đó biên tập nội dung file này như sau:
[Unit] Description=Ung dung ASP.NET MVC BLOG [Service] WorkingDirectory=/home/userasp/mvcblog ExecStart=/usr/bin/dotnet /home/userasp/mvcblog/mvcblog.dll Restart=always # Khởi động lại ứng dụng sau 10 bị crash RestartSec=10 KillSignal=SIGINT SyslogIdentifier=asp-net-app User=userasp Environment=ASPNETCORE_ENVIRONMENT=Production [Install] WantedBy=multi-user.target
/usr/bin/dotnet
là đường dẫn đầy đủ đến file binary của lệnh dotnet, có thể kiểm
tra bằng lệnh
which dotnet
Để thiết lập dịch vụ tự động chạy bạn
systemctl enable mvcblog
Khởi chạy dịch vụ (ứng dụng)
systemctl start mvcblog
Xem trang thái
systemctl status mvcblog
Lưu ý, ứng dụng ASP.NET chạy trên lắng nghe ở cổng 8090 hoặc cổng do bạn thiết lập, cổng này không public ra ngoài (không dùng firewall để mở). Cổng chỉ dùng cho các dịch vụ như apache, nginx chuyển hướng đến.
Dùng máy chủ Apache chạy Asp.net trên CENTOS
Đầu tiên hãy đảm bảo máy chủ đã tắt SELinux: Cách tắt SELinux
Nếu chưa có máy chủ Apache, cài vào:
yum -y install httpd mod_ssl mod_rewrite
Dùng lệnh systemctl
để chạy, quản lý dịch vụ Apache
systemctl enable httpd
systemctl start httpd
File cấu hình chung của Apache ở đường dẫn: /etc/httpd/conf/httpd.conf
Để cấu hình Apache như một Proxy - chuyển hướng các yêu cầu đến ASP.NET, hãy thêm cấu hình vào,
có thể tạo ra file cấu hình trong thư mục /etc/httpd/conf.d/
để Apache tự động nạp
Ví dụ tạo ra file /etc/httpd/conf.d/mvcblog.conf
,
biên tập nội dung như sau
<VirtualHost *:*> RequestHeader set "X-Forwarded-Proto" expr="%{REQUEST_SCHEME}e" </VirtualHost> <VirtualHost *:80> ProxyPreserveHost On ProxyPass / http://127.0.0.1:8090/ ProxyPassReverse / http://127.0.0.1:8090/ ServerName mvcblog.vn ServerAlias *.mvcblog.vn ErrorLog ${APACHE_LOG_DIR}mvcblog-error.log CustomLog ${APACHE_LOG_DIR}mvcblog-access.log common </VirtualHost>
Sau đó khởi động lại HTTPD
systemctl restart httpd
Với cấu hình trên, Http Apache lắng nghe ở cổng 80, khi truy cập với tên miền mvcblog.vn thì nó sẽ chuyển các yêu cầu tới ứng dụng ở cổng 8090. Hãy tạo ra tên miền trong file hosts để kiểm tra.
Cấu hình sử dụng https - Apache centos - cho ứng dụng aps.net core
Để sử dụng SSL tạo giao thức kết nối an toàn https thì bạn cần kích hoạt mod_ssl của Apache, nếu chưa có thì cài đặt và nạp vào cùng Apache
yum install mod_ssl
Khi có mod_ssl có thể tạo Vhost lắng nghe ở cổng 443, bạn cũng nên cài đặt mod_rewrite để tự động chuyển truy cập http thành https
Cấu hình SSL thì cần có cặp private/public key chứng thực bởi bên thứ 3 (như Let's Encrypt), tuy nhiên để kiểm thử ta tự phát sinh cặp key này - tự xác thực (cách phát sinh như hướng dẫn tại Sử dụng OPENSSL )
Thực hiện các lệnh:
mkdir /certtest cd /certtest/ openssl genrsa -out ca.key 2048 openssl req -new -key ca.key -out ca.csr openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
Hoàn thành các lệnh trên sẽ thu được public key tại /certtest/ca.crt
và private key tại /certtest/ca.key
Lúc này mở /etc/httpd/conf.d/mvcblog.conf
cập nhật thành
<VirtualHost *:*> RequestHeader set "X-Forwarded-Proto" expr="%{REQUEST_SCHEME}e" </VirtualHost> <VirtualHost *:80> ServerName mvcblog.vn ServerAlias *.mvcblog.vn # chuyển hướng http sang https RewriteEngine On RewriteCond %{HTTPS} !=on RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L] </VirtualHost> <VirtualHost *:443> ServerName mvcblog.vn ServerAlias *.mvcblog.vn ProxyPreserveHost On ProxyPass / http://127.0.0.1:8090/ ProxyPassReverse / http://127.0.0.1:8090/ ErrorLog ${APACHE_LOG_DIR}helloapp-error.log CustomLog ${APACHE_LOG_DIR}helloapp-access.log common # Cấu hình HTTPS SSLEngine on # SSLProtocol all -SSLv2 # SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:!RC4+RSA:+HIGH:+MEDIUM:!LOW:!RC4 SSLCertificateFile /certtest/ca.crt SSLCertificateKeyFile /certtest/ca.key </VirtualHost>>
Khởi động lại Apache, giờ đã có thể truy cập với giao thức https
Dùng nginx với Kestrel trên CENTOS chạy asp.net
Cài đặt nginx trên CentOS 7
Tạo file /etc/yum.repos.d/nginx.repo
với nội dung
[nginx] name=nginx repo baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/ gpgcheck=0 enabled=1
Thực hiện các lệnh:
yum install nginx systemctl enable nginx systemctl start nginx
Mở file cấu hình /etc/nginx/conf.d/default.conf
sửa thành
server { listen 80; server_name mvcblog.vn *.mvcblog.vn; location / { proxy_pass http://localhost:8090; 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; } }
File cấu hình này thiết lập nginx lắng nghe ở cổng 80, cho các truy vấn đến từ tên miền mvcblog.vn, nó chuyể traffic đến ứng dụng ASP.NET ở cổng 8090
Cấu hình nginx sử dụng https cho ứng dụng asp.net core
Tạo ra file /etc/nginx/proxy.conf
, biên tập nội dung như sau:
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; proxy_set_header X-Forwarded-Proto $scheme; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffers 32 4k;
Mở file /etc/nginx/nginx.conf
biên tập thành
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/proxy.conf; limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s; server_tokens off; sendfile on; keepalive_timeout 29; # Adjust to the lowest possible value that makes sense for your use case. client_body_timeout 10; client_header_timeout 10; send_timeout 10; upstream mvcblog { server localhost:8090; } server { listen *:80; add_header Strict-Transport-Security max-age=15768000; return 301 https://$host$request_uri; } server { listen *:443 ssl; server_name example.com; ssl_certificate /certtest/ca.crt; ssl_certificate_key /certtest/ca.key; ssl_protocols TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; ssl_ecdh_curve secp384r1; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; ssl_stapling on; #ensure your cert is capable ssl_stapling_verify on; #ensure your cert is capable add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; #Redirects all traffic location / { proxy_pass http://mvcblog; limit_req zone=one burst=10 nodelay; } } }
Khởi động lại nginx sau khi cập nhật cấu hình