翻譯自 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 Linux。node
注意:linux
對於 Ubuntu 14.04,建議使用 supervisord 監控 Kestrel 進程做爲解決方案。對於 Ubuntu 14.04 的介紹,能夠該話題的以前版本。nginx
本指南包含如下內容: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),能夠安裝下面任意一種途徑解決:
在開發環境中運行 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。
使用 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 做爲一個反向代理轉發 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 存儲在內存中,當應用程序重啓的時候就會:
爲了配置數據保護持久化和加密 key ring,請查看:
代理服務器默認設置根據平臺請求頭部區域限制一般是 4K 或者 8K 大小。應用程序可能要求比默認大小更長的請求頭部(例如,使用 Azure Active Directory 的應用程序)。若是更長的請求頭部要求,代理服務器的默認設置就須要調整。應用的數值根據狀況而定。更多信息,請查看服務器文檔:
注意:
除非有必要,不然不要增長代理 buffers 的大小。增長這些值增大了 buffer 溢出的風險和 被惡意用戶的拒絕服務 Denial of Service(Dos) 攻擊。
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
編輯 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。
dotnet run 命令使用應用程序的 Properties/launchSettings.json 文件,這個文件配置應用程序在由 applicationUrl 屬性提供的 URLs 上面監聽。例如,https://localhost;http://localhost:5000。
配置應用程序在開發中 dotnet run 命令或者在開發環境中(F5 or Ctrl + F5 在 Visual Studio Code) 中使用一個證書,可使用如下途徑之一:
注意
對於開發環境,咱們建議使用臨時重定向(302)而不是永久重定向(301)。連接緩存可能在開發環境中致使不穩定的行爲。
添加 /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。
Clickjacking,也被稱爲界面不久攻擊,是一種惡意攻擊,訪客被欺騙在一個不一樣的頁面上點擊一個連接或者按鈕,而不是在當前正在訪問的頁面。使用 X-FRAME-OPTIONS 保護站點。
爲了減輕點擊劫持攻擊:
1. 編輯 nginx.conf 文件:
sudo nano /etc/nginx/nginx.conf
添加行:add_header X-Frame-Options "SAMEORIGIN";
2. 保存文件
3. 重啓 Nginx
這個頭部阻止大多數的瀏覽器嗅探一個離開聲明內容類型的返回,因爲頭部指示瀏覽器不要覆蓋返回內容的類型。使用 nosniff 選項,若是服務說內容是 text/html,那麼瀏覽器就渲染爲 text/html。
1. 變價 nginx.conf 文件:
sudo nano /etc/nginx/nginx.conf
添加行: add_header X-Content-Type-Options "nosniff";
2. 保存文件
3. 重啓 Nginx
在升級完服務器上共享的框架,從新啓動服務器託管的 ASP.NET Core 應用程序。