翻譯 - ASP.NET Core 託管和部署 - 在 Linux 上使用 Nginx 託管 ASP.NET Core 網站

翻譯自 https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-5.0html

本文介紹了在 Ubuntu 16.04 服務器上設置生產環境可用的 ASP.NET Core 環境。這裏的介紹對於更新版本的 Ubuntu 可能也會工做,可是並無在更新版本的服務器上測試。前端

更過關於 ASP.NET Core 只是的 Linux 發行版,請查看 Prerequisites for .NET Core on Linuxnode

注意:linux

對於 Ubuntu 14.04,建議使用 supervisord 監控 Kestrel 進程做爲解決方案。對於 Ubuntu 14.04 的介紹,能夠該話題的以前版本。nginx

本指南包含如下內容:web

  • 使用反向代理服務器放置一個現存的 ASP.NET Core 應用程序
  • 設置反向代理服務器將請求轉發到 Kestrel web 服務器
  • 保證 web 應用程序在啓動時做爲守護進程(daemon)運行
  • 配置一個進程管理工具幫助 web 應用程序從新啓動

先決條件

1. 使用帶有 sudo 權限的標準用戶帳號訪問 Ubuntu 16.04 服務器json

2. 在服務上安裝 .NET Core 運行時。ubuntu

    a. 訪問 Download .NET Core pageapi

    b. 選擇一個最新非預覽版的 .NET Core 版本瀏覽器

    c. 下載表格中 Run apps - Runtime 最新非預覽版本

    d.  選擇 Linux Package manager instructions 連接,按照你的版本的 Ubuntu 的說明進行操做

3. 一個現存的 ASP.NET Core 應用程序

以後的任什麼時候候,在升級完 shared framework 後,須要從新啓動服務器託管的 ASP.NET Core 應用程序。

發佈和複製應用程序

配置應用程序爲框架獨立的部署。

若是應用程序在本地運行,而且沒有配置安全鏈接(HTTPS),能夠安裝下面任意一種途徑解決:

  • 配置應用程序處理安全的本地鏈接。更多信息請查看 HTTPS configuration
  • 從文件 Properties/launchSettings.json 中的屬性 applicationUrl 中移除 https://localhost:5001(若是存在的話)

在開發環境中運行 dotnet publish 打包應用程序到一個能夠運行在服務器上的目錄 (例如,bin/Release/{TARGET FRAMEWORK MONIKER}/publish,佔位符 {TARGET FRAMEWORK MONIKER} 是目標框架名稱) 中:

dotnet publish --configuration Release

若是你不想在服務器上維護 .NET Core 運行時,應用程序也能夠被髮布爲自包含部署(self-contained deployment)。

使用組織工做流中的工具(例如,SCP,SFTP)複製 ASP.NET Core 應用程序到服務器。一般把 web 應用程序放到 var 目錄(例如:var/www/helloapp)。

注意

在生產部署環境中,一個持續集成的工做流完成發佈和複製資源到服務器上。

測試服務器:

1. 從命令行運行應用程序:dotnet <app_assembly>.dll

2. 在瀏覽器中,導航到 http://<serveraddress>:<port> 驗證應用程序正常運行

 配置反向代理服務器

 反向代理一般用來設置動態 web 應用程序服務。一個反向代理終結 HTTP 請求並轉發給 ASP.NET Core 應用程序。

使用反向代理服務

Kestrel 從 ASP.NET Core 服務動態內容是強大的,然而,web 服務能力並無像 IIS,Apache,或者 Nginx 有不少特性。一個反向代理服務器能夠從 HTTP 服務器分擔一些工做,例如服務靜態內容,緩存請求,壓縮請求和 HTTPS 終結。反向代理服務器可能部署在專用機器上,也可能和 HTTP 服務器部署在同一臺機器上。

出於本指南的目的,一個單獨的 Nginx 實例被使用。它和 HTTP 服務運行在同一臺服務器上。根據需求,不一樣的設置會被選擇。

由於請求都被反向代理轉發,使用 Microsoft.AspNetCore.HttpOverrides 包中的中間件 Forwarded Headers Middleware。這個中間件使用 X-Forwarded-Proto header 更新了 Request.Scheme,因此重定向 URIs和其它安全策略工做正確。

Forwarded Headers Middleware 應該在其它中間件以前運行。這個順序保證了依賴 forwarded headers 信息的中間件能夠在處理過程當中使用 header 的值。在 diagnostics 和 錯誤處理中間件以後運行 Forwarded Headers Middleware,查看 Forwarded Headers Middleware order

在調用其它中間件以前,在 Startup.Configure 的頂部調用 UseForwardedHeaders。配置中間件轉發 X-Forwarded-For 和 X-Forwarded-Proto headers:

