ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

.NET 10 Web API 项目在 Ubuntu 服务器上的完整部署与配置指南

.NET 10 Web API 项目在 Ubuntu 服务器上的完整部署与配置指南 最近在将一个基于 .NET 10 开发的 Web API 项目部署到 Ubuntu 服务器时踩了不少坑。从项目发布、服务器环境配置到最终服务上线整个过程涉及多个环节网上资料虽然多但往往零散不成体系特别是针对 .NET 10 和 Ubuntu 24.04/22.04 这类较新组合的完整教程较少。本文将整合一套从零开始的闭环实操方案涵盖项目发布、服务器环境搭建、服务部署、进程守护以及 Swagger 文档访问等全流程并提供完整的代码示例和线上避坑指南。无论你是刚接触 .NET 部署的新手还是需要将现有项目迁移到 Linux 服务器的开发者都能从中找到可复用的解决方案。1. 项目准备与发布在将应用部署到服务器之前我们需要先在本地开发环境中完成项目的构建与发布。1.1 项目结构与技术栈假设我们有一个典型的 ASP.NET Core Web API 项目其核心结构如下MyNet10Api/ ├── MyNet10Api.csproj # 项目文件定义目标框架和依赖 ├── Program.cs # 应用程序入口 ├── appsettings.json # 配置文件 ├── Controllers/ # API控制器目录 │ └── WeatherForecastController.cs ├── Properties/ │ └── launchSettings.json └── 其他业务逻辑文件...项目文件 (MyNet10Api.csproj) 的关键配置指明了我们使用 .NET 10Project SdkMicrosoft.NET.Sdk.Web PropertyGroup TargetFrameworknet10.0/TargetFramework Nullableenable/Nullable ImplicitUsingsenable/ImplicitUsings /PropertyGroup ItemGroup !-- 项目依赖包 -- PackageReference IncludeSwashbuckle.AspNetCore Version6.4.0 / !-- 其他依赖 -- /ItemGroup /Project1.2 本地发布应用发布过程会将项目编译、依赖项打包并生成可在目标环境Linux上独立运行的文件。我们采用“框架依赖”的发布模式这要求目标服务器上已安装对应的 .NET 运行时。打开终端或 PowerShell、CMD导航到项目根目录即.csproj文件所在目录执行以下命令# 发布到 ./publish 目录目标运行时为 linux-x64 dotnet publish -c Release -o ./publish --runtime linux-x64 --self-contained false命令参数详解-c Release使用 Release 配置进行编译会进行代码优化适合生产环境。-o ./publish指定输出目录为当前目录下的publish文件夹。--runtime linux-x64指定目标运行时为 Linux 64 位系统。这是关键参数确保生成兼容 Linux 的可执行文件。--self-contained false发布为“框架依赖”模式。生成的发布包较小但要求服务器安装有对应的 .NET 运行时。如果设置为true则会打包所有依赖包括运行时生成包很大但部署环境无需预装 .NET。执行成功后你会在./publish目录下看到所有发布文件其中包含一个名为MyNet10Api或你的项目名的可执行文件以及appsettings.json、appsettings.Production.json、*.dll等。1.3 发布包内容检查发布完成后建议检查publish目录。一个典型的发布目录应包含MyNet10Api主可执行文件Linux。MyNet10Api.dll应用程序的主程序集。appsettings.json和appsettings.Production.json配置文件。wwwroot/静态文件目录如果有。大量*.dll文件项目依赖和 .NET 运行时库因为是框架依赖模式所以不包含完整的运行时。至此本地发布步骤完成。接下来我们将把这个publish文件夹上传到 Ubuntu 服务器。2. Ubuntu 服务器环境准备在将应用上传之前我们需要在目标 Ubuntu 服务器上准备好运行环境。本文以Ubuntu 22.04 LTS为例其他版本如 20.04 或 24.04 步骤类似。2.1 系统更新与基础工具安装首先通过 SSH 连接到你的 Ubuntu 服务器。连接后建议先更新系统包列表并升级现有软件。# 更新包列表 sudo apt update # 升级已安装的包 sudo apt upgrade -y # 安装一些常用的工具如用于解压的 unzip用于编辑的 vim/nano sudo apt install -y unzip curl vim2.2 安装 .NET 10 运行时由于我们发布时使用了--self-contained false服务器必须安装对应的 .NET 运行时。微软为 Ubuntu 提供了官方的软件包仓库。1. 添加微软包仓库和签名密钥# 下载微软的包仓库 GPG 密钥 wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb # 安装密钥包 sudo dpkg -i packages-microsoft-prod.deb # 删除下载的 deb 文件 rm packages-microsoft-prod.deb2. 安装 .NET 10 运行时# 更新包列表以获取新添加的微软仓库信息 sudo apt update # 安装 ASP.NET Core 运行时 (包含 .NET 运行时) sudo apt install -y aspnetcore-runtime-10.03. 验证安装安装完成后运行以下命令检查 .NET 运行时是否安装成功及其版本。dotnet --info输出中应包含类似Runtime Environment: OS Name: ubuntu ... Version: 10.0.x的信息确认运行时已就绪。2.3 配置防火墙可选但推荐如果服务器启用了防火墙如ufw需要开放 API 应用监听的端口默认为 5000 和 5001HTTP/HTTPS。# 查看防火墙状态 sudo ufw status # 如果状态是 inactive可以跳过。如果是 active开放端口。 # 开放 HTTP (5000) 和 HTTPS (5001) 端口 sudo ufw allow 5000/tcp sudo ufw allow 5001/tcp # 如果使用 Nginx 反向代理后续会讲则需要开放 80 和 443 # sudo ufw allow 80/tcp # sudo ufw allow 443/tcp # 启用防火墙规则 sudo ufw reload环境准备妥当后我们就可以将本地的发布文件上传到服务器了。3. 应用部署与直接运行3.1 上传发布文件到服务器有多种方式可以将本地publish目录上传到服务器例如使用scp命令、SFTP 客户端如 FileZilla或通过 Git。这里演示使用scp命令。在本地机器的终端中导航到包含publish文件夹的上级目录执行# 将整个 publish 目录压缩可选加快传输 tar -czf myapp.tar.gz -C publish . # 使用 scp 上传压缩包到服务器替换 YOUR_SERVER_IP 和 /home/ubuntu 为目标路径 scp myapp.tar.gz ubuntuYOUR_SERVER_IP:/home/ubuntu/然后在服务器上解压并放置到合适的目录。通常我们将应用放在/var目录下。# 连接到服务器后进入用户主目录 cd /home/ubuntu # 创建应用目录例如 /var/www/myapp sudo mkdir -p /var/www/myapp # 将上传的压缩包移动到应用目录并解压 sudo mv myapp.tar.gz /var/www/myapp/ cd /var/www/myapp sudo tar -xzf myapp.tar.gz # 删除压缩包 sudo rm myapp.tar.gz # 修改目录所有权让当前用户有权限根据你的用户名修改 ubuntu sudo chown -R ubuntu:ubuntu /var/www/myapp现在应用文件已经位于/var/www/myapp目录下。3.2 直接运行与测试在配置守护进程或反向代理之前我们可以先直接运行应用测试其是否能在服务器上正常工作。# 进入应用目录 cd /var/www/myapp # 直接运行可执行文件指定生产环境 ./MyNet10Api --environment Production # 或者使用 dotnet 命令运行 dll # dotnet MyNet10Api.dll --environment Production如果一切正常你将看到类似以下的输出表明应用已启动并在监听http://localhost:5000和https://localhost:5001。info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5000 info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:5001 info: Microsoft.Hosting.Lifetime[0] Application started. Press CtrlC to shut down.此时应用仅在服务器本地监听。为了能从外部访问我们需要进行端口转发或配置反向代理。注意直接运行的方式在终端关闭后进程会结束不适合生产环境。我们将在下一步配置进程守护。3.3 处理常见启动错误在直接运行阶段你可能会遇到一些错误错误Failed to bind to address http://localhost:5000原因5000 端口已被其他进程占用。解决更改应用监听端口修改appsettings.json或Program.cs中的UseUrls或停止占用端口的进程。错误The configured user limit (128) ...或文件句柄数限制原因Linux 默认对进程打开文件数有限制高并发应用可能触及。解决临时提高限制ulimit -n 4096或永久修改/etc/security/limits.conf。错误缺少依赖库原因某些原生依赖如用于 HTTPS 的 libssl可能缺失。解决安装常见依赖sudo apt install -y libssl-dev ca-certificates。测试无误后按CtrlC停止应用。接下来配置守护进程让应用在后台稳定运行。4. 使用 Systemd 守护进程systemd是 Ubuntu 的系统和服务管理器我们可以用它来将我们的 .NET 应用创建为一个系统服务实现开机自启、自动重启、日志集中管理等功能。4.1 创建 Service 文件在/etc/systemd/system/目录下为我们的应用创建一个 service 文件。sudo vim /etc/systemd/system/myapp.service将以下内容写入文件请根据你的实际情况修改WorkingDirectory、ExecStart、User和Group。[Unit] DescriptionMy .NET 10 Web API Application Afternetwork.target [Service] Typeexec # 服务启动的工作目录即你的应用发布目录 WorkingDirectory/var/www/myapp # 启动命令指向你的可执行文件 ExecStart/var/www/myapp/MyNet10Api --environment Production # 重启策略总是重启除非手动停止 Restartalways # 如果应用在60秒内没有正常启动则视为失败 RestartSec10 # 杀死进程前等待的秒数 KillSignalSIGINT TimeoutStopSec30 SyslogIdentifiermyapp-dotnet # 运行服务的用户和组建议使用非root用户 Userubuntu Groupubuntu # 设置环境变量如ASPNETCORE_ENV EnvironmentASPNETCORE_ENVIRONMENTProduction # 环境变量绑定所有网络接口而不仅仅是localhost以便外部或反向代理访问 EnvironmentASPNETCORE_URLShttp://*:5000;https://*:5001 # 可选指定Kestrel使用的证书路径如果使用HTTPS # EnvironmentASPNETCORE_Kestrel__Certificates__Default__Path/path/to/cert.pem # EnvironmentASPNETCORE_Kestrel__Certificates__Default__KeyPath/path/to/key.pem # 确保服务以正确的文件权限启动 UMask0007 [Install] WantedBymulti-user.target关键配置说明WorkingDirectory必须设置否则应用可能找不到appsettings.json等文件。ExecStart直接指向可执行文件。也可以使用dotnet /var/www/myapp/MyNet10Api.dll的形式。User/Group使用非 root 用户运行服务是安全最佳实践。EnvironmentASPNETCORE_URLS这个环境变量至关重要。默认情况下.NET Core 应用只监听localhost。将其设置为http://*:5000表示监听所有网络接口的 5000 端口这样 Nginx 或外部请求才能访问到它。Restartalways确保应用崩溃后能自动重启。4.2 启动并启用服务创建好 service 文件后需要重新加载systemd配置然后启动服务。# 重新加载 systemd 配置使新的 service 文件生效 sudo systemctl daemon-reload # 启动 myapp 服务 sudo systemctl start myapp.service # 设置服务开机自启 sudo systemctl enable myapp.service # 查看服务状态确认是否运行成功 sudo systemctl status myapp.service运行status命令后如果看到Active: active (running)字样并且下方没有红色的错误日志说明服务已成功启动。4.3 查看日志与常用命令systemd统一管理服务日志可以通过journalctl命令查看。# 查看 myapp 服务的全部日志 sudo journalctl -u myapp.service # 查看实时日志类似 tail -f sudo journalctl -u myapp.service -f # 查看最近100行日志 sudo journalctl -u myapp.service -n 100 # 查看指定时间段的日志 sudo journalctl -u myapp.service --since 2024-01-01 --until 2024-01-02其他常用服务管理命令# 停止服务 sudo systemctl stop myapp.service # 重启服务 sudo systemctl restart myapp.service # 禁用开机自启 sudo systemctl disable myapp.service # 重新加载服务配置修改 service 文件后 sudo systemctl reload myapp.service现在你的 .NET 10 API 应用已经作为一个系统服务在后台稳定运行了。你可以通过http://你的服务器IP:5000/swagger尝试访问 Swagger UI如果项目启用了的话但通常生产环境不会直接暴露 5000 端口而是通过 Nginx 反向代理。5. 配置 Nginx 反向代理直接通过 IP:Port 访问服务不够友好且不利于管理多个服务、配置 SSL 等。Nginx 作为高性能的反向代理服务器可以帮我们实现将域名如api.yourdomain.com指向我们的应用。处理静态文件减轻应用负担。配置 SSL/TLS实现 HTTPS 加密。负载均衡如果有多实例。5.1 安装 Nginx在 Ubuntu 上安装 Nginx 非常简单sudo apt install -y nginx安装后Nginx 会自动启动。你可以通过sudo systemctl status nginx检查状态。5.2 配置反向代理我们需要为应用创建一个 Nginx 的站点配置文件。通常放在/etc/nginx/sites-available/目录下然后在/etc/nginx/sites-enabled/创建软链接。创建配置文件sudo vim /etc/nginx/sites-available/myapp写入配置内容以下是一个基本的反向代理配置将访问http://your_domain_or_ip的请求转发到运行在http://localhost:5000的 .NET 应用。server { listen 80; # 将 your_domain_or_ip 替换为你的域名或服务器IP server_name your_domain_or_ip; location / { # 转发到后端 .NET 应用 proxy_pass http://localhost:5000; # 传递原始客户端信息 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; # 超时设置 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; # 禁用缓冲适用于 Server-Sent Events 或 WebSockets # proxy_buffering off; } # 可选处理静态文件如果应用有 wwwroot 目录 # location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ { # root /var/www/myapp/wwwroot; # expires 1y; # add_header Cache-Control public, immutable; # } }配置关键点proxy_pass http://localhost:5000;这是核心将请求转发给我们的 .NET 服务。proxy_set_header ...这几行确保后端应用能获取到真实的客户端 IP、协议等信息对于日志记录和某些中间件如获取客户端 IP非常重要。server_name如果配置了域名请填写域名如果直接用 IP 访问可以填写 IP 或_通配。启用站点并测试配置# 在 sites-enabled 中创建软链接 sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/ # 测试 Nginx 配置语法是否正确 sudo nginx -t如果输出syntax is ok和test is successful说明配置正确。重启 Nginx 使配置生效sudo systemctl reload nginx # 或者 sudo systemctl restart nginx现在你应该可以通过服务器的 IP 地址或配置的域名无需加端口 5000直接访问你的 API 了。例如http://your_server_ip/swagger。5.3 配置 HTTPS (SSL/TLS) - 使用 Let‘s Encrypt为了安全生产环境必须启用 HTTPS。我们可以使用 Let‘s Encrypt 提供的免费 SSL 证书并通过certbot工具自动化获取和配置。安装 certbot 和 Nginx 插件sudo apt install -y certbot python3-certbot-nginx获取并自动配置 SSL 证书确保你的域名例如api.example.com的 DNS 记录已经指向了服务器的 IP 地址。确保 Nginx 配置中server_name正确设置为你的域名。运行以下命令certbot会自动修改你的 Nginx 配置。sudo certbot --nginx -d api.example.com按照提示操作输入邮箱同意条款选择是否重定向 HTTP 到 HTTPS强烈建议选择重定向。验证自动续期Let‘s Encrypt 证书有效期为 90 天certbot会配置自动续期任务。可以手动测试续期sudo certbot renew --dry-run配置完成后你的 Nginx 配置文件会被自动修改添加监听 443 端口的 SSL 配置。现在你可以通过https://api.example.com安全地访问你的 API 了。6. 访问 Swagger UI 与 API 测试如果你的项目集成了 Swashbuckle.AspNetCoreSwagger在部署后可能需要关注其访问性。6.1 确保 Swagger 在生产环境可用默认情况下Swagger 可能只在开发环境启用。检查Program.cs中的相关代码// Program.cs var builder WebApplication.CreateBuilder(args); // ... 其他服务配置 builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app builder.Build(); // 配置 HTTP 请求管道 if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } // 为了让生产环境也能访问 Swagger可以移除环境判断 app.UseSwagger(); app.UseSwaggerUI(); // ... 其他中间件配置 app.Run();注意在生产环境暴露 Swagger UI 存在安全风险如暴露 API 结构。建议采取以下措施之一完全禁用保留环境判断生产环境不启用。条件启用通过特定的配置开关或授权策略来控制访问例如只允许特定 IP 或拥有管理员角色的用户访问。使用不同路径可以配置 Swagger UI 在一个非默认的、难以猜测的路径下。6.2 通过 Nginx 访问 Swagger配置好 Nginx 反向代理后访问 Swagger 就很简单了。假设你的 API 根路径是/那么 Swagger UI 的路径通常是/swagger或/swagger/index.html。如果直接通过 IP 和端口访问http://服务器IP:5000/swagger如果通过 Nginx 代理无域名http://服务器IP/swagger如果配置了域名和 HTTPShttps://api.example.com/swagger打开浏览器访问上述地址你应该能看到熟悉的 Swagger UI 界面并可以在此进行 API 测试。6.3 常见 API 访问错误在部署后测试 API 或 Swagger 时可能会遇到以下错误Failed to load API definition或Fetch error原因Swagger 的 JSON 端点通常是/swagger/v1/swagger.json无法访问或返回错误。排查直接访问https://api.example.com/swagger/v1/swagger.json看是否能返回 JSON。检查应用日志sudo journalctl -u myapp.service -f查看是否有相关错误。检查 Nginx 代理配置确保路径转发正确没有遗漏/。检查应用是否配置了路径基UsePathBase这会影响 Swagger JSON 的生成路径。api error: 400 ‘type‘ must be in [“enabled“, “disabled“, “auto”]原因这个错误看起来像是某个 API 接口对请求参数type的校验失败要求其值必须在指定的枚举列表中。这不是部署问题而是你的 API 业务逻辑或客户端调用的问题。解决检查调用该 API 的客户端如 Swagger UI、Postman 或前端应用确保传入的type参数值是“enabled“、“disabled“或“auto“中的一个并且大小写匹配。查看后端该接口的模型定义和验证逻辑。api error: 400 this model‘s maximum context length is ...原因这个错误信息常见于大语言模型LLMAPI提示请求的上下文长度超过了模型限制。如果你的 .NET API 是这类服务的代理或中转需要检查并限制客户端请求的大小。解决在 .NET 应用中配置请求大小限制ConfigureKestrel或RequestSizeLimit属性或在将请求转发给下游 API 前进行校验和截断。7. 部署后的维护与优化应用上线后维护工作同样重要。7.1 应用更新流程当有新版本需要部署时遵循以下流程可以最小化停机时间本地构建发布在开发环境运行dotnet publish -c Release -o ./publish-new --runtime linux-x64。备份当前版本在服务器上备份当前运行的应用目录sudo cp -r /var/www/myapp /var/www/myapp_backup_$(date %Y%m%d)。停止服务sudo systemctl stop myapp.service。替换文件将新的发布包上传并解压到临时目录然后替换应用目录或使用 rsync 同步差异。cd /var/www sudo rsync -av --delete ./myapp-new/ ./myapp/ # 确保文件权限正确 sudo chown -R ubuntu:ubuntu /var/www/myapp启动服务sudo systemctl start myapp.service。验证检查服务状态和日志确认新版本运行正常。回滚预案如果新版本有问题快速回滚停止服务 - 用备份目录替换 - 启动服务。7.2 日志管理与监控集中日志除了journalctl可以考虑将日志发送到集中式系统如 Elastic Stack (ELK)、Seq 或云服务商的日志服务。在 .NET 中使用Serilog等库可以方便地实现。监控健康检查ASP.NET Core 提供了健康检查中间件。在Program.cs中添加services.AddHealthChecks()和app.MapHealthChecks(“/health”)。然后可以通过 Nginx 或监控系统定期访问/health端点来检查应用状态。进程监控使用systemctl status myapp.service或htop等工具监控资源占用CPU、内存。7.3 安全加固建议使用非 root 用户运行如前所述在 systemd service 文件中配置User和Group。防火墙最小化开放端口只开放必要的端口如 80, 443, SSH。定期更新定期运行sudo apt update sudo apt upgrade更新系统和 .NET 运行时。配置应用机密不要将数据库连接字符串、API 密钥等敏感信息硬编码在appsettings.json中。使用环境变量、Azure Key Vault、HashiCorp Vault 或dotnet user-secrets仅开发来管理。禁用不必要的服务如果不需要可以禁用 Swagger UI。7.4 性能调优考虑Kestrel 配置在appsettings.Production.json中调整 Kestrel 服务器的限制如最大请求体大小、并发连接数等。Nginx 缓冲与缓存根据 API 特性调整 Nginx 的proxy_buffering、proxy_buffer_size等参数。对于静态资源利用 Nginx 的缓存能力。数据库连接池确保数据库连接字符串中设置了合理的连接池大小。异步编程确保 API 控制器和业务逻辑充分使用异步async/await以避免阻塞线程。从项目发布到 Ubuntu 服务器部署整个过程涉及开发、运维和安全的交叉知识。本文提供了一条清晰的路径本地发布 - 服务器环境准备 - 部署运行 - 进程守护 - 反向代理 - 安全加固。每个步骤都包含了具体的命令、配置和排错思路你可以根据自己项目的实际情况进行调整。部署不是终点而是稳定运行的起点建立规范的更新流程和监控机制同样重要。
返回列表