翻译自 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 应用程序。