using Microsoft.AspNetCore.HttpOverrides;

...

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthentication();

若是沒有中間件沒有指定 ForwardedHeadersOptions,默認轉發的 headers 是 None。

代理運行在迴路地址 (127.0.0.0/8, [::]),包含標準本地地址 (127.0.01),默認是被信任的。若是其它的代理或者組織內的網絡處理網絡和 web 服務器之間的請求,可使用 ForwardedHeadersOptions 把它們添加到 KnownProxies 或者 KnownNetworks 列表中。下面的實例在 Startup.ConfigureServices 中添加了一個 IP 地址爲 10.0.0.100 可信任的代理到 Forwarded Header Middleware KnownProxies 中。

using System.Net;

...

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

更多信息查看 Configure ASP.NET Core to work with proxy servers and load balancers

安裝 Nginx

使用 apt-get 安裝 Nginx。安裝器建立一個 systemd 初始化腳本啓動 Nginx 做爲守護進程。按照下面 Ubuntu 安裝 Nginx 說明操做:Official Debian/Ubuntu packages

注意:

若是要求可選的 Nginx 模塊,可能須要從源碼編譯 Nginx。

因爲 Nginx 是第一次安裝,運行下面的命令顯式啓動:

sudo service nginx start

經過瀏覽器顯示 Nginx 默認加載頁驗證 Nginx 是否正常。加載的頁面 http://<server_IP_address>/index.nginx-debian.html 是能夠訪問的。

配置 Nginx

爲了配置 Nginx 做爲一個反向代理轉發 HTTP 請求到你的 ASP.NET Core 應用程序,須要修改 /etc/nginx/sites-available/default。使用文本編輯器打開它,使用下面的內容替換:

server {
    listen        80;
    server_name   example.com *.example.com;
    location / {
        proxy_pass         http://localhost: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;
    }
}

若是應用程序是 SingalR 或者 Blazor Server app,查看 ASP.NET Core SignalR production hosting and scaling 和 Host and deploy ASP.NET Core Blazor Serve

若是沒有 server_name 匹配,Nginx使用默認服務。若是沒有定義默認的服務,配置文件中的第一個服務做爲默認服務。做爲最佳實踐,在配置文件中添加一個返回 444 狀態碼的默認服務。一個默認的配置示例以下:

server {
    listen   80 default_server;
    # listen [::]:80 default_server deferred;
    return   444;
}

前面的配置文件和默認服務,Nginx 接受端口 80 上主機頭爲 example.com 或者 *.example.com 的流量。不匹配這些主機的請求將不會被轉發到 Kestrel。Nginx 轉發匹配的請求到 Kestrel 的 http://localhost:5000。更多信息查看 How nginx processes a request。更改 Kestrel 的 IP/端口。查看 Kestrel: Endpoint configuration

注意:

沒有合適的指定 server_name 指令會暴露你的應用程序的安全弱點。子域通配符綁定(例如,*.example.com)並不會形成安全問題,若是你控制了所有的父域(而不是 *.com,這個存在隱患)。更多信息查看rfc7230 section-5.4.。

Nginx 配置創建後,運行 sudo nginx -t 驗證配置文件是否有語法錯誤。若是配置文件測試成功,能夠運行 sudo nginx -s reload 強制 Nginx 使用修改後的配置。

 直接在服務器上運行應用程序:

1. 導航到應用程序目錄

2. 運行應用程序:dotnet <app_assembly.dll>,app_assembly.dll 是應用程序程序集的文件名稱。

若是應用程序在服務器上運行成功,可是經過網絡訪問失敗,能夠檢查服務器的防火牆確認80端口已經打開。若是使用的是 Azure Ubuntu VM,添加一個網絡安全組(NSG)規則確保80端口入站流量。不須要使能80端口出站規則,由於出站流量在入站規則使能的視狀況會自動保證使能。

完成應用程序的測試後,Ctrl + C 關閉應用程序。

監視應用程序

服務器被設置爲轉發指向 http://<serveraddress>:80 的請求到運行在 Kestrel 地址爲 http://127.0.0.1:5000 的 ASP.NET Core 應用程序上。然而,Nginx 沒有被設置爲管理 Kestrel 進程。systemd 能夠被用來建立一個服務文件去啓動和監視背後的 web 應用程序。systemd 是一個初始化系統,提供了不少強大的特性去啓動,中止和管理進程。

建立一個服務文件

建立一個服務定義文件:

sudo nano /etc/systemd/system/kestrel-helloapp.service

下面是一個應用程序服務文件的示例:

[Unit]
Description=Example .NET Web API App running on Ubuntu

[Service]
WorkingDirectory=/var/www/helloapp
ExecStart=/usr/bin/dotnet /var/www/helloapp/helloapp.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

