笔者近期需要部署一款基于B/S架构的后端程序在linux的Debian发行版上,本文章以本次部署遇到的问题为线索,总结如何在Debian上部署ASP.NET Core7.0WebAPI应用程序。
- 使用具有 sudo 特权的标准用户帐户访问linux
- 在linux服务器上安装好支持将要部署的应用程序的.NET运行时
如果还没有安装.NET运行时,可以参考这篇文章在Linux上安装.NET。
我们将应用的“目标运行时”发布为“可移植”,提高我们应用程序的“可移植性”,确保在部署时如果发生失败和错误,不是应用程序发布的问题。
可选择的部署方式:
- 基于Nignx等反向代理服务器部署
- 基于Linux服务管理器部署(如systemd)
- 直接运行应用程序
第一种方式和第二种方式其实没有本质上的区别,只是二者在功能上各有侧重:
至于第三种方式,最为快捷和简单,直接启用应用程序:
root@xxxx:~# /usr/bin/dotnet /root/HuaWei/DotNetPublish/Test2/HuaWeiProject.dll --urls=http://192.168.1.xxx:监听端口
/usr/bin/dotnet
是.NET运行时的根目录/root/HuaWei/DotNetPublish/Test2/
是应用程序发布后的目标目录根目录HuaWeiProject.dll
是应用程序发布根目录下与exe文件同名的dll文件 --urls=http://192.168.1.xxx:监听端口
是我们指定监听的ip和端口,通过访问这个地址,我们可以进入调用我们WebAPI的其实页面我这里开启了swagger,通过在远程或者本地的浏览器访问http://192.168.1.xxx:监听端口/swagger
可以进入swagger调试页面
使用这第三种方式,在命令行键入命令后回车,我们可以成功运行应用程序,但是这个时候问题来了:
虽然我们可以运行成功,并且监听我们指定的地址和端口,但是我们只是运行了dll文件,可能会导致有些配置文件无法生效,笔者在使用这种方式时,就碰到了数据库配置失效的问题
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HN1MKK48QQ2H", Request id "0HN1MKK48QQ2H:00000001": An unhandled exception was thrown by the application.
Autofac.Core.DependencyResolutionException: An exception was thrown while activating Service.BusinessService.ProductInfoService -> DBModels.AgiletyDbContext -> λ:Microsoft.EntityFrameworkCore.DbContextOptions`1[[DBModels.AgiletyDbContext, DBModels, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].
---> MySqlConnector.MySqlException (0x80004005): Access denied for user ''@'localhost' (using password: NO)
at MySqlConnector.Core.ServerSession.ReceiveReplyAsync(IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 894
at MySqlConnector.Core.ServerSession.SendClearPasswordAsync(String password, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 743
at MySqlConnector.Core.ServerSession.SwitchAuthenticationAsync(ConnectionSettings cs, String password, PayloadData payload, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnector/Core/ServerSession.cs:line 712
MySqlConnector.MySqlException (0x80004005): Access denied for user ''@'localhost' (using password: NO)
表名我的user和password都是空的。
综上所述,第三种方式可以运行一些简单的配置少的程序,但并不适合我们的WebAPI,因为我们的API一般都是要访问数据库的。解决这个问题的方法是采用第一种或第二种方式。
笔者选择的是第二种方式基于Linux服务管理器部署
,一方面是因为笔者不熟悉Nignx,另一方面,这是一个Linux系统集成的最佳实践,也被ASP.NET Core官方文档作为推荐之一。
在终端中,我们新建一个服务单元
vim /etc/systemd/system/webapi.service
文件将会建立在 /etc/systemd/system/
目录下,服务单元的名称可以自定义,我这里取的是webapi
,带有一些语义信息,webapi.service
中的内容如下
[Unit]
Description=ASP.NET Core WebAPI Service
[Service]
User=root
Group=root
WorkingDirectory=/root/HuaWei/DotNetPublish/Test
Restart=always
RestartSec=10
Environment=ASPNETCORE_ENVIRONMENT=Production
ExecStart=/usr/bin/dotnet /root/HuaWei/DotNetPublish/Test/HuaWeiProject.dll --urls=http://192.168.1.xxx:xx64
[Install]
WantedBy=multi-user.target
上述内容可以作为模板,需要修改的只有4个地方:
WorkingDirectory=/root/HuaWei/DotNetPublish/Test
替换为程序发布的目标目录在linux文件系统中的绝对位置/root/HuaWei/DotNetPublish/Test/HuaWeiProject.dll
替换为程序发布出的dll文件及文件路径urls=http://192.168.1.xxx:xx64
替换为你想要监听的ip和端口(如果需要远程访问,要确保此端口已经开启了防火墙规则)举一个例子,你的应用程序发布后,与可执行文件(exe)同名的文件为“mydll.dll”,整个目标文件夹为mypublishapi
,放在了linux服务器的root
目录下,现在你要监听http:172.168.1.101:8080
,那么你的webapi.service
应当如下:
[Unit]
Description=ASP.NET Core WebAPI Service
[Service]
User=root
Group=root
WorkingDirectory=/root/mysqlpublishapi
Restart=always
RestartSec=10
Environment=ASPNETCORE_ENVIRONMENT=Production
ExecStart=/usr/bin/dotnet /root/mypublishapi/mydll.dll --urls=http:172.168.1.101:8080
[Install]
WantedBy=multi-user.target
在vim中编辑完上述内容后,保存退出
systemctl daemon-reload
systemctl start webapi.service
systemctl status webapi.service
看到active
则表示已经运行成功,可以远程访问
ExecStart=/usr/bin/dotnet /root/mypublishapi/mydll.dll --urls=http:172.168.1.101:8080
在编写webapi.service
的配置代码时,除了端口,ip地址的选择也是值得考究的。
我们有3个选择:
- linux服务器的公网ip
- localhost
- ifconfig命令查询出的ip地址
笔者因为购买的服务器对ip的限制而在很长一段时间内没有部署成功,下面给出选择方案:
如果远程主机ping得通linux服务器的公网ip,linux服务器自己也ping得通公网ip,那么我们可以选择直接使用公网ip,这种方法允许我们远程访问
如果远程主机ping得通linux服务器的公网ip,linux服务器自己ping不通公网ip,那我们可以选择使用ifconfigfig查询出来的ip,这种方式一般也允许我们远程访问
选择localhost,这种方式只能在本机访问
如果linux服务器配置了公网地址,服务器的网络配置包括公网IP地址,自己ping得通公网ip,就可以远程访问,这是最直接最简单的。
使用ifconfig命令提供了服务器操作系统能够识别的本机IPv4地址,该地址可用于在本地主机上运行应用程序,并且可能会通过反向NAT技术在互联网上映射到服务器。这样,即使是通过ifconfig查看的地址也可用于本地部署和远程访问。
而localhost(127.0.0.1)是一个回环地址,用于在本地主机上访问自身服务。因此,虽然应用程序在本地主机上运行成功,但由于localhost不会通过物理网络接口发送或接收数据包,因此无法从外部网络访问。