先决条件
- 使用具有 sudo 特权的标准用户帐户访问 Ubuntu 服务器。
- 服务器上安装了最新的非预览版 .NET 运行时。
- 一个现有 ASP.NET Core 应用。
升级共享框架后,可随时重启服务器托管的 ASP.NET Core 应用。
通过应用发布和复制
配置应用以进行依赖框架的部署。
如果应用在本地运行,且未配置为建立安全连接 (HTTPS),则采用以下任一方法:
- 配置应用,以处理安全的本地连接。 有关详细信息,请参阅 HTTPS 配置部分。
- 从 Properties/launchSettings.json 文件的 applicationUrl 属性中删除 https://localhost:(如果存在)。
在开发环境中运行 dotnet publish,将应用打包到可在服务器上运行的目录中(例如 bin/Release/{TARGET FRAMEWORK MONIKER}/publish,其中 {TARGET FRAMEWORK MONIKER} 占位符表示目标框架名字对象/TFM):
.NET CLI
dotnet publish --configuration Release
如果不希望维护服务器上的 .NET Core 运行时,还可将应用发布为独立部署。
使用集成到组织工作流的工具(例如 SCP、SFTP)将 ASP.NET Core 应用复制到服务器。 通常可在 var 目录(例如 var/www/helloapp)下找到 Web 应用。
备注
在生产部署方案中,持续集成工作流会执行发布应用并将资产复制到服务器的工作。
测试应用:
- 在命令行中运行应用:dotnet
.dll。 - 在浏览器中,导航到 http://
: 以确认应用在 Linux 本地正常运行。
配置反向代理服务器
反向代理是为动态 Web 应用提供服务的常见设置。 反向代理终止 HTTP 请求,并将其转发到 ASP.NET Core 应用。
使用反向代理服务器
Kestrel 非常适合从 ASP.NET Core 提供动态内容。 但是,Web 服务功能不像服务器(如 IIS、Apache 或 Nginx)那样功能丰富。 反向代理服务器可以卸载 HTTP 服务器的工作负载,如提供静态内容、缓存请求、压缩请求和 HTTPS 终端。 反向代理服务器可能驻留在专用计算机上,也可能与 HTTP 服务器一起部署。
鉴于此指南的目的,使用 Nginx 的单个实例。 它与 HTTP 服务器一起运行在同一服务器上。 根据要求,可以选择不同的设置。
由于请求通过反向代理转发,因此使用
Microsoft.AspNetCore.HttpOverrides 包中的转接头中间件。 此中间件使用 X-Forwarded-Proto 标头来更新 Request.Scheme,使重定向 URI 和其他安全策略能够正常工作。
转接头中间件应在其他中间件之前运行。 此顺序可确保依赖于转接头信息的中间件可以使用标头值进行处理。 若要在诊断和错误处理中间件后运行转接头中间件,请参阅转接头中间件顺序。
调用其他中间件之前,请先在 Startup.Configure 的基础上调用 UseForwardedHeaders 方法。 配置中间件以转接 X-Forwarded-For 和 X-Forwarded-Proto 标头:
C#
using Microsoft.AspNetCore.HttpOverrides;
...
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseAuthentication();
如果没有为中间件指定 ForwardedHeadersOptions,则要转接的默认标头为 None。
默认情况下,在环回地址 (/8, [::1])(包括标准 localhost 地址 ())上运行的代理受信任。 如果组织内的其他受信任代理或网络处理 Internet 与 Web 服务器之间的请求,请使用 ForwardedHeadersOptions 将其添加到 KnownProxies 或 KnownNetworks 的列表。 以下示例会将 IP 地址为 的受信任代理服务器添加到 Startup.ConfigureServices 中的转接头中间件 KnownProxies:
C#
using System.Net;
...
services.Configure(options =>
{
options.KnownProxies.Add(IPAddress.Parse(""));
});
有关详细信息,请参阅 配置 ASP.NET Core 以使用代理服务器和负载均衡器。
安装 Nginx
使用 apt-get 安装 Nginx。 安装程序将创建一个 systemd init 脚本,该脚本运行 Nginx,作为系统启动时的守护程序。 按照以下网站上的 Ubuntu 安装说明操作:Nginx:官方 Debian/Ubuntu 包。
备注
如果需要可选 Nginx 模块,则可能需要从源代码生成 Nginx。
因为是首次安装 Nginx,通过运行以下命令显式启动:
Bash
sudo service nginx start
确认浏览器显示 Nginx 的默认登陆页。 可在 http://
配置 Nginx
若要将 Nginx 配置为反向代理以将 HTTP 请求转发到 ASP.NET Core 应用程序,请修改
/etc/nginx/sites-available/default。 在文本编辑器中打开它,并将内容替换为以下代码片段:
nginx
server {
listen ;
server_name example.com *.example.com;
location / {
proxy_pass http://:;
proxy_http_version ;
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;
}
}
如果应用是 SignalR 或 Blazor Server 应用,请分别参阅 SignalRASP.NET Core生产托管和缩放 和 托管和部署 ASP.NET Core Blazor Server 以了解详细信息。
当没有匹配的 server_name 时,Nginx 使用默认服务器。 如果没有定义默认服务器,则配置文件中的第一台服务器是默认服务器。 最佳做法是,添加一个特定的默认服务器,它会在配置文件中返回状态代码 。 默认的服务器配置示例是:
nginx
server {
listen default_server;
# listen [::]: default_server deferred;
return ;
}
使用上述配置文件和默认服务器,Nginx 接受主机标头 example.com 或 *.example.com 端口 上的公共流量。 与这些主机不匹配的请求不会转发到 Kestrel。 Nginx 将匹配的请求转发到 http://: 中的 Kestrel。 有关详细信息,请参阅 nginx 如何处理请求。 要更改 Kestrel 的 IP/端口,请参阅 Kestrel:终结点配置。
警告
未能指定正确的 server_name 指令会公开应用的安全漏洞。 如果可控制整个父域(区别于易受攻击的 *.com),则子域通配符绑定(例如,*.example.com)不具有此安全风险。
完成配置 Nginx 后,运行 sudo nginx -t 来验证配置文件的语法。 如果配置文件测试成功,可以通过运行 sudo nginx -s reload 强制 Nginx 选取更改。
要直接在服务器上运行应用:
- 请导航到应用目录。
- 运行应用:dotnet
,其中 app_assembly.dll 是应用的程序集文件名。
如果应用在服务器上运行,但无法通过 Internet 响应,请检查服务器的防火墙,确认端口 已打开。 如果使用 Azure Ubuntu VM,请添加启用入站端口 流量的网络安全组 (NSG) 规则。 不需要启用出站端口 规则,因为启用入站规则后会自动许可出站流量。
完成应用测试后,请在命令提示符处按 Ctrl + C 关闭应用。
监视应用
服务器设置为将对 http://
创建服务文件
创建服务定义文件:
Bash
sudo nano /etc/systemd/system/kestrel-helloapp.service
以下示例是应用的服务文件:
ini
[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 seconds if the dotnet service crashes:
RestartSec=
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 以终止该应用程序。 提供作为无单位秒数的值(例如,)、时间跨度值(例如,2min 30s)或 infinity 以禁用超时。 TimeoutStopSec 默认为管理器配置文件 (systemd-system.conf, system.conf.d, systemd-user.conf, user.conf.d) 中 DefaultTimeoutStopSec 的值。 大多数分发版的默认超时时间为 秒。
# The default value is seconds for most distributions.
TimeoutStopSec=
Linux 具有区分大小写的文件系统。 将 ASPNETCORE_ENVIRONMENT 设置为 Production 时,将搜索配置文件
appsettings.Production.json,而不搜索
appsettings.production.json。
必须转义某些值(例如,SQL 连接字符串)以供配置提供程序读取环境变量。 使用以下命令生成适当的转义值以供在配置文件中使用:
控制台
systemd-escape ""
环境变量名不支持冒号 (:) 分隔符。 使用双下划线 (__) 代替冒号。 环境变量读入配置时,环境变量配置提供程序将双下划线转换为冒号。 以下示例中,连接字符串密钥
ConnectionStrings:DefaultConnection 以
ConnectionStrings__DefaultConnection 形式设置到服务定义文件中:
Environment=ConnectionStrings__DefaultConnection={Connection String}
保存该文件并启用该服务。
Bash
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 :: NZDT; 35s ago
Main PID: (dotnet)
CGroup: /system.slice/kestrel-helloapp.service
└─ /usr/local/bin/dotnet /var/www/helloapp/helloapp.dll
在配置了反向代理并通过 systemd 管理 Kestrel 后,Web 应用现已完全配置,并能在本地计算机上的浏览器中从 http://localhost 进行访问。 也可以从远程计算机进行访问,同时限制可能进行阻止的任何防火墙。 检查响应标头,Server 标头显示由 Kestrel 所提供的 ASP.NET Core 应用。
text
HTTP/ OK
Date: Tue, Oct :: GMT
Server: Kestrel
Keep-Alive: timeout=5, max=
Connection: Keep-Alive
Transfer-Encoding: chunked
查看日志
使用 Kestrel 的 Web 应用是通过 systemd 进行管理的,因此所有事件和进程都被记录到集中日志。 但是,此日志包含由 systemd 管理的所有服务和进程的全部条目。 若要查看特定于 kestrel-helloapp.service 的项,请使用以下命令:
Bash
sudo journalctl -fu kestrel-helloapp.service
有关进一步筛选,使用时间选项(如 --since today、--until 1 hour ago)或这些选项的组合可以减少返回的条目数。
Bash
sudo journalctl -fu kestrel-helloapp.service --since "" --until " :"
数据保护
ASP.NET Core 数据保护堆栈由多个 ASP.NET Core 中间件(包括 cookie 中间件等身份验证中间件)和跨站点请求伪造 (CSRF) 保护使用。 即使用户代码不调用数据保护 API,也应该配置数据保护,以创建持久的加密密钥存储。 如果不配置数据保护,则密钥存储在内存中。重启应用时,密钥会被丢弃。
如果密钥环存储于内存中,则在应用重启时:
- 所有基于 cookie 的身份验证令牌都无效。
- 用户需要在下一次请求时再次登录。
- 无法再解密使用密钥环保护的任何数据。 这可能包括 CSRF 令牌和 ASP.NET Core MVC TempData cookie。
若要配置数据保护以持久保存并加密密钥环,请参阅:
- ASP.NET Core 中的密钥存储提供程序
- 使用 ASP.NET Core 在 Windows 和 Azure 中静态 ASP.NET 加密
较长的请求标头字段
代理服务器默认设置通常将请求标头字段限制为 4 K 或 8 K,具体取决于平台。 某些应用可能需要超过默认值的字段(例如,使用 Azure Active Directory 的应用)。 如果需要更长的字段,则代理服务器的默认设置需要进行调整。 要应用的值具体取决于方案。 有关详细信息,请参见服务器文档。
- proxy_buffer_size
- proxy_buffers
- proxy_busy_buffers_size
- large_client_header_buffers
警告
除非必要,否则不要提高代理缓冲区的默认值。 提高这些值将增加缓冲区溢出的风险和恶意用户的拒绝服务 (DoS) 攻击风险。
保护应用
启用 AppArmor
Linux 安全模块 (LSM) 是一个框架,它是自 Linux 后的 Linux kernel 的一部分。 LSM 支持安全模块的不同实现。 AppArmor 是实现强制访问控制系统的 LSM,它允许将程序限制在一组有限的资源内。 确保已启用并成功配置 AppArmor。
配置防火墙
关闭所有未使用的外部端口。 通过为配置防火墙提供 CLI,不复杂的防火墙 (ufw) 为 iptables 提供了前端。
警告
如果未正确配置,防火墙将阻止对整个系统的访问。 在使用 SSH 进行连接时,未能指定正确的 SSH 端口最终会将你关在系统之外。 默认端口为 。
安装 ufw,并将其配置为允许所需任何端口上的流量。
Bash
sudo apt-get install ufw
sudo ufw allow /tcp
sudo ufw allow /tcp
sudo ufw allow /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;
配置选项
用其他必需模块配置服务器。 请考虑使用 ModSecurity 等 Web 应用防火墙来加强对应用的保护。
HTTPS 配置
配置应用,以进行安全的 (HTTPS) 本地连接
dotnet run 命令使用应用的
Properties/launchSettings.json 文件,该文件将应用配置为侦听 applicationUrl 属性提供的 URL。 例如,https://localhost:;http://localhost:。
使用以下方法之一配置应用,使其在开发过程中将证书用于 dotnet run 命令或开发环境(Visual Studio Code 中的 F5 或 Ctrl+F5):
- 从配置中替换默认证书(推荐)
- KestrelServerOptions.ConfigureHttpsDefaults
配置反向代理,以便进行安全 (HTTPS) 客户端连接
警告
本部分中的安全配置是一种常规配置,可以作为进一步进行自定义的起点。 我们无法为第三方工具、服务器和操作系统提供支持。 如果使用本部分中的配置,请自行承担风险。 有关更多信息,请访问以下资源:
- 配置 HTTPS 服务器(Nginx 文档)
- mozilla.org SSL Configuration Generator
- 通过指定由受信任的证书颁发机构 (CA) 颁发的有效证书来配置服务器,以侦听端口 上的 HTTPS 流量。
- 通过采用以下“/etc/nginx/nginx.conf”文件中所示的某些做法来增强安全保护。
- 下面的示例未将服务器配置为重定向不安全的请求。 建议使用 HTTPS 重定向中间件。 有关详细信息,请参阅 在 ASP.NET Core 强制实施 HTTPS。 备注对于由服务器配置(而非 HTTPS 重定向中间件)处理安全重定向的开发环境,建议使用临时重定向 () 替代永久性重定向 ()。 链接缓存会导致开发环境中的行为不稳定。
- 添加 Strict-Transport-Security (HSTS) 标头可确保由客户端发起的所有后续请求都通过 HTTPS。 有关设置 Strict-Transport-Security 标头的指南,请参阅 在 ASP.NET Core 强制实施 HTTPS。
- 如果将来将禁用 HTTPS,请使用以下方法之一:不要添加 HSTS 标头。选择短的 max-age 值。
添加 /etc/nginx/proxy.conf 配置文件:
nginx
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 ;
proxy_send_timeout ;
proxy_read_timeout ;
proxy_buffers 4k;
将 /etc/nginx/nginx.conf 配置文件的内容替换为以下文件。 示例包含一个配置文件中的 http 和 server 部分。
nginx
http {
include /etc/nginx/proxy.conf;
limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
server_tokens off;
sendfile on;
# Adjust keepalive_timeout to the lowest possible value that makes sense
# for your use case.
keepalive_timeout ;
client_body_timeout ; client_header_timeout ; send_timeout ;
upstream helloapp{
server :;
}
server {
listen ssl http2;
listen [::]: ssl http2;
server_name example.com *.example.com;
ssl_certificate /etc/ssl/certs/testCert.crt;
ssl_certificate_key /etc/ssl/certs/testCert.key;
ssl_session_timeout 1d;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling off;
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= nodelay;
}
}
}
备注
Blazor WebAssembly 应用需要更大的 burst 参数值才能容纳应用发出的更大量的请求。
备注
上面的示例禁用了在线证书状态协议 (OCSP) 装订。 如果启用,请确认证书支持该功能。
ssl_stapling
ssl_stapling_file
ssl_stapling_responder
ssl_stapling_verify
保护 Nginx 免受点击劫持的侵害
点击劫持(也称为 UI 伪装攻击)是一种恶意攻击,其中网站访问者会上当受骗,从而导致在与当前要访问的页面不同的页面上单击链接或按钮。 使用 X-FRAME-OPTIONS 可保护网站。
缓解点击劫持攻击:
- 编辑 nginx.conf 文件:Bash复制sudo nano /etc/nginx/nginx.conf 添加行:add_header X-Frame-Options "SAMEORIGIN";
- 保存该文件。
- 重启 Nginx。
MIME 类型探查
此标头可阻止大部分浏览器通过 MIME 方式探查来自已声明内容类型的响应,因为标头会指示浏览器不要替代响应内容类型。 使用 nosniff 选项后,如果服务器认为内容是“text/html”,则浏览器将其显示为“text/html”。
- 编辑 nginx.conf 文件:Bash复制sudo nano /etc/nginx/nginx.conf 添加行:add_header X-Content-Type-Options "nosniff";
- 保存该文件。
- 重启 Nginx。
其他 Nginx 建议
在服务器上升级共享框架后,重启服务器托管的 ASP.NET Core 应用。