前面的這個例子中,管理服務的用戶經過 User 選項指定。用戶 (www-data)必須存在而且擁有應用程序文件的合適的權限。

使用 TimeoutStopSec 配置在應用程序關閉後收到初始中斷信號等待的時長。若是應用程序這時沒有關閉,SIGKILL 能夠用來結束應用程序。能夠提供不帶單位的秒(例如,150),時間範圍(例如,2min 30s),或者 infinity 禁用超時。TimeoutStopSed 默認值是 DefaultTimeoutStopSec 的值,存在於配置文件 (systemd-system.conf,system.conf.d,systemd-user.conf,user.conf.d)。大部分發行版的默認超時時間是 90 秒。

# The default value is 90 seconds for most distributions.
TimeoutStopSec=90

Linux 文件系統區分大小寫。Production 被設置爲 ASPNETCORE_ENVIRONMENT 會使得搜索配置文件 appsetting.Production.json,而不是appsetting.production.json。

某些值(例如, SQL 鏈接字符串)必須轉義才能被配置提供器去讀取環境變量。使用下面的命令生成一個在配置文件中使用的合適的轉義值:

systemd-escape "<value-to-escape>"

環境變量名稱不支持冒號(:)分隔符。使用雙下劃線(__)代替冒號。Environment Variables configuration provider 在環境變量被讀入配置的時候會轉換雙下劃線爲冒號。在下面的示例中,鏈接字符串鍵值 ConnectionStrings:DefaultConnection 在服務定義文件中被設置爲: ConnectionStrings__DefaultConnection:

Environment=ConnectionStrings__DefaultConnection={Connection String}

保存文件而且使能服務:

sudo systemctl enable kestrel-helloapp.service

啓動服務,驗證運行:

sudo systemctl start kestrel-helloapp.service
sudo systemctl status kestrel-helloapp.service

◝ kestrel-helloapp.service - Example .NET Web API App running on Ubuntu
    Loaded: loaded (/etc/systemd/system/kestrel-helloapp.service; enabled)
    Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet)
    CGroup: /system.slice/kestrel-helloapp.service
            └─9021 /usr/local/bin/dotnet /var/www/helloapp/helloapp.dll

使用反向代理配置,Kestrel 經過 systemd 管理,web 應用程序已經徹底配置好,能夠在本機的瀏覽器中訪問 http://localhost。也能夠經過遠程主機訪問,除非是有防火牆的阻塞。檢查返回頭部,Server 頭部顯示的是 ASP.NET Core 應用程序託管在 Kestrel 上。

HTTP/1.1 200 OK
Date: Tue, 11 Oct 2016 16:22:23 GMT
Server: Kestrel
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked

瀏覽日誌

因爲 web 應用程序使用的 Kestrel 經過 systemd 管理,全部的事件和處理過程都被記錄到中心日誌中。然而,這個日誌包含全部 systemd 管理的服務和進程的全部條目的日誌。要查看 kestrel-ledinpro.service 的條目,使用下面的命令:

sudo journalctl -fu kestrel-helloapp.service

更進一步的篩選,時間選項,例如 --since today,until 1 hour ago,或者這些的結合能夠減小返回條目的數量:

sudo journalctl -fu kestrel-helloapp.service --since "2016-10-18" --until "2016-10-18 04:00"

 數據保護

 ASP.NET Core Data Protection stack 被多個 ASP.NET Core 中間件使用,包含認證中間件(例如,cookie 中間件)和跨站請求僞造(CSRF)保護。即便數據保護 APIs 不被用戶代碼調用,數據保護也應該建立一個持久加密的鍵值存儲配置。若是數據保護沒有配置,在內存中的鍵值在應用程序重啓的時候就會被丟棄。

若是 key ring 存儲在內存中,當應用程序重啓的時候就會:

  • 全部基於 cooked 的認證 tokens 都會失效
  • 用戶在他們下一次請求的時候會被要求再次登陸
  • 任何使用 key ring 的數據保護再也不能被解密。這可能包含 CSRF tokens 和 ASP.NET Core MVC TempData cookies

爲了配置數據保護持久化和加密 key ring,請查看:

長請求頭部區域

代理服務器默認設置根據平臺請求頭部區域限制一般是 4K 或者 8K 大小。應用程序可能要求比默認大小更長的請求頭部(例如,使用 Azure Active Directory 的應用程序)。若是更長的請求頭部要求,代理服務器的默認設置就須要調整。應用的數值根據狀況而定。更多信息,請查看服務器文檔:

注意:

除非有必要,不然不要增長代理 buffers 的大小。增長這些值增大了 buffer 溢出的風險和 被惡意用戶的拒絕服務 Denial of Service(Dos) 攻擊。

保護應用程序

