Linux CentOS7部署ASP.NET Core应用程序,并配置Nginx反向代理服务器和Supervisor守护服务
<h2>前言:</h2><p> 本篇文章主要讲解的是如何在Linux CentOS7操作系统搭建.NET Core运行环境并发布ASP.NET Core应用程序,以及配置Nginx反向代理服务器。因为公司的项目一直都是托管在Window服务器IIS上,对于Linux服务器上托管.NET Core项目十分好奇。因为好奇,因此就有了这篇文章关于如何在Linux CentOS7系统中配置.NET Core运行环境,部署项目和反向代理服务器的配置。</p>
<h2>一、开发工具介绍</h2>
<h3>Xshell:</h3>
<p> 是一个强大的安全终端模拟软件,它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议。Xshell 通过互联网到远程主机的安全连接以及它创新性的设计和特色帮助用户在复杂的网络环境中享受他们的工作。</p>
<h3>Xftp:</h3>
<p> 是一个功能强大的SFTP、FTP 文件传输软件。使用了 Xftp 以后,MS Windows 用户能安全地在 UNIX/Linux 和 Windows PC 之间传输文件。Xftp 能同时适应初级用户和高级用户的需要。它采用了标准的 Windows 风格的向导,它简单的界面能与其他 Windows 应用程序紧密地协同工作,此外它还为高级用户提供了众多强劲的功能特性。</p>
<p>当然这两个工具提供了非商业用途的免费使用权限,你只需要填写对应的信息即可。</p>
<p>下载地址:https://www.netsarang.com/en/free-for-home-school/</p>
<h2>二、.NET Core环境搭建</h2>
<p>环境下载地址:https://dotnet.microsoft.com/download</p>
<h3>查看操作系统版本:</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">lsb_release -a
</pre>
</div>
<p><img src="https://img2018.cnblogs.com/blog/1336199/201905/1336199-20190523115257697-816587575.png" alt=""></p>
<h3>Install .NET Core SDK【安装.Net Core SDK】:</h3>
<p><strong>概述:</strong>.NET Core SDK 是一组库和工具,开发人员可用其创建 .NET Core 应用程序和库。</p>
<p>它包含以下用于构建和运行应用程序的组件:</p>
<blockquote>
<p>.NET Core CLI 工具。<br>.NET Core 库和运行时。<br>DotNet 驱动程序(https://docs.microsoft.com/zh-cn/dotnet/core/tools/index?tabs=netcore2x#driver)。</p>
</blockquote>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm
sudo yum install dotnet-sdk-2.2
</pre>
</div>
<p><strong>官网最新安装教程:</strong></p>
<p><strong>https://dotnet.microsoft.com/download/linux-package-manager/centos7/sdk-current</strong></p>
<p> <img src="https://img2018.cnblogs.com/common/1336199/201911/1336199-20191107103253077-292815127.png" alt=""></p>
<h3>查看安装环境版本信息:</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">dotnet --info
</pre>
</div>
<p><img src="https://img2018.cnblogs.com/blog/1336199/201905/1336199-20190523140035919-2057699361.png" alt=""></p>
<h2>三、项目发布并部署到CentOS服务器中</h2>
<h3>使用Visual Studio发布项目:</h3>
<p><strong>部署方式选择框架依赖</strong></p>
<p><strong>原因:</strong>因为前面我们已经安装好了.Net Core应用程序运行所需要的运行环境和对应的SDK了。</p>
<p><strong>目标运行时选中可移植的</strong></p>
<p><strong>原因:</strong>可以适用所有操作系统。</p>
<p><img src="https://img2018.cnblogs.com/blog/1336199/201905/1336199-20190523142020966-192112159.png" alt=""></p>
<h3>将发布好的文件使用xftp上传到服务器:</h3>
<p><img src="https://img2018.cnblogs.com/blog/1336199/201905/1336199-20190523144622682-685701545.png" alt=""></p>
<h3>使用xshell查看项目是否上传成功:</h3>
<p><img src="https://img2018.cnblogs.com/blog/1336199/201905/1336199-20190523144818722-849684953.png" alt=""></p>
<h3>运行项目:</h3>
<p><strong>首先要进入项目目录:</strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">cd MyDotNetApplication/
</pre>
</div>
<p><strong>运行项目:</strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">dotnet FirstCore.dll -d &
</pre>
</div>
<p><img src="https://img2018.cnblogs.com/blog/1336199/201911/1336199-20191105010045055-507708187.png" alt=""></p>
<h3>查看后台是否能够运行:</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">wget http://localhost:5000</pre>
</div>
<p>或者</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">curlhttp://localhost:5000
</pre>
</div>
<p><img src="https://img2018.cnblogs.com/blog/1336199/201911/1336199-20191105010141116-2147305880.png" alt=""></p>
<h3>运行程序提示问题:</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">warn: Microsoft.AspNetCore.Server.Kestrel
Unable to bind to http://localhost:5000 on the IPv6 loopback interface: 'Cannot assign requested address'.
</pre>
</div>
<p><strong>出现这个警告的话,IPV6s回送的时候不可达,也就是说你只能够在服务器内部通过本地访问,但是无法通过外网ip对网站进行访问。</strong></p>
<p><strong> 解决方法:</strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">首先停止网站:
查看运行程序端口:jobs -l
结束当前程序:kill 端口号
重新运行程序,最后设置如下访问方式【当然这样子做只是为了看运行效果,下面我们需要配置Nginx以及守护服务】:
dotnet FirstCore.dll --server.urls="http://*:5000"</pre>
</div>
<p><strong>然后在输入外网ip+5000端口号进行访问,访问成功,页面如下图所示:</strong></p>
<p><img src="https://img2018.cnblogs.com/i-beta/1336199/201911/1336199-20191107004245443-59137680.png" alt=""></p>
<h2>四、配置Nginx反向代理:</h2>
<h3>使用反向代理服务器的优势:</h3>
<blockquote>
<pre>Kestrel 非常适合从 ASP.NET Core 提供动态内容。 但是,Web 服务功能不像服务器(如 IIS、Apache 或 Nginx)那样功能丰富。 反向代理服务器可以卸载 HTTP 服务器的工作负载,如提供静态内容、缓存请求、<br>压缩请求和 HTTPS 终端。 反向代理服务器可能驻留在专用计算机上,也可能与 HTTP 服务器一起部署。</pre>
</blockquote>
<p>反向代理服务器接收来自网络的 HTTP 请求,并将这些请求转发到 (边缘服务器)Kestrel,请求流程图如下所示:</p>
<p><img src="https://img2018.cnblogs.com/blog/1336199/201911/1336199-20191105004749667-268734595.png" alt=""></p>
<h3>下载、安装、启动Nginx命令:</h3>
<h4>首先添加CentOS 7 EPEL源:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">sudo yum install epel-release </pre>
</div>
<h4>(拓展)添加EPEL源的作用:</h4>
<blockquote>
<p> EPEL(Extra Packages for Enterprise Linux)是由 Fedora 社区打造的、为 RHEL 及其衍生发行版(如 CentOS 等)提供高质量软件包的项目。安装了 EPEL 源之后,就像在 Fedora 上一样,通过“yum install 软件包名”,即可安装很多之前需要编译安装的软件、常用的软件以及一些比较流行的软件,比如现在流行的 nginx、redis 等。安装了EPEL源之后,都可以使用 EPEL 很方便的安装更新。</p>
</blockquote>
<h4>使用以下yum命令安装Nginx :</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">sudo yum install nginx
</pre>
</div>
<h4>因为是首次安装 Nginx,通过运行以下命令显式启动: </h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">sudo service nginx start</pre>
</div>
<p>或者: </p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">sudo systemctl start nginx
</pre>
</div>
<h4>查看Nginx是否启动: </h4>
<p><strong>查看Nginx的运行状态: </strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">systemctl status nginx </pre>
</div>
<p><strong><img src="https://img2018.cnblogs.com/blog/1336199/201911/1336199-20191105014530324-1449477469.png" alt=""></strong></p>
<p><strong>用ps -ef列出进程列表,然后通过grep过滤nginx:</strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">ps -ef | grep nginx</pre>
</div>
<p><img src="https://img2018.cnblogs.com/blog/1336199/201911/1336199-20191105012727327-1382737468.png" alt=""></p>
<h4> 设置系统启动时启用Nginx:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">sudo systemctl enable nginx</pre>
</div>
<h4>查看系统防火墙状态:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">service iptables status</pre>
</div>
<p>如下图所示我的防火墙是关闭的: </p>
<p><img src="https://img2018.cnblogs.com/blog/1336199/201911/1336199-20191105013515340-1293846687.png" alt=""></p>
<h4> 如果系统中的防火墙未关闭,请输入以下命令来允许 HTTP 和 HTTPS 通信: </h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload </pre>
</div>
<h4>在浏览器中输入服务器的 IP 地址:http://123.xx.xx.88/来验证 Nginx 是否成功运行:</h4>
<p>如下图所示能看到 Nginx 的默认转发网页则说明Nginx运行成功了:<img src="https://img2018.cnblogs.com/blog/1336199/201905/1336199-20190527152023864-588424458.png" alt="" width="1156" height="312"></p>
<h3>修改 Nginx 配置文件:</h3>
<h4>使用Vim命令打开Nginx默认配置:</h4>
<p>若要将 Nginx 配置为反向代理服务器用来将请求转接到 ASP.NET Core 应用,请修改Nginx的默认配置文件 /etc/nginx/nginx.conf 在文本编辑器中打开它,并将内容替换为以下内容:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;"> vim /etc/nginx/nginx.conf</pre>
</div>
<h4>将原server中的默认配置内容替换成以下内容:</h4>
<p><img src="https://img2018.cnblogs.com/i-beta/1336199/201911/1336199-20191106232951664-1328003900.png" alt=""></p>
<p> </p>
<p> </p>
<p><strong> 替换的内容:</strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">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;
}
} </pre>
</div>
<h4>保存编辑,并退出文本编辑器:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">esc+:wq保存修改并退出vim编辑器</pre>
</div>
<h4>验证Nginx的默认文件配置是否正确:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">nginx -t
</pre>
</div>
<p><img src="https://img2018.cnblogs.com/i-beta/1336199/201911/1336199-20191106013121028-1785174697.png" alt=""> </p>
<h4>查看端口在实例中是否正常被监听:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">netstat -an | grep 80
</pre>
</div>
<p><img src="https://img2018.cnblogs.com/i-beta/1336199/201911/1336199-20191106233830955-290948067.png" alt=""></p>
<h4>重启Nginx:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">nginx -s reload
</pre>
</div>
<h4>最后直接通过服务器ip地址访问ASP.NET Core应用程序:</h4>
<p><strong>提示502 Bad Gateway:</strong></p>
<p><strong><img src="https://img2018.cnblogs.com/i-beta/1336199/201911/1336199-20191107002511784-376271472.png" alt=""></strong></p>
<p> </p>
<p> </p>
<p> </p>
<p><strong>原因:Linux CentOs中的项目没有运行!</strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">到对应的项目目录,运行项目,输入以下命令:
进入项目目录:
cd MyDotNetApplication/
运行项目:
dotnet FirstCore.dll -d & </pre>
</div>
<p><strong>再次访问服务器Ip,项目成功运行:</strong></p>
<p><strong><img src="https://img2018.cnblogs.com/i-beta/1336199/201911/1336199-20191107004553166-138052234.png" alt=""></strong></p>
<p> <img src="https://img2018.cnblogs.com/common/1336199/201911/1336199-20191107005727350-1144120025.png" alt=""></p>
<h2>五、配置Supervisor守护服务:</h2>
<h3>为什么要配置Supervisor:</h3>
<p> 使用Linux部署过ASP.NET Core应用程序的小伙伴都清楚,我们在部署项目都是通过Shell进行项目启动运行的。有时候我们会发现当我们关闭了Shell后,应用程序会立马宕机无法访问,需要我们重新进入服务器连接Shell输入dot命令重启应用程序。在生成环境中对于这种没有对应用程序进行任何的守护和监听的部署是非常的糟糕的,因此我们需要守护服务或者容器(推荐使用Docker)来对应用程序进行监听保护作用,当监听到应用进程停止,Supervisor会自动重启该应用程序。</p>
<h3>Supervisor简单概述:</h3>
<p> 首先简单了解下Supervisor, Supervisor(http://supervisord.org/)是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。它可以很方便的监听、启动、停止、重启一个或多个进程。用Supervisor管理的进程,当一个进程意外被杀死,supervisort监听到进程死后,会自动将它重新拉起,很方便的做到进程自动恢复的功能,不再需要自己写shell脚本来控制。</p>
<h3>安装Supervisor:</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">yum install python-setuptools
easy_install supervisor
</pre>
</div>
<h3>配置Supervisor</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;"> //新建指定目录,为了避免默认配置会在某些更新覆盖掉
mkdir /etc/supervisor
//这里是在新建好的目录新建conf文件,这里关键。默认文件会建立在/etc目录下
echo_supervisord_conf > /etc/supervisor/supervisord.conf</pre>
</div>
<h4><strong>新建成功如下图所示:</strong></h4>
<p><img src="https://img2018.cnblogs.com/i-beta/1336199/201912/1336199-20191209000733877-16094021.png" alt=""></p>
<h4>打开supervisord.conf,要将文件的结尾部分替换掉以便后面能读取到我们的配置文件</h4>
<p><strong>打开supervisord.conf配置文件:</strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">vim supervisord.conf </pre>
</div>
<p><strong>在文件的结尾找到以下配置代码:</strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">;<br>;files = relative/directory/*.ini
</pre>
</div>
<p><img src="https://img2018.cnblogs.com/i-beta/1336199/201912/1336199-20191209013633921-218242682.png" alt=""></p>
<p><strong>将代码替换为如下,注意前后不能带 ;和空格符号</strong></p>
<div class="cnblogs_Highlighter">
<p> <br> files = conf.d/*.conf</p>
</div>
<p><img src="https://img2018.cnblogs.com/i-beta/1336199/201912/1336199-20191209015547118-1625134417.png" alt=""></p>
<h3>配置对ASP.NET Core应用的守护:</h3>
<h4>进入目录 /etc/supervisor/ 新建 conf.d文件夹:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">mkdir conf.d </pre>
</div>
<h4>在【/etc/supervisor/conf.d/】目录下新建一个AspNetCoreWebApi.conf配置文件:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">vim AspNetCoreWebApi.conf </pre>
</div>
<p><strong>直接复制以下内容:</strong></p>
<div class="cnblogs_Highlighter">
<p><br>command=dotnet FirstCore.dll;<br>directory=/root/MyDotNetApplication/;<br>autorestart=true;<br>stderr_logfile=/var/log/AspNetCoreWebApi.err.log;<br>stdout_logfile=/var/log/AspNetCoreWebApi.out.log;<br>environment=ASPNETCORE_ENVIRONMENT=Production;<br>user=root;<br>stopsignal=INT;</p>
</div>
<p><strong>配置说明: </strong></p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">
command=dotnet FirstCore.dll; 运行程序的命令
directory=/root/MyDotNetApplication/; 命令执行的目录
autorestart=true; 程序意外退出是否自动重启
stderr_logfile=/var/log/AspNetCoreWebApi.err.log;错误日志文件
stdout_logfile=/var/log/AspNetCoreWebApi.out.log;输出日志文件
environment=ASPNETCORE_ENVIRONMENT=Production;进程环境变量
user=root;进程执行的用户身份
stopsignal=INT</pre>
</div>
<p><strong>注意:如果服务已启动,修改配置文件可用“supervisorctl reload”命令来使其生效。</strong></p>
<h4>运行supervisord,查看是否生效,命令如下:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">supervisord -c /etc/supervisor/supervisord.conf
ps -ef | grep AspNetCoreWebApi //AspNetCoreWebApi是上面配置的program名称:</pre>
</div>
<h3><strong>配置Supervisor</strong><strong>开机启动</strong></h3>
<h4>新建一个“supervisord.service”文件</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">
Description=Supervisor daemon
Type=forking
ExecStart=/usr/bin/supervisord -c /etc/supervisor/supervisord.conf
ExecStop=/usr/bin/supervisorctl shutdown
ExecReload=/usr/bin/supervisorctl reload
KillMode=process
Restart=on-failure
RestartSec=42s
WantedBy=multi-user.target</pre>
</div>
<h4>将supervisord.service文件拷贝至:</h4>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">/usr/lib/systemd/system/ #系统目录下</pre>
</div>
<p><strong>执行命令:systemctl enable supervisord #激活开机启动命令</strong></p>
<p><strong>执行命令:systemctl is-enabled supervisord #来验证是否为开机启动</strong></p>
<h4><strong>下面是一些常用的 Supervisor 的命令 (参考https://segmentfault.com/a/1190000003955182):</strong></h4>
<table style="height: 503px; width: 1245px">
<thead>
<tr class="firstRow"><th align="left" width="149"> 命令</th><th align="left" width="601.3333333333334"> 说明</th></tr>
</thead>
<tbody>
<tr>
<td align="left" width="149">supervisord</td>
<td align="left" width="601.3333333333334">初始启动Supervisord,启动、管理配置中设置的进程</td>
</tr>
<tr>
<td align="left" width="149">supervisorctl stop myproject</td>
<td align="left" width="601.3333333333334">停止某一个进程(programxxx),programxxx为里配置的值,这个示例就是chatdemon</td>
</tr>
<tr>
<td align="left" width="149">supervisorctl start myproject</td>
<td align="left" width="601.3333333333334">启动某个进程</td>
</tr>
<tr>
<td align="left" width="149">supervisorctl restart myproject</td>
<td align="left" width="601.3333333333334">重启某个进程</td>
</tr>
<tr>
<td align="left" width="149">supervisorctl stop groupworker</td>
<td align="left" width="601.3333333333334">重启所有属于名为groupworker这个分组的进程(start,restart同理)</td>
</tr>
<tr>
<td align="left" width="149">supervisorctl stop all</td>
<td align="left" width="582.3333333333334">停止全部进程,注:start、restart、stop都不会载入最新的配置文件</td>
</tr>
<tr>
<td align="left" width="149">supervisorctl reload</td>
<td align="left" width="601.3333333333334">载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程</td>
</tr>
<tr>
<td align="left" width="149">supervisorctl update</td>
<td align="left" width="601.3333333333334">根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启。注意:显示用stop停止掉的进程,用reload或者update都不会自动重启</td>
</tr>
</tbody>
</table>
<p> </p>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
<blockquote >
<p style='font-family:YouYuan;font-size: 16px;margin: 0 auto 0.01em auto;'><span style='font-size: 17px; '>作者名称:</span>追逐时光者</p>
<p style='font-family:YouYuan;font-size: 16px;margin: 0 auto 0.01em auto;'><span style='font-size: 17px; '>作者简介:</span>一个热爱编程、善于分享、喜欢学习、探索、尝试新事物和新技术的全栈软件工程师。</p>
<p style='font-family:YouYuan;font-size: 16px;margin: 0 auto 0.01em auto;'>
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。如果该篇文章对您有帮助的话,可以点一下右下角的【♥推荐♥】,希望能够持续的为大家带来好的技术文章,文中可能存在描述不正确的地方,欢迎指正或补充,不胜感激。
</p>
</blockquote><br><br>
来源:https://www.cnblogs.com/Can-daydayup/p/10911067.html
頁:
[1]