ARTICLE DETAIL

资讯详情

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

.NET Web API 从发布到部署:Ubuntu + Nginx + Systemd 全链路实践

.NET Web API 从发布到部署:Ubuntu + Nginx + Systemd 全链路实践 1. 项目背景与核心概念在当前的软件开发流程中将本地开发的 .NET Web API 项目部署到 Linux 服务器特别是 Ubuntu 系统上已成为一项标准且高频的操作。无论是个人项目上线还是企业级应用发布掌握一套从代码发布到服务器部署的完整、可靠的流程是每一位 .NET 开发者必须跨越的实践门槛。本文将以一个典型的 .NET 6/7/8 Web API 项目我们暂且称之为NET10 API为例手把手带你走通从 Visual Studio 发布、文件传输、服务器环境配置、服务进程守护到最终通过 Nginx 反向代理对外提供服务的全链路。这个过程不仅涉及基础的dotnet命令更涵盖了生产环境中必须考虑的权限、日志、进程管理和高可用性配置。如果你之前部署时遇到过诸如“502 Bad Gateway”、“服务进程意外退出”、“依赖库缺失”等问题那么本文将为你提供一套系统性的解决方案和避坑指南。2. 环境准备与版本说明在开始部署之前请确保你拥有以下环境。版本差异可能导致命令或配置略有不同本文会以主流稳定版本为例进行说明并指出关键版本注意事项。开发环境 (Windows/Mac):开发工具:Visual Studio 2022 或 Visual Studio Code。.NET SDK:.NET 6.0, 7.0 或 8.0 LTS 版本。本文示例基于 .NET 6.0但流程对更高版本完全兼容。项目类型:ASP.NET Core Web API 项目。发布配置:采用“框架依赖”或“独立”发布均可本文将演示更通用的“框架依赖”模式。服务器环境 (Ubuntu):操作系统:Ubuntu Server 20.04 LTS 或 22.04 LTS。本文以Ubuntu 22.04 LTS为例。.NET 运行时:需要在服务器上安装与项目匹配的 .NET Runtime 或 SDK。如果项目是“框架依赖”发布则必须安装对应版本的运行时。Web 服务器:Nginx用作反向代理服务器。进程管理:systemd用于将我们的 API 应用托管为系统服务实现开机自启、自动重启。远程连接工具:使用 SSH 客户端如 PowerShell, Terminal, Xshell, MobaXterm连接服务器。版本兼容性核心提示:SDK 与 Runtime:确保服务器上安装的 .NET Runtime 版本大于等于你开发时使用的 SDK 版本。例如用 .NET 6.0 SDK 开发服务器至少安装 .NET 6.0 Runtime。Ubuntu 版本:不同 Ubuntu 版本对应的官方软件源可能不同安装 .NET 的命令源需要根据系统版本选择。项目端口:确保 API 项目监听的端口如5000,5001在服务器防火墙中是开放的。3. 本地项目发布与打包部署的第一步是将开发好的代码编译、打包成一个可以在生产环境直接运行的程序集。3.1 配置项目发布设置在 Visual Studio 中右键点击你的 Web API 项目选择“发布”。发布目标:选择“文件夹”。配置:选择“Release”发布模式。务必不要使用 Debug 模式部署到生产环境。部署模式:选择“框架依赖”。这意味着生成的发布包较小但要求目标服务器有对应的 .NET 运行时。如果选择“独立”则包会包含运行时体积大但环境兼容性好。目标运行时:选择“linux-x64”。因为我们部署到 UbuntuLinux系统。点击“发布”按钮Visual Studio 会在你指定的本地文件夹如bin\Release\net6.0\publish\下生成所有必需的文件。3.2 检查发布包内容发布完成后进入publish文件夹你应该看到类似以下结构的文件publish/ ├── NET10.API.dll # 项目的主程序集 ├── NET10.API.deps.json # 依赖关系文件 ├── NET10.API.runtimeconfig.json # 运行时配置 ├── appsettings.json # 应用配置文件 ├── appsettings.Production.json # 生产环境配置文件如有 ├── web.config # 可能没有对于Linux部署非必需 └── 其他依赖的 .dll 文件关键文件说明:NET10.API.dll: 这是应用程序的入口点。*.deps.json和*.runtimeconfig.json: .NET Core/5 应用运行所必需的清单文件切勿删除。appsettings.json: 配置文件。重要生产环境的数据库连接字符串、密钥等敏感信息切勿直接写在此文件中。应使用环境变量、密钥管理服务或appsettings.Production.json来覆盖并确保该文件已被.gitignore忽略。3.3 打包并传输到服务器为了方便传输我们将整个publish文件夹压缩。在 Windows 上可以将其压缩为NET10_API_Publish.zip。接下来需要将压缩包上传到 Ubuntu 服务器。我们使用scp命令Secure Copy这是通过 SSH 进行安全文件传输的标准工具。打开你的本地终端PowerShell 或 CMD执行以下命令scp -r /本地路径/NET10_API_Publish.zip usernameyour_server_ip:/home/username//本地路径/NET10_API_Publish.zip: 替换为你本地 zip 文件的实际路径。username: 替换为你的 Ubuntu 服务器用户名如ubuntu,root或自定义用户。your_server_ip: 替换为你的服务器公网 IP 地址。/home/username/: 替换为你希望存放文件的目标目录通常放在用户家目录下。输入对应用户的密码后文件即开始传输。4. 服务器环境配置与项目部署通过 SSH 连接到你的 Ubuntu 服务器ssh usernameyour_server_ip4.1 安装 .NET 运行时如果你的项目是“框架依赖”模式服务器必须安装对应的 .NET 运行时。添加 Microsoft 包存储库和安装依赖:# 更新包列表 sudo apt-get update # 安装 HTTPS 传输和证书管理工具 sudo apt-get install -y apt-transport-https ca-certificates # 导入 Microsoft 存储库的 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 rm packages-microsoft-prod.deb安装 .NET 运行时 (以 .NET 6 为例):sudo apt-get update sudo apt-get install -y dotnet-runtime-6.0如果需要安装 .NET 7 运行时将6.0替换为7.0。如果需要安装 SDK以便在服务器上进行dotnet命令操作则安装dotnet-sdk-6.0。验证安装:dotnet --list-runtimes如果安装成功你会看到类似Microsoft.NETCore.App 6.0.25 [/usr/share/dotnet/shared/Microsoft.NETCore.App]的输出。4.2 部署应用程序文件解压文件并移动到部署目录:# 解压到当前目录 unzip NET10_API_Publish.zip -d NET10_API # 创建一个专用的应用程序目录通常放在 /var 下 sudo mkdir -p /var/www/NET10_API # 将解压的文件复制到应用目录并设置所有权 sudo cp -r NET10_API/* /var/www/NET10_API/ # 设置目录所有权给一个非root用户更安全这里假设你的用户名是‘ubuntu’ sudo chown -R ubuntu:ubuntu /var/www/NET10_API # 给予执行权限 sudo chmod x /var/www/NET10_API/NET10.API.dll测试应用能否直接运行:cd /var/www/NET10_API dotnet NET10.API.dll --urls http://*:5000--urls “http://*:5000”参数指定应用监听 5000 端口的所有网络接口。如果看到类似Now listening on: http://[::]:5000的输出说明应用启动成功。按CtrlC停止测试。这只是临时运行我们需要一个更稳定的方式。5. 配置 Systemd 服务守护进程使用systemd来管理我们的 API 应用可以确保应用在服务器启动时自动运行在崩溃时自动重启并方便地查看日志和管理服务状态。创建 systemd 服务文件:sudo nano /etc/systemd/system/net10-api.service编辑服务文件内容:[Unit] DescriptionNET10 API Service Afternetwork.target [Service] # 指定运行服务的用户和组建议使用非root用户 Userubuntu Groupubuntu # 工作目录即我们的应用目录 WorkingDirectory/var/www/NET10_API # 启动命令。%i 代表服务实例名 ExecStart/usr/bin/dotnet /var/www/NET10_API/NET10.API.dll # 重启策略在发生故障时总是重启 Restartalways # 如果服务在10秒内没有正常关闭强制杀死 KillSignalSIGINT TimeoutStopSec10 # 设置环境变量如 ASPNETCORE_ENVIRONMENT EnvironmentASPNETCORE_ENVIRONMENTProduction EnvironmentDOTNET_PRINT_TELEMETRY_MESSAGEfalse [Install] WantedBymulti-user.target关键配置解释:User/Group: 使用非 root 用户运行服务是重要的安全实践。WorkingDirectory: 必须设置否则应用可能找不到appsettings.json等文件。ExecStart: 直接使用dotnet命令启动我们的 DLL。Restartalways: 确保服务异常退出后能自动恢复。Environment: 设置环境变量为Production这会促使应用读取appsettings.Production.json配置文件如果存在。启用并启动服务:# 重新加载 systemd 配置使其识别新服务 sudo systemctl daemon-reload # 设置服务开机自启 sudo systemctl enable net10-api.service # 立即启动服务 sudo systemctl start net10-api.service # 查看服务状态确认是否运行成功 sudo systemctl status net10-api.service如果状态显示为active (running)并且下面没有红色的错误日志说明服务已成功启动。查看应用日志:# 查看服务的所有日志 sudo journalctl -u net10-api.service # 实时跟踪最新日志类似 tail -f sudo journalctl -u net10-api.service -f通过日志你可以排查应用启动过程中的任何问题例如数据库连接失败、配置错误等。6. 配置 Nginx 反向代理目前我们的服务运行在5000端口只能通过http://服务器IP:5000访问。为了使用标准的 HTTP/HTTPS 端口80/443并提供静态文件服务、负载均衡等能力我们需要配置 Nginx 作为反向代理。安装 Nginx:sudo apt-get update sudo apt-get install -y nginx配置 Nginx 站点:删除默认配置为我们的 API 创建新的配置文件。sudo rm /etc/nginx/sites-enabled/default sudo nano /etc/nginx/sites-available/net10-api编辑 Nginx 配置:server { listen 80; # 将 your_domain.com 替换为你的域名或服务器IP server_name your_domain.com; location / { # 将请求代理到运行在 localhost:5000 上的 .NET 应用 proxy_pass http://localhost:5000; # 传递原始请求头信息这对于获取真实客户端IP、协议等信息很重要 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; 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_cache_bypass $http_upgrade; # 设置代理超时时间 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } # 可选配置静态文件服务如果你的API有前端页面 # location /wwwroot/ { # root /var/www/NET10_API; # expires 1h; # } }启用配置并测试:# 创建符号链接以启用站点 sudo ln -s /etc/nginx/sites-available/net10-api /etc/nginx/sites-enabled/ # 测试 Nginx 配置语法是否正确 sudo nginx -t如果输出syntax is ok和test is successful则说明配置正确。重启 Nginx 使配置生效:sudo systemctl restart nginx现在你可以通过浏览器或curl访问http://your_domain.com或http://your_server_ipNginx 会将请求转发给运行在5000端口的 .NET API 应用。7. 防火墙与安全配置为了服务器安全我们需要配置防火墙只开放必要的端口。启用并配置 UFW (Uncomplicated Firewall):# 允许 SSH 连接默认22端口确保你不会把自己锁在外面 sudo ufw allow OpenSSH # 允许 HTTP (80) 和 HTTPS (443) 端口 sudo ufw allow 80/tcp sudo ufw allow 443/tcp # 启用防火墙 sudo ufw enable # 查看防火墙状态 sudo ufw status verbose输出应显示80/tcp和443/tcp是ALLOW状态。重要保护你的 API:使用 HTTPS:申请 SSL 证书如 Let‘s Encrypt 免费证书并在 Nginx 中配置 HTTPS强制将所有 HTTP 请求重定向到 HTTPS。API 密钥/令牌:为你的 API 设计认证和授权机制不要将敏感接口直接暴露在公网。环境变量管理:数据库连接字符串、JWT Secret 等敏感信息务必通过服务器环境变量或专业的密钥管理工具注入而不是写在appsettings.json文件中。定期更新:定期运行sudo apt update sudo apt upgrade更新系统和软件包修复安全漏洞。8. 常见问题与排查思路部署过程中难免会遇到问题下面是一个快速排查清单问题现象可能原因排查步骤与解决方案访问http://服务器IP返回 502 Bad Gateway1. .NET 应用服务未运行。2. Nginx 配置中proxy_pass地址或端口错误。3. 应用监听的地址不是localhost或0.0.0.0。1.sudo systemctl status net10-api.service检查服务状态查看日志sudo journalctl -u net10-api.service。2. 检查/etc/nginx/sites-available/net10-api中proxy_pass是否指向http://localhost:5000。3. 确认应用启动时监听了*:5000在Program.cs或appsettings.json中配置Urls。服务状态为failed或inactive1. 应用本身有运行时错误如缺少依赖、配置错误。2.systemd服务文件配置错误如路径、用户权限。3. 端口已被占用。1. 仔细查看服务日志sudo journalctl -u net10-api.service -n 50 --no-pager。2. 检查服务文件中WorkingDirectory和ExecStart的路径是否正确以及User是否有该目录的读取和执行权限。3. 使用 sudo netstat -tlnpdotnet命令未找到.NET 运行时/ SDK 未安装或未正确安装。运行dotnet --info确认。重新执行安装步骤并确保添加了正确的微软源。Nginx 配置测试失败 (nginx -t报错)Nginx 配置文件语法错误。根据错误提示检查配置文件常见错误有缺少分号;、括号不匹配、路径错误等。应用运行但无法连接数据库1. 生产环境数据库连接字符串错误。2. 服务器防火墙未开放数据库端口如 MySQL 3306。3. 数据库用户权限不足或不允许远程连接。1. 检查appsettings.Production.json或环境变量中的连接字符串。2. 如果是云服务器还需检查云服务商的安全组规则。3. 登录数据库检查用户授权GRANT语句。9. 最佳实践与工程建议使用进程管理工具 (systemd):永远不要仅通过nohup或在后台运行生产服务。systemd提供了完善的监控、日志收集和生命周期管理。非 Root 用户运行:始终使用一个专用的、权限受限的系统用户来运行你的应用程序这能极大限制漏洞被利用后的影响范围。配置与代码分离:将数据库连接字符串、API 密钥、第三方服务凭证等所有敏感信息从代码库中移除。使用appsettings.Production.json不被 Git 跟踪或环境变量来管理。结构化日志:在Program.cs中使用 Serilog 或 NLog 等日志框架将日志输出到文件并配置日志轮转避免日志文件无限增大。同时在systemd服务文件中可以设置StandardOutputjournal和StandardErrorjournal来将日志集成到系统日志。健康检查端点:在 API 项目中实现一个简单的健康检查端点如/health返回应用状态。这便于监控系统如 Prometheus或负载均衡器判断服务是否健康。使用 CI/CD 流水线:对于频繁更新的项目考虑使用 GitHub Actions, GitLab CI/CD 或 Jenkins 等工具自动化构建、测试和部署过程。流水线可以自动完成本文中大部分手动步骤。备份与回滚:在更新应用前备份当前的发布目录和数据库。准备好快速回滚的方案例如通过切换systemd服务文件指向旧版本目录。从 Visual Studio 的一个发布按钮到用户通过浏览器稳定访问你的 API中间跨越了环境配置、文件传输、服务托管、网络代理和安全加固等多个环节。本文详细拆解了每一步的操作和原理旨在为你构建一条可重复、可维护的部署路径。掌握这套流程后你不仅可以部署自己的 .NET API其核心思想进程守护、反向代理、配置分离同样适用于其他语言如 Python Flask, Node.js的应用部署。接下来你可以进一步探索 Docker 容器化部署它将应用及其所有依赖打包成一个镜像能提供更好的环境一致性和部署效率是现代化部署的进阶方向。
返回列表