使能 AppArmor

Linux Security Modules(LSM) 是一個框架,自 Linux 2.6 版本依賴就是 Linux 內核的一部分。LSM 支持安全模塊的不一樣實現。AppArmor 實現了 Mandatory Access Control 系統的一種 LSM,它容許限制程序訪問有限的資源集合。確保 AppArmor 使能是合適的配置。

配置防火牆

關閉全部用不到的端口。Uncomplicated firewall (ufw) 經過提供了 CLI 配置防火牆爲 iptable 提供了一個前端。

警告:

若是配置不正確,防火牆將會阻止訪問整個系統。錯誤的指定 SSH 端口將會將你鎖定在系統外,若是你使用 SSH 去鏈接它。默認端口是 22。更多信息請查看 introduction to ufw 和 manual

安裝 ufw,在須要的端口上配置容許流量:

sudo apt-get install ufw

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable

保護 Nginx

修改 Nginx 返回名稱

編輯 src/http/ngx_http_header_filter_module.c:

static char ngx_http_server_string[] = "Server: Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: Web Server" CRLF;

配置選項

使用更多要求的模塊配置服務。考慮使用 web 應用程序防火牆加固應用程序,例如 ModSecurity

HTTPS 配置

配置應用程序安全 (HTTPS) 的本地鏈接

dotnet run 命令使用應用程序的 Properties/launchSettings.json 文件,這個文件配置應用程序在由 applicationUrl 屬性提供的 URLs 上面監聽。例如,https://localhost;http://localhost:5000。

配置應用程序在開發中 dotnet run 命令或者在開發環境中(F5 or Ctrl + F5 在 Visual Studio Code)  中使用一個證書,可使用如下途徑之一:

配置反向代理安全(HTTPS)的客戶端鏈接

  • 經過指定一個受信任的證書頒發機構的有效證書,配置服務在 443 端口上監聽 HTTPS 流量
  • 利用 /etc/nginx/nginx.conf 文件中的一些實踐描述增強安全。例子包含了選擇一個強加密和重定向HTTP上全部的流量到 HTTPS。

注意

對於開發環境,咱們建議使用臨時重定向(302)而不是永久重定向(301)。連接緩存可能在開發環境中致使不穩定的行爲。

  • 添加一個 HTTP Strict-Transport-Security(HSTS)頭部保證客戶端隨後的全部請求都使用 HTTPS。
    更多關於 HSTS 的指南,請查看 Enforce HTTPS in ASP.NET Core
  • 若是在之後不使用 HTTPS 了,可使用下面其中之一的方法:
    1. 不要添加 HSTS 頭部
    2. 選擇一個更短的 max-age 值

添加 /etc/nginx/proxy.conf 配置文件:

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;

使用下面的內容替換 /etc/nginx/nginx.conf 配置文件的內容。下面的示例在一個配置文件中包含 http 和 server 部分:

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 helloapp{
        server localhost:5000;
    }

    server {
        listen     80;
        return     301 https://$host$request_uri;
    }

    server {
        listen                    443 ssl;
        server_name               example.com *.example.com;
        ssl_certificate           /etc/ssl/certs/testCert.crt;
        ssl_certificate_key       /etc/ssl/certs/testCert.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://helloapp;
            limit_req  zone=one burst=10 nodelay;
        }
    }
}

注意:

Blazor WebAssembly 應用程序要求更大的 burst 參數以適應應用程序更大數量的請求。更多信息,查看 Host and deploy ASP.NET Core Blazor WebAssembly

Secure Nginx from clickjacking

Clickjacking,也被稱爲界面不久攻擊,是一種惡意攻擊,訪客被欺騙在一個不一樣的頁面上點擊一個連接或者按鈕,而不是在當前正在訪問的頁面。使用 X-FRAME-OPTIONS 保護站點。

爲了減輕點擊劫持攻擊:

1. 編輯 nginx.conf 文件:

sudo nano /etc/nginx/nginx.conf

添加行:add_header X-Frame-Options "SAMEORIGIN";

2. 保存文件

3. 重啓 Nginx

MIME-type 嗅探

這個頭部阻止大多數的瀏覽器嗅探一個離開聲明內容類型的返回,因爲頭部指示瀏覽器不要覆蓋返回內容的類型。使用 nosniff 選項,若是服務說內容是 text/html,那麼瀏覽器就渲染爲 text/html。

1. 變價 nginx.conf 文件:

sudo nano /etc/nginx/nginx.conf

添加行: add_header X-Content-Type-Options "nosniff";

2. 保存文件

3. 重啓 Nginx

額外的 Nginx 建議

在升級完服務器上共享的框架,從新啓動服務器託管的 ASP.NET Core 應用程序。

相關文章
相關標籤/搜索