<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Nes的草稿箱</title>
  
  <subtitle>Draft</subtitle>
  <link href="https://nestealin.com/atom.xml" rel="self"/>
  
  <link href="https://nestealin.com/"/>
  <updated>2026-03-20T12:06:00.336Z</updated>
  <id>https://nestealin.com/</id>
  
  <author>
    <name>NesTeaLin</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>acme.sh多域名自动化统一管理</title>
    <link href="https://nestealin.com/450bd21e/"/>
    <id>https://nestealin.com/450bd21e/</id>
    <published>2024-08-31T19:20:36.000Z</published>
    <updated>2026-03-20T12:06:00.336Z</updated>
    
    <content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><blockquote><p>前情提要:</p><p>这会是一篇系列文章，本想先从 SSL 基本概念科普讲起，结果坑越挖越大。为了不鸽太久，就先把最近刚更完的证书相关操作先来逐步填坑，等后续再反补科普向内容（但愿）。</p><p>本系列内容大致分为四篇:</p><ul><li>SSL 相关基础知识-科普向 （有生之年）</li><li><a href="https://nestealin.com/89bbe3ef/">acme.sh 快速入门-主要功能及申请SSL证书实践</a></li><li><a href="https://nestealin.com/814887c9/">acme.sh 最佳实践-自动申请证书与自动部署群晖 DSM</a></li><li><a href="https://nestealin.com/450bd21e/">acme.sh 进阶版-多域名自动化管理</a> （<strong>本篇</strong>）</li><li>acme.sh 阶段性终结-批量部署</li></ul></blockquote><p>在上一篇 <a href="https://nestealin.com/814887c9/">acme.sh 最佳实践-自动申请证书与自动部署群晖 DSM</a> 中，我们已经完成了单个域名的证书申请及自动化维护。但在我们日常生活中，难免会有多个域名、多个 NS 托管商，进而需要申请和维护多套 SSL 证书的情况，这时候光靠简单的指令执行可能不利于集中维护。</p><p>因此，本篇将以笔者个人用途场景出发，以简单脚本的方式统一维护多域名、多 NS 配置，实现多套 SSL 证书的便捷维护操作。</p><hr><h2 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h2><p>在开始”最佳实践”之前，重申一下后续执行 acme.sh 的相关环境，方便还没阅读过前文的读者直接上手。</p><h3 id="基础环境"><a href="#基础环境" class="headerlink" title="基础环境"></a>基础环境</h3><p>在开始之前需要升级系统的 CA 证书，以避免后续在申请 SSL 证书时遇到问题。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yum <span class="token function">install</span> -y ca-certificates<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="安装-acme-sh"><a href="#安装-acme-sh" class="headerlink" title="安装 acme.sh"></a>安装 acme.sh</h3><p>在本例中将以 root 用户进行安装。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">ACME_HOME</span><span class="token operator">=</span><span class="token string">"/usr/local/acme.sh"</span><span class="token function">mkdir</span> -p <span class="token variable">$ACME_HOME</span>/data<span class="token builtin class-name">cd</span> /usr/local/src<span class="token function">curl</span> -so acme.sh https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh<span class="token function">chmod</span> +x acme.sh <span class="token operator">&amp;&amp;</span> ./acme.sh --install-online <span class="token punctuation">\</span>--home <span class="token variable">$ACME_HOME</span> <span class="token punctuation">\</span>--cert-home <span class="token variable">$ACME_HOME</span>/data <span class="token punctuation">\</span>--accountemail <span class="token string">"nestealin@gmail.com"</span> <span class="token punctuation">\</span>--nocron<span class="token function">ls</span> ./acme.sh <span class="token operator">&amp;&amp;</span> <span class="token function">rm</span> -f ./acme.sh <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">cd</span> <span class="token variable">$ACME_HOME</span> <span class="token operator">&amp;&amp;</span> <span class="token function">ls</span> -l<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>参数释义:</p><ul><li><code>--home</code>: 表示安装主目录(默认含 <code>config-home</code>)，用于安装 <code>acme.sh</code>。默认情况下，它安装在 <code>~/.acme.sh</code>。</li><li><code>--cert-home</code>: 用于保存你签发的证书 ( 如: <code>/usr/local/acme.sh/data/</code> )。默认情况下，它跟随 <code>--config-home</code> 默认值。</li><li><code>--accountemail</code>: 用于在 Let’s Encrypt 注册账户的电子邮件地址，以便后续收到续期通知邮件。</li><li><code>--nocron</code>: 安装 <code>acme.sh</code> 后不自动创建定时任务。</li></ul><h3 id="更换签发-CA"><a href="#更换签发-CA" class="headerlink" title="更换签发 CA"></a>更换签发 CA</h3><blockquote><p>注: <strong>该步骤非必须</strong>，可以根据实际情况按需修改。</p></blockquote><p>由于 acme.sh 默认向 ZeroSSL CA 申请 SSL 证书。然而，本次笔者将其修改为 Let’s Encrypt 作为证书的 CA。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --set-default-ca --server letsencrypt<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>以上，完成环境的基本准备，可以开始实践操作。</p><h3 id="工具下载"><a href="#工具下载" class="headerlink" title="工具下载"></a>工具下载</h3><p>在<a href="https://github.com/nestealin/acme_cli/releases">本仓库 Release</a> 中已提供 Linux 系统打包好的二进制文件，可以在有限的操作系统中做到”开箱即用”。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">mkdir</span> /usr/local/acme.sh/scripts<span class="token builtin class-name">cd</span> /usr/local/acme.sh/scripts<span class="token function">curl</span> -sL https://github.com/nestealin/acme_cli/releases/download/v1.0.0/acme_cli -o acme_cli<span class="token function">chmod</span> +x ./acme_cli<span class="token function">ln</span> -s /usr/local/acme.sh/scripts/acme_cli /usr/local/bin/acme_cli<span class="token function">curl</span> -sL https://github.com/nestealin/acme_cli/releases/download/v1.0.0/domains_config.yaml.sample -o domains_config.yaml<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="基本配置"><a href="#基本配置" class="headerlink" title="基本配置"></a>基本配置</h3><p>参照 domains_config.yaml 内容，结合域名、NS特性进行修改。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /usr/local/acme.sh/scripts<span class="token function">vim</span> domains_config.yaml<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h4 id="主域名证书"><a href="#主域名证书" class="headerlink" title="主域名证书"></a>主域名证书</h4><p>以下是一个 example.com 域名将 DNS 托管在 Cloudflare，打算申请 <code>example.com</code> 及 <code>*.example.com</code> 域名证书的配置格式:</p><pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token key atrule">domains</span><span class="token punctuation">:</span>  <span class="token comment"># Cloudflare-SingleDomain</span>  <span class="token comment"># issue for example.com and *.example.com</span>  <span class="token punctuation">-</span> <span class="token key atrule">domain_name</span><span class="token punctuation">:</span> example.com    <span class="token key atrule">domain_ns</span><span class="token punctuation">:</span> dns_cf    <span class="token key atrule">ns_key</span><span class="token punctuation">:</span> CF_Token    <span class="token key atrule">ns_key_value</span><span class="token punctuation">:</span> ABCDEFG1234567890    <span class="token key atrule">ns_secret</span><span class="token punctuation">:</span> CF_Account_ID    <span class="token key atrule">ns_secret_value</span><span class="token punctuation">:</span> HIJKLMN0987654321    <span class="token key atrule">SAN_domains</span><span class="token punctuation">:</span> <span class="token string">""</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>参数释义:</p><ul><li><code>domain_name</code>: 证书主域名，即主要签发的域名，默认签发三级泛域名 <code>*.foo.org</code>；</li><li><code>domain_ns</code>: 主域名所属 DNS 服务商，语法格式遵循<a href="https://nestealin.com/89bbe3ef/#toc-heading-35">acme.sh DNS API 简称</a>；</li><li><code>ns_key</code>: DNS API 参数环境变量”Key”名称，遵循<a href="https://nestealin.com/89bbe3ef/#toc-heading-35">acme.sh DNS API 变量</a>；</li><li><code>ns_key_value</code>: DNS API 参数环境变量”Key”对应值；</li><li><code>ns_secret</code>: DNS API 参数环境变量”Secret”名称，遵循<a href="https://nestealin.com/89bbe3ef/#toc-heading-35">acme.sh DNS API 变量</a>；</li><li><code>ns_secret_value</code>: DNS API 参数环境变量”Secret”对应值</li><li><code>SAN_domains</code>: 证书是否需要签发多个子域名，如果不存在则保持 <code>&quot;&quot;</code> 即可，如果存在则以列表格式追加；</li></ul><h4 id="多SAN证书"><a href="#多SAN证书" class="headerlink" title="多SAN证书"></a>多SAN证书</h4><p>以下是一个主域名为 foo.net，其 DNS 托管在 DNSPod，打算申请:</p><ul><li><code>foo.net</code></li><li><code>*.foo.net</code></li><li><code>dev.foo.net</code></li><li><code>*.dev.foo.net</code></li><li><code>test.foo.net</code></li><li><code>*.test.foo.net</code></li></ul><p>多SAN域名证书的配置格式:</p><pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token key atrule">domains</span><span class="token punctuation">:</span>  <span class="token comment"># DNSPod-MultiSANs</span>  <span class="token comment"># issue for foo.net, *.foo.net, dev.foo.net, *.dev.foo.net, test.foo.net and *.test.foo.net</span>  <span class="token punctuation">-</span> <span class="token key atrule">domain_name</span><span class="token punctuation">:</span> foo.net    <span class="token key atrule">domain_ns</span><span class="token punctuation">:</span> dns_dp    <span class="token key atrule">ns_key</span><span class="token punctuation">:</span> DP_Id    <span class="token key atrule">ns_key_value</span><span class="token punctuation">:</span> <span class="token number">123456</span>    <span class="token key atrule">ns_secret</span><span class="token punctuation">:</span> DP_Key    <span class="token key atrule">ns_secret_value</span><span class="token punctuation">:</span> ABCDEFG1234567890    <span class="token key atrule">SAN_domains</span><span class="token punctuation">:</span>    <span class="token punctuation">-</span> dev.foo.net    <span class="token punctuation">-</span> test.foo.net<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>注: </p><ul><li>更多供应商配置信息请参考: <a href="https://nestealin.com/89bbe3ef/#toc-heading-35">自动 DNS API 简称及变量速查 | Nes的草稿箱</a></li></ul></blockquote><hr><h2 id="基本功能"><a href="#基本功能" class="headerlink" title="基本功能"></a>基本功能</h2><blockquote><p>前提条件:</p><ul><li>已经安装 acme.sh 基本环境；</li><li>已经完成 domains_config.yaml 文件的域名与DNS API配置；</li></ul></blockquote><p>以下，将主要介绍二进制工具的管理功能。</p><h4 id="查询当前托管中的证书"><a href="#查询当前托管中的证书" class="headerlink" title="查询当前托管中的证书"></a>查询当前托管中的证书</h4><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">acme_cli list<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>效果:</p><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell"><span class="token comment"># acme_cli list</span>Main_Domain     KeyLength  SAN_Domains                                                                             CA               Created               Renewexample.com      <span class="token string">"ec-256"</span>   *.example.com,*.dev.example.com,*.pre.example.com                                          LetsEncrypt.org  <span class="token number">2024</span>-08-30T14:37:23Z  <span class="token number">2024</span>-10-28T14:37:23Z<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h4 id="续期单一证书"><a href="#续期单一证书" class="headerlink" title="续期单一证书"></a>续期单一证书</h4><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">acme_cli renew <span class="token variable">$&#123;CERT_DOMAIN&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><blockquote><p>注意: 这里的 <code>CERT_DOMAIN</code> 指的是证书的主域名，即使用 <code>acme_cli list</code> 输出中的 <strong>“Main_Domain”</strong> 字段。</p></blockquote><p>该指令允许使用 <code>--force</code> 参数可以实现强制更新，如: 即使当前证书距离到期大于30天，也可以执行强制更新。</p><h4 id="更新单一域名-新增-SAN-域名"><a href="#更新单一域名-新增-SAN-域名" class="headerlink" title="更新单一域名 | 新增 SAN 域名"></a>更新单一域名 | 新增 SAN 域名</h4><p>该功能具备如下几种能力:</p><ul><li>可以是新增域名时的<strong>首次证书申请</strong>；</li><li>可以是在已有证书的情况下追加SAN域名<strong>重新签发</strong>；</li><li>可以是对<strong>现有证书执行更新</strong>，效果等同于 <code>acme_cli renew $&#123;CERT_DOMAIN&#125;</code>；</li></ul><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">acme_cli issue example.com --force<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>可以增加 <code>--force</code> 参数可以实现强制更新，如: 即使当前证书距离到期日期大于30天，也可以执行强制更新。</p><h4 id="续期所有证书"><a href="#续期所有证书" class="headerlink" title="续期所有证书"></a>续期所有证书</h4><pre class="line-numbers language-shell" data-language="shell"><code class="language-shell">acme_cli renew_all<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>该指令默认为强制更新维护中的所有证书。</p><h4 id="移除证书"><a href="#移除证书" class="headerlink" title="移除证书"></a>移除证书</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme_cli remove example.com<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>该功能会同时移除 acme.sh 维护中的证书，以及本地证书目录，避免需要人为二次清理。（因为删除操作是高危操作，所以会有二次确认的交互内容）</p><blockquote><p>注: 由于该工具只是根据笔者习惯简单封装了 acme.sh 的几个常用核心功能，如有自定义扩展需求，可以拉取<a href="https://github.com/nestealin/acme_cli?tab=readme-ov-file#%E8%87%AA%E5%AE%9A%E4%B9%89%E4%BF%AE%E6%94%B9">仓库源码</a>自定义扩展/修改。</p></blockquote><hr><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><h3 id="1-新增域名"><a href="#1-新增域名" class="headerlink" title="1. 新增域名"></a>1. 新增域名</h3><p>假设现在有一个新的域名(foo.org)，其 DNS 托管在”阿里云DNS”上，现在要签发一套 <code>foo.org</code> 和 <code>*.foo.org</code> 域名的 SSL 证书。可以参照如下流程进行:</p><p>在配置文件中新增域名</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /usr/local/acme.sh/scripts<span class="token function">vim</span> domains_config.yaml<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>新增域名 <code>foo.org</code> 如:</p><pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token punctuation">-</span> <span class="token key atrule">domain_name</span><span class="token punctuation">:</span> foo.org  <span class="token key atrule">domain_ns</span><span class="token punctuation">:</span> dns_ali  <span class="token key atrule">ns_key</span><span class="token punctuation">:</span> Ali_Key  <span class="token key atrule">ns_key_value</span><span class="token punctuation">:</span> LTA123456  <span class="token key atrule">ns_secret</span><span class="token punctuation">:</span> Ali_Secret  <span class="token key atrule">ns_secret_value</span><span class="token punctuation">:</span> ABCDEFG1234567890  <span class="token key atrule">SAN_domains</span><span class="token punctuation">:</span> <span class="token string">""</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>参数释义:</p><ul><li><code>domain_name</code>: 证书主域名，即主要签发的域名，默认签发三级泛域名 <code>*.foo.org</code>；</li><li><code>domain_ns</code>: 主域名所属 DNS 服务商，语法格式遵循<a href="https://nestealin.com/89bbe3ef/#toc-heading-35">acme.sh DNS API 简称</a>；</li><li><code>ns_key</code>: DNS API 参数环境变量”Key”名称，遵循<a href="https://nestealin.com/89bbe3ef/#toc-heading-35">acme.sh DNS API 变量</a>；</li><li><code>ns_key_value</code>: DNS API 参数环境变量”Key”对应值；</li><li><code>ns_secret</code>: DNS API 参数环境变量”Secret”名称，遵循<a href="https://nestealin.com/89bbe3ef/#toc-heading-35">acme.sh DNS API 变量</a>；</li><li><code>ns_secret_value</code>: DNS API 参数环境变量”Secret”对应值</li><li><code>SAN_domains</code>: 证书是否需要签发多个子域名，如果不存在则保持 <code>&quot;&quot;</code> 即可，如果存在则以列表格式追加；</li></ul><p>执行新增</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme_cli issue foo.org<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>静候执行结束即可。</p><h3 id="2-追加SAN域名"><a href="#2-追加SAN域名" class="headerlink" title="2. 追加SAN域名"></a>2. 追加SAN域名</h3><p>假设现在要给以前发过证书的 foo.org 域名证书中追加 SAN 域名，其中 SAN 域名有:</p><ul><li><code>dev.foo.org</code></li><li><code>bar.foo.org</code><br>那么，签发后的证书理论上应该包含如下几个域名:</li><li><code>foo.org</code></li><li><code>*.foo.org</code></li><li><code>dev.foo.org</code></li><li><code>*.dev.foo.org</code></li><li><code>bar.foo.org</code></li><li><code>*.bar.foo.org</code></li></ul><p>可以参照如下流程进行:</p><p>在配置文件中新增域名</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /usr/local/acme.sh/scripts<span class="token function">vim</span> domains_config.yaml<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>找到已存在的域名 <code>foo.org</code>，对 <code>SAN_domains</code> 字段追加预期的子域名:</p><pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token punctuation">-</span> <span class="token key atrule">domain_name</span><span class="token punctuation">:</span> foo.org  <span class="token key atrule">domain_ns</span><span class="token punctuation">:</span> dns_ali  <span class="token key atrule">ns_key</span><span class="token punctuation">:</span> Ali_Key  <span class="token key atrule">ns_key_value</span><span class="token punctuation">:</span> LTA123456  <span class="token key atrule">ns_secret</span><span class="token punctuation">:</span> Ali_Secret  <span class="token key atrule">ns_secret_value</span><span class="token punctuation">:</span> ABCDEFG1234567890  <span class="token key atrule">SAN_domains</span><span class="token punctuation">:</span>  <span class="token punctuation">-</span> dev.foo.org  <span class="token punctuation">-</span> bar.foo.org<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>参数释义:</p><ul><li><code>domain_name</code>: 证书主域名，即主要签发的域名，默认签发三级泛域名 <code>*.foo.org</code>；</li><li><code>domain_ns</code>: 主域名所属 DNS 服务商，语法格式遵循<a href="https://nestealin.com/89bbe3ef/#toc-heading-35">acme.sh DNS API 简称</a>；</li><li><code>ns_key</code>: DNS API 参数环境变量”Key”名称，遵循<a href="https://nestealin.com/89bbe3ef/#toc-heading-35">acme.sh DNS API 变量</a>；</li><li><code>ns_key_value</code>: DNS API 参数环境变量”Key”对应值；</li><li><code>ns_secret</code>: DNS API 参数环境变量”Secret”名称，遵循<a href="https://nestealin.com/89bbe3ef/#toc-heading-35">acme.sh DNS API 变量</a>；</li><li><code>ns_secret_value</code>: DNS API 参数环境变量”Secret”对应值</li><li><code>SAN_domains</code>: 因为存在多个 SAN 域名，则以列表格式追加；</li></ul><p>执行新增</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme_cli issue foo.org --force<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>静候执行结束即可。</p><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本篇主要讲述如何使用 <a href="https://github.com/nestealin/acme_cli">acme_cli</a> 工具简单实现多域名、多 NS 托管商的统一管理，来进一步降低用户的维护复杂度。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;前情提要:&lt;/p&gt;
&lt;p&gt;这会是一篇系列文章，本想先从 SSL 基本概念科普讲起，结果坑越挖越大。为了不鸽太久，就</summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="SSL" scheme="https://nestealin.com/tags/SSL/"/>
    
    <category term="Let&#39;s Encrypt" scheme="https://nestealin.com/tags/Let-s-Encrypt/"/>
    
    <category term="证书" scheme="https://nestealin.com/tags/%E8%AF%81%E4%B9%A6/"/>
    
    <category term="域名" scheme="https://nestealin.com/tags/%E5%9F%9F%E5%90%8D/"/>
    
    <category term="CA" scheme="https://nestealin.com/tags/CA/"/>
    
  </entry>
  
  <entry>
    <title>acme.sh实现自动申请证书与自动部署群晖DSM</title>
    <link href="https://nestealin.com/814887c9/"/>
    <id>https://nestealin.com/814887c9/</id>
    <published>2024-08-31T17:01:31.000Z</published>
    <updated>2026-03-20T12:06:00.339Z</updated>
    
    <content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><blockquote><p>前情提要:</p><p>这会是一篇系列文章，本想先从 SSL 基本概念科普讲起，结果坑越挖越大。为了不鸽太久，就先把最近刚更完的证书相关操作先来逐步填坑，等后续再反补科普向内容（但愿）。</p><p>本系列内容大致分为四篇:</p><ul><li>SSL 相关基础知识-科普向 （有生之年）</li><li><a href="https://nestealin.com/89bbe3ef/">acme.sh 快速入门-主要功能及申请SSL证书实践</a></li><li><a href="https://nestealin.com/814887c9/">acme.sh 最佳实践-自动申请证书与自动部署群晖 DSM</a> （<strong>本篇</strong>）</li><li><a href="https://nestealin.com/450bd21e/">acme.sh 进阶版-多域名自动化管理</a></li><li>acme.sh 阶段性终结-批量部署</li></ul></blockquote><p>本篇文章将基于之前入门篇介绍的基本功能，结合最佳实践，进一步深入讲解如何自动签发和续期证书，以及如何通过该工具部署和更新群晖 DSM 上的证书。</p><hr><h2 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h2><p>在开始”最佳实践”之前，先来一下后续执行 acme.sh 的相关环境，方便还没阅读过前文的读者直接上手。</p><h3 id="基础环境"><a href="#基础环境" class="headerlink" title="基础环境"></a>基础环境</h3><p>在开始之前需要升级系统的 CA 证书，以避免后续在申请 SSL 证书时遇到问题。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yum <span class="token function">install</span> -y ca-certificates<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="安装-acme-sh"><a href="#安装-acme-sh" class="headerlink" title="安装 acme.sh"></a>安装 acme.sh</h3><p>在本例中将以 root 用户进行安装。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">ACME_HOME</span><span class="token operator">=</span><span class="token string">"/usr/local/acme.sh"</span><span class="token function">mkdir</span> -p <span class="token variable">$ACME_HOME</span>/data<span class="token builtin class-name">cd</span> /usr/local/src<span class="token function">curl</span> -so acme.sh https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh<span class="token function">chmod</span> +x acme.sh <span class="token operator">&amp;&amp;</span> ./acme.sh --install-online <span class="token punctuation">\</span>--home <span class="token variable">$ACME_HOME</span> <span class="token punctuation">\</span>--cert-home <span class="token variable">$ACME_HOME</span>/data <span class="token punctuation">\</span>--accountemail <span class="token string">"nestealin@gmail.com"</span> <span class="token punctuation">\</span>--nocron<span class="token function">ls</span> ./acme.sh <span class="token operator">&amp;&amp;</span> <span class="token function">rm</span> -f ./acme.sh <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">cd</span> <span class="token variable">$ACME_HOME</span> <span class="token operator">&amp;&amp;</span> <span class="token function">ls</span> -l<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>参数释义:</p><ul><li><code>--home</code>: 表示安装主目录(默认含 <code>config-home</code>)，用于安装 <code>acme.sh</code>。默认情况下，它安装在 <code>~/.acme.sh</code>。</li><li><code>--cert-home</code>: 用于保存你签发的证书 ( 如: <code>/usr/local/acme.sh/data/</code> )。默认情况下，它跟随 <code>--config-home</code> 默认值。</li><li><code>--accountemail</code>: 用于在 Let’s Encrypt 注册账户的电子邮件地址，以便后续收到续期通知邮件。</li><li><code>--nocron</code>: 安装 <code>acme.sh</code> 后不自动创建定时任务。</li></ul><h3 id="更换签发-CA"><a href="#更换签发-CA" class="headerlink" title="更换签发 CA"></a>更换签发 CA</h3><blockquote><p>注: <strong>该步骤非必须</strong>，可以根据实际情况按需修改。</p></blockquote><p>由于 acme.sh 默认向 ZeroSSL CA 申请 SSL 证书。然而，本次笔者将其修改为 Let’s Encrypt 作为证书的默认 CA。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --set-default-ca --server letsencrypt<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>以上，完成环境的基本准备，可以开始实践操作。</p><hr><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><h3 id="1-使用-Cloudflare-API-Token-自动签发及更新-SSL-证书"><a href="#1-使用-Cloudflare-API-Token-自动签发及更新-SSL-证书" class="headerlink" title="1. 使用 Cloudflare API Token 自动签发及更新 SSL 证书"></a>1. 使用 Cloudflare API Token 自动签发及更新 SSL 证书</h3><p>前置说明:</p><ul><li>本方法所使用的是 Cloudflare API Token 方式对个别 zone 实现 DNS 单独管理；</li><li>如果有多个 zone 或使用 Global API Key 可参考: <a href="https://github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cf">dnsapi · acmesh-official/acme.sh Wiki · GitHub</a></li></ul><h4 id="获取-API-Token"><a href="#获取-API-Token" class="headerlink" title="获取 API Token"></a>获取 API Token</h4><ol><li>访问  <a href="https://dash.cloudflare.com/profile/api-tokens">Cloudflare 控制台</a> 获取 token。出于安全考虑，建议不要使用秘钥，而是为 Certbot / acme.sh 创建单独的 API 令牌。</li></ol><img src="/814887c9/image-20240901010407534.png" class=""><ol start="2"><li>选择 API 令牌模板为“编辑区域 DNS”</li></ol><img src="/814887c9/image-20240901010551966.png" class=""><ol start="3"><li>填写令牌信息，选择要管理的域名（Zone）</li></ol><p>启用编辑设定”Token 名称”（例如: “For Certbot Auto Confirm”）</p><img src="/814887c9/image-20240901010622537.png" class=""><img src="/814887c9/image-20240901010630073.png" class=""><ol start="4"><li>确认摘要信息</li></ol><img src="/814887c9/image-20240901010711032.png" class=""><ol start="5"><li>创建成功，请妥善保管你的 token （红框内容已脱敏）</li></ol><img src="/814887c9/image-20240901010732545.png" class=""><p>记下最后创建的 <strong>API Token</strong>。</p><h4 id="获取账户-ID"><a href="#获取账户-ID" class="headerlink" title="获取账户 ID"></a>获取账户 ID</h4><p>进入 zone 概述页面，右下角（下图红框）即可看到:</p><img src="/814887c9/image-20240901010759545.png" class=""><p>记下<strong>账户 ID</strong>（Account ID）。</p><h4 id="编辑隐私文件"><a href="#编辑隐私文件" class="headerlink" title="编辑隐私文件"></a>编辑隐私文件</h4><blockquote><p>注: 在本文中，acme.sh 的安装目录在 <code>/usr/local/acme.sh</code></p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">vim</span> /usr/local/acme.sh/account.conf<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>将获取到的 Cloudflare API Token 以如下格式追加到文件中</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">CF_Token</span><span class="token operator">=</span><span class="token string">"&lt;API Token>"</span><span class="token builtin class-name">export</span> <span class="token assign-left variable">CF_Account_ID</span><span class="token operator">=</span><span class="token string">"&lt;Account ID>"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>然后保存并退出即可</p><h4 id="申请证书"><a href="#申请证书" class="headerlink" title="申请证书"></a>申请证书</h4><p>通过执行以下命令实现自动签发 SSL 证书:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --set-default-ca --server letsencryptacme.sh --issue <span class="token punctuation">\</span>--dns dns_cf <span class="token punctuation">\</span>-d <span class="token string">"nestealin.com"</span> <span class="token punctuation">\</span>-d <span class="token string">"*.nestealin.com"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>命令释义:</p><ul><li><code>--set-default-ca --server letsencrypt</code>: 显式告诉 acme.sh 修改 SSL 证书默认申请的 CA 为 Let’ Encrypt；（默认为ZeroSSL）</li><li><code>--issue</code>: 申请证书参数，如果需要续期可将参数改为 <code>--renew</code> 即可；</li><li><code>--dns dns_cf</code>: 使用 Cloudflare 的 DNS API 模块自动申请证书；</li><li><code>-d 域名</code>: 用来声明 SSL 证书所需要签发的域名有哪些，如有多个域名则继续追加 <code>-d</code> 参数即可；（具体限制详见: ）</li></ul><p>执行过程参考:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 部分内容有做脱敏</span><span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:26 CST <span class="token number">2024</span><span class="token punctuation">]</span> Using CA: https://acme-v02.api.letsencrypt.org/directory<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:26 CST <span class="token number">2024</span><span class="token punctuation">]</span> Creating domain key<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:26 CST <span class="token number">2024</span><span class="token punctuation">]</span> The domain key is here: /usr/local/acme.sh/data/nestealin.com_ecc/nestealin.com.key<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:26 CST <span class="token number">2024</span><span class="token punctuation">]</span> Multi <span class="token assign-left variable">domain</span><span class="token operator">=</span><span class="token string">'DNS:nestealin.com,DNS:*.nestealin.com'</span><span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:30 CST <span class="token number">2024</span><span class="token punctuation">]</span> Getting webroot <span class="token keyword">for</span> <span class="token assign-left variable">domain</span><span class="token operator">=</span><span class="token string">'nestealin.com'</span><span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:30 CST <span class="token number">2024</span><span class="token punctuation">]</span> Getting webroot <span class="token keyword">for</span> <span class="token assign-left variable">domain</span><span class="token operator">=</span><span class="token string">'*.nestealin.com'</span><span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:30 CST <span class="token number">2024</span><span class="token punctuation">]</span> Adding TXT value: YzuIQsaUWFaPxiYmHfMEvW2spm3Ezz2cpZ0R02F-7F8 <span class="token keyword">for</span> domain: _acme-challenge.nestealin.com<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:34 CST <span class="token number">2024</span><span class="token punctuation">]</span> Adding record<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:35 CST <span class="token number">2024</span><span class="token punctuation">]</span> Added, OK<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:35 CST <span class="token number">2024</span><span class="token punctuation">]</span> The TXT record has been successfully added.<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:35 CST <span class="token number">2024</span><span class="token punctuation">]</span> Adding TXT value: iS4HZJtsG9e-2iQyINf6r3N1PUbkpWD2_3g_c_vf8Dw <span class="token keyword">for</span> domain: _acme-challenge.nestealin.com<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:38 CST <span class="token number">2024</span><span class="token punctuation">]</span> Adding record<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:39 CST <span class="token number">2024</span><span class="token punctuation">]</span> Added, OK<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:39 CST <span class="token number">2024</span><span class="token punctuation">]</span> The TXT record has been successfully added.<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:03:39 CST <span class="token number">2024</span><span class="token punctuation">]</span> Let<span class="token string">'s check each DNS record now. Sleeping for 20 seconds first.[Sat Aug 31 16:04:00 CST 2024] You can use '</span>--dnssleep<span class="token string">' to disable public dns checks.[Sat Aug 31 16:04:00 CST 2024] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck[Sat Aug 31 16:04:00 CST 2024] Checking nestealin.com for _acme-challenge.nestealin.com[Sat Aug 31 16:04:02 CST 2024] Success for domain nestealin.com '</span>_acme-challenge.nestealin.com<span class="token string">'.[Sat Aug 31 16:04:02 CST 2024] Checking nestealin.com for _acme-challenge.nestealin.com[Sat Aug 31 16:04:03 CST 2024] Success for domain nestealin.com '</span>_acme-challenge.nestealin.com<span class="token string">'.[Sat Aug 31 16:04:03 CST 2024] All checks succeeded[Sat Aug 31 16:04:03 CST 2024] Verifying: nestealin.com[Sat Aug 31 16:04:04 CST 2024] Pending. The CA is processing your order, please wait. (1/30)[Sat Aug 31 16:04:08 CST 2024] Success[Sat Aug 31 16:04:08 CST 2024] Verifying: *.nestealin.com[Sat Aug 31 16:04:09 CST 2024] Pending. The CA is processing your order, please wait. (1/30)[Sat Aug 31 16:04:13 CST 2024] Success[Sat Aug 31 16:04:13 CST 2024] Removing DNS records.[Sat Aug 31 16:04:13 CST 2024] Removing txt: YzuIQsaUWFaPxiYmHfMEvW2spm3Ezz2cpZ0R02F-7F8 for domain: _acme-challenge.nestealin.com[Sat Aug 31 16:04:17 CST 2024] Successfully removed[Sat Aug 31 16:04:17 CST 2024] Removing txt: iS4HZJtsG9e-2iQyINf6r3N1PUbkpWD2_3g_c_vf8Dw for domain: _acme-challenge.nestealin.com[Sat Aug 31 16:04:21 CST 2024] Successfully removed[Sat Aug 31 16:04:21 CST 2024] Verification finished, beginning signing.[Sat Aug 31 16:04:21 CST 2024] Let'</span>s finalize the order.<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:04:21 CST <span class="token number">2024</span><span class="token punctuation">]</span> <span class="token assign-left variable">Le_OrderFinalize</span><span class="token operator">=</span><span class="token string">'https://acme-v02.api.letsencrypt.org/acme/finalize/123123/456789'</span><span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:04:23 CST <span class="token number">2024</span><span class="token punctuation">]</span> Downloading cert.<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:04:23 CST <span class="token number">2024</span><span class="token punctuation">]</span> <span class="token assign-left variable">Le_LinkCert</span><span class="token operator">=</span><span class="token string">'https://acme-v02.api.letsencrypt.org/acme/cert/abcd'</span><span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:04:24 CST <span class="token number">2024</span><span class="token punctuation">]</span> Cert success.-----BEGIN CERTIFICATE-----<span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token operator">==</span>-----END CERTIFICATE-----<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:04:24 CST <span class="token number">2024</span><span class="token punctuation">]</span> Your cert is in: /usr/local/acme.sh/data/nestealin.com_ecc/nestealin.com.cer<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:04:24 CST <span class="token number">2024</span><span class="token punctuation">]</span> Your cert key is in: /usr/local/acme.sh/data/nestealin.com_ecc/nestealin.com.key<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:04:24 CST <span class="token number">2024</span><span class="token punctuation">]</span> The intermediate CA cert is in: /usr/local/acme.sh/data/nestealin.com_ecc/ca.cer<span class="token punctuation">[</span>Sat Aug <span class="token number">31</span> <span class="token number">16</span>:04:24 CST <span class="token number">2024</span><span class="token punctuation">]</span> And the full-chain cert is in: /usr/local/acme.sh/data/nestealin.com_ecc/fullchain.cer<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>如上述输出，全程由 acme.sh 的 DNS API 模块自动完成两次 DNS Challenge 验证，并最终签发证书。</p><blockquote><p>注: DNS API 模块除了在验证过程中自动添加 TXT 记录外，在验证通过后还会自动删除对应解析记录，避免残留不必要的解析记录。</p></blockquote><p>至此，就已经完成了域名证书的自动签发，可以根据输出提示拿到证书及私钥文件使用了。</p><blockquote><p>注: 在 Nginx 使用场景中，建议使用 <code>fullchain.cer</code> 作为证书文件，因为它包含了域名证书和中间证书（即具备完整证书链），从而确保客户端能够正确验证服务器的身份。</p></blockquote><h4 id="证书续期"><a href="#证书续期" class="headerlink" title="证书续期"></a>证书续期</h4><p>对于证书续期，完全参照”申请证书”的步骤即可，全程也是由 DNS API 模块完成自动化操作。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --renew <span class="token punctuation">\</span>--dns dns_cf <span class="token punctuation">\</span>-d <span class="token string">"nestealin.com"</span> <span class="token punctuation">\</span>-d <span class="token string">"*.nestealin.com"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>默认情况下，当证书距离到期日大于 30 天是不会进行续期操作的，当然也可以增加 <code>--force</code> 参数来实现强制更新。更新后的证书将直接覆盖原有的证书内容。</p><h3 id="2-将证书部署到群晖-DSM-更新群晖-DSM-证书"><a href="#2-将证书部署到群晖-DSM-更新群晖-DSM-证书" class="headerlink" title="2. 将证书部署到群晖 DSM | 更新群晖 DSM 证书"></a>2. 将证书部署到群晖 DSM | 更新群晖 DSM 证书</h3><p>在群晖 DSM 中，默认情况下只有 Synology 默认证书，此时如果想以自有域名将群晖服务对外暴露，此时就需要用到我们申请的 SSL 证书。</p><img src="/814887c9/image-20240901010901834.png" class=""><p>然而，默认情况下只能通过<a href="https://kb.synology.cn/zh-cn/DSM/help/DSM/AdminCenter/connection_certificate?version=7">页面后台</a>进行替换，但对于三个月一换的证书来说还是非常繁琐的。恰好 acme.sh 也集成了群晖的证书部署模块，所以下文将介绍如何使用该模块进行远程部署与更新群晖 DSM 证书。</p><p>acme.sh 集成了群晖的三种更新方式:</p><ul><li>支持<strong>临时管理员</strong>更新（推荐，但只能将 acme.sh 部署在群晖本机上）</li><li>支持用户直接使用账号密码登录，即”<strong>常规登录</strong>“；</li><li>支持基于 OTP 的<strong>双重验证登录</strong>，但是对于脚本执行上会与”常规登录”有配置差异，请在使用时注意；</li></ul><p>可以根据实际情况自行选择，由于笔者不想把群晖当做”有状态”服务器来维护，所以本次将主要介绍如何使用”<strong>常规登录</strong>“的方式，即通过 HTTPS 远程(管理机)登录的方式，部署/更新群晖 DSM 证书。</p><h4 id="常规登录"><a href="#常规登录" class="headerlink" title="常规登录"></a>常规登录</h4><p><strong>前置说明</strong>:</p><ul><li>本样例中，群晖属于内网后端，<strong>有前置的 Nginx 实现反向代理</strong>，即访问群晖域名时，会先经过独立的 Nginx 才会访问到群晖；</li><li>在执行 acme.sh 脚本节点上<strong>存在已签发证书</strong>；</li></ul><h5 id="创建独立的管理用户"><a href="#创建独立的管理用户" class="headerlink" title="创建独立的管理用户"></a>创建独立的管理用户</h5><p>为了管理方便，避免管理员变动影响证书更新，在本示例中新建了一个独立的管理用户来维护证书更新。</p><p>首先，登陆群晖 DSM，进入<strong>控制面板</strong> - <strong>用户与群组</strong> - <strong>用户账号</strong> - <strong>新增</strong></p><img src="/814887c9/image-20240901011028206.png" class=""><p>简单输入账号及密码</p><img src="/814887c9/image-20240901011054107.png" class=""><p>需要加入管理员群组(<strong>administrators</strong>)</p><img src="/814887c9/image-20240901011109298.png" class=""><p>文件夹访问权限、配额、速率限制保持默认即可</p><p>应用访问权限可以先全部拒绝，<strong>只开放 DSM 权限</strong>即可</p><img src="/814887c9/image-20240901011127965.png" class=""><p>权限总览</p><img src="/814887c9/image-20240901011140429.png" class=""><p>点击保存后完成管理员账号创建</p><p>然后进入控制面板 - 用户与群组 - 用户账号 - 找到并选择刚才创建的管理员账号 - <strong>编辑</strong></p><p>在应用程序中找到 DSM，将”允许”改为”<strong>按 IP</strong>“</p><img src="/814887c9/image-20240901011156055.png" class=""><p>依次选择”<strong>添加 IP 地址</strong>“-“<strong>来源 IP</strong>“-“<strong>子网</strong>“，然后填写管控机所在的网络段即可 （或者限制单一主机）</p><blockquote><p>注: 由于是内部管控用户，所以建议按 IP / 子网来限制网络登录。</p></blockquote><img src="/814887c9/image-20240901011208379.png" class=""><p>最后依次保存退出即可。</p><h5 id="创建执行脚本"><a href="#创建执行脚本" class="headerlink" title="创建执行脚本"></a>创建执行脚本</h5><p>为了后续能够通过定时任务自动执行，所以采取脚本形式包装执行内容。</p><p>创建并进入脚本路径，创建公共变量(<code>var</code>)及部署脚本文件(<code>ssl_cert_deploy_to_synologyDSM.sh</code>):</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">mkdir</span> -p /usr/local/acme.sh/scripts<span class="token builtin class-name">cd</span> /usr/local/acme.sh/scripts<span class="token function">cat</span> <span class="token operator">&lt;&lt;</span> <span class="token string">EOF<span class="token bash punctuation"> <span class="token operator">></span> var</span>#!/bin/bash# ACME ENVexport ACME_HOME="/usr/local/acme.sh"export PATH=\<span class="token variable">$ACME_HOME</span>:\<span class="token environment constant">$PATH</span>export ACME_SSL_CERT_DATA_PATH="\<span class="token variable">$ACME_HOME</span>/data"EOF</span><span class="token function">cat</span> <span class="token operator">&lt;&lt;</span> <span class="token string">EOF<span class="token bash punctuation"> <span class="token operator">></span> ssl_cert_deploy_to_synologyDSM.sh</span>#!/bin/bash# Load ENVSCRIPT_PATH=\<span class="token variable"><span class="token variable">$(</span><span class="token builtin class-name">cd</span> <span class="token punctuation">\</span><span class="token punctuation">$(</span>dirname <span class="token string">"\<span class="token variable">$0</span>"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token builtin class-name">pwd</span><span class="token variable">)</span></span>. \<span class="token variable">$SCRIPT_PATH</span>/varexport CERT_DOMAIN="example.com"export LOCAL_SSL_CERT_FILE="\<span class="token variable">$ACME_SSL_CERT_DATA_PATH</span>/\<span class="token variable">$&#123;CERT_DOMAIN&#125;</span>_ecc/fullchain.cer"   # 默认签发ECC证书export SYNO_SCHEME="https"export SYNO_HOSTNAME="synology.example.com"export SYNO_PORT="443"export SYNO_Username="acme-user"export SYNO_Password="123456789ABCDEFG"export SYNO_Certificate=\<span class="token variable">$CERT_DOMAIN</span>  # 可选，描述证书的名称export SYNO_Create=1  # 如果证书不存在则创建function check_local_cert() &#123;    # 检查本地证书路径，如果不存在则提示需要执行证书签发    if [ ! -f "\<span class="token variable">$LOCAL_SSL_CERT_FILE</span>" ]; then        # 目录不存在，打印需要执行的命令        echo "Error: Cert file \<span class="token variable">$LOCAL_SSL_CERT_FILE</span> does not exist."        echo "Please execute the following command to issue the certificate:"        echo "./acme.sh --issue --dns dns_cf -d '\<span class="token variable">$CERT_DOMAIN</span>' -d '*.\<span class="token variable">$CERT_DOMAIN</span>'"        exit 1    else        echo "Cert file \<span class="token variable">$LOCAL_SSL_CERT_FILE</span> exists."    fi&#125;function deploy_ssl_cert_to_synology_DSM() &#123;    echo "Deploying SSL Cert: \<span class="token variable">$CERT_DOMAIN</span> to synology DSM."    deploy_status=\<span class="token variable"><span class="token variable">$(</span> <span class="token builtin class-name">cd</span> <span class="token punctuation">\</span>$ACME_HOME <span class="token operator">&amp;&amp;</span> acme.sh --deploy --home <span class="token punctuation">\</span>$ACME_HOME -d <span class="token string">"\<span class="token variable">$CERT_DOMAIN</span>"</span> --deploy-hook synology_dsm <span class="token variable">)</span></span>    if [ \<span class="token variable">$?</span> -eq 0 ]; then        echo "证书更新成功: \<span class="token variable">$deploy_status</span>"    else        echo "错误信息: \<span class="token variable">$deploy_status</span>"        exit 1    fi&#125;check_local_certdeploy_ssl_cert_to_synology_DSMEOF</span><span class="token function">chmod</span> +x ssl_cert_deploy_to_synologyDSM.sh<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>参数释义:</p><ul><li><p><code>CERT_DOMAIN</code>: 在 acme.sh 维护签发的证书名称，详见: <code>acme.sh --list</code> 结果中的”<strong>Main_Domain</strong>“；</p></li><li><p><code>SYNO_SCHEME</code>: 登陆群晖的 HTTP 协议，由于做了强制 HTTPS 所以此处使用 HTTPS 作为交互协议；</p></li><li><p><code>SYNO_HOSTNAME</code>: 登陆群晖的请求域名，由于前置了 Nginx，所以此处使用域名交互；</p></li><li><p><code>SYNO_PORT</code>: 登陆群晖的端口，由于登录协议采用了 HTTPS 并且在前置 Nginx 上监听的是 HTTPS 的默认端口，所以在脚本中填写 443，如果使用其他端口直接修改即可；</p></li><li><p><code>SYNO_Username</code>: 群晖中的管理员账户，即第一步创建的管理账户名称；</p></li><li><p><code>SYNO_Password</code>: 群晖中的管理员账户密码，即第一步创建的管理账户密码；</p></li><li><p><code>SYNO_Certificate</code>: 用于在群晖证书中显示的”<strong>描述</strong>“名称，这里采取与证书域名相同名称进行填充，<em>可选项</em>；</p><ul><li><img src="/814887c9/image-20240901011250757.png" class=""></li></ul></li><li><p><code>SYNO_Create</code>: 用于声明群晖证书中如果不存在证书是否自动创建，如果值为 1 则表示自动创建，默认不自动创建，<em>可选项</em>；</p></li></ul><blockquote><p>注: 脚本内容已对敏感参数进行脱敏，请根据实际情况进行修改。包括:</p><ul><li><code>CERT_DOMAIN</code></li><li><code>SYNO_HOSTNAME</code></li><li><code>SYNO_Username</code></li><li><code>SYNO_Password</code></li></ul></blockquote><h5 id="执行更新"><a href="#执行更新" class="headerlink" title="执行更新"></a>执行更新</h5><p>通过以下命令即可完成证书的<strong>首次部署</strong>或<strong>更新部署</strong>:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /usr/local/acme.sh/scripts<span class="token function">sh</span> ssl_cert_deploy_to_synologyDSM.sh<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>输出过程:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">15</span>:27:48 CST <span class="token number">2024</span><span class="token punctuation">]</span> Logging into synology.nestealin.com:443<span class="token punctuation">..</span>.<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">15</span>:27:50 CST <span class="token number">2024</span><span class="token punctuation">]</span> Getting certificates <span class="token keyword">in</span> Synology DSM<span class="token punctuation">..</span>.<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">15</span>:27:50 CST <span class="token number">2024</span><span class="token punctuation">]</span> Generating form POST request<span class="token punctuation">..</span>.<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">15</span>:27:50 CST <span class="token number">2024</span><span class="token punctuation">]</span> Upload certificate to the Synology DSM.<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">15</span>:27:50 CST <span class="token number">2024</span><span class="token punctuation">]</span> Restart HTTP services failed.<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">15</span>:27:51 CST <span class="token number">2024</span><span class="token punctuation">]</span> Success<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>出现以上输出则代表执行成功。</p><h5 id="结果验证"><a href="#结果验证" class="headerlink" title="结果验证"></a>结果验证</h5><p>登陆 DSM 确认证书已更新: <strong>登陆 DSM</strong> - <strong>控制面板</strong> - <strong>安全性</strong> - <strong>证书</strong></p><img src="/814887c9/image-20240901011459566.png" class=""><p>在 Synology Drive 查看执行状态</p><img src="/814887c9/image-20240901011515461.png" class=""><p>上传结果正常，表明证书更新正常。</p><h4 id="2FA-登陆-OTP-验证"><a href="#2FA-登陆-OTP-验证" class="headerlink" title="2FA 登陆 | OTP 验证"></a>2FA 登陆 | OTP 验证</h4><p>如果群晖的管理员开启了双重认证，则需要通过以下方式进行配置。</p><p>在”常规登录”的基础上，需要额外声明 <code>SYNO_DEVICE_ID</code> 和 <code>SYNO_OTP_CODE</code> 参数使用。</p><p>具体详见: <a href="https://github.com/acmesh-official/acme.sh/wiki/deployhooks#20-deploy-the-certificate-to-synology-dsm">deployhooks · acmesh-official/acme.sh Wiki · GitHub</a></p><blockquote><p>ref: <a href="https://申请限制-nas-guide/">Synology NAS Guide · acmesh-official/acme.sh Wiki · GitHub</a></p></blockquote><h3 id="3-定时自动更新-SSL-证书"><a href="#3-定时自动更新-SSL-证书" class="headerlink" title="3. 定时自动更新 SSL 证书"></a>3. 定时自动更新 SSL 证书</h3><p>由于”<a href="https://nestealin.com/814887c9/#toc-heading-7">最佳实践1. 使用 Cloudflare API Token 自动签发及更新 SSL 证书</a>“已经完成了 SSL 证书全流程的自动申请，这时候我们只需要利用 <code>--renew-all</code> 参数即可对所有已申请的证书统一执行续期，然后让定时任务(crontab)定期执行即可。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">cat</span> <span class="token operator">&lt;&lt;</span> <span class="token string">EOF<span class="token bash punctuation"> <span class="token operator">>></span> /var/spool/cron/<span class="token variable"><span class="token variable">`</span><span class="token function">whoami</span><span class="token variable">`</span></span></span># Ansible acme.sh Auto Renew Cert## Per 2 month0 1 1 */2 * /bin/bash /usr/local/acme.sh/acme.sh --renew-all --ecc > /dev/null 2>&amp;1EOF</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>执行说明:</p><ul><li><code>0 1 1 */2 *</code>: 表示每两个月的第一天凌晨 1 点整执行一次。</li><li>即该 cron 表达式实际上表示的是，每隔两个月，在每个月的 1 号凌晨 1 点执行任务。例如，如果从 1 月份开始执行，那么下一次执行将是 3 月份的 1 号凌晨 1 点，然后是 5 月份的 1 号，以此类推。</li></ul><blockquote><p><strong>注意</strong>:</p><ul><li><code>--renew-all</code> 命令用于统一续期证书，其执行范围仅限于 acme.sh 所在的本Certbot来确认。</li><li>默认情况下，**<code>renew</code> 命令仅更新 acme.sh 的本地证书存储位置** (如: <code>/usr/local/acme.sh/data/xxx_ecc</code>)，如果证书有在其他路径使用，如: 群晖 DSM 或 Nginx 等，<em>仍需要在每次证书自动更新后手动更新/部署</em>。</li></ul></blockquote><hr><h2 id="可能遇到的问题"><a href="#可能遇到的问题" class="headerlink" title="可能遇到的问题"></a>可能遇到的问题</h2><h4 id="too-many-certificates-already-issued"><a href="#too-many-certificates-already-issued" class="headerlink" title="too many certificates already issued"></a>too many certificates already issued</h4><p>如果你在使用acme.sh申请证书时遇到”too many certificates already issued”的错误，可能是因为你超过了这些速率限制</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">18</span>:16:14 CST <span class="token number">2024</span><span class="token punctuation">]</span> Using CA: https://acme-v02.api.letsencrypt.org/directory<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">18</span>:16:14 CST <span class="token number">2024</span><span class="token punctuation">]</span> Creating domain key<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">18</span>:16:14 CST <span class="token number">2024</span><span class="token punctuation">]</span> The domain key is here: /usr/local/acme.sh/nestealin.com_ecc/nestealin.com.key<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">18</span>:16:14 CST <span class="token number">2024</span><span class="token punctuation">]</span> Multi <span class="token assign-left variable">domain</span><span class="token operator">=</span><span class="token string">'DNS:nestealin.com,DNS:*.nestealin.com'</span><span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">18</span>:16:15 CST <span class="token number">2024</span><span class="token punctuation">]</span> Error creating new order. Le_OrderFinalize not found. <span class="token punctuation">&#123;</span>  <span class="token string">"type"</span><span class="token builtin class-name">:</span> <span class="token string">"urn:ietf:params:acme:error:rateLimited"</span>,  <span class="token string">"detail"</span><span class="token builtin class-name">:</span> <span class="token string">"Error creating new order :: too many certificates (5) already issued for this exact set of domains in the last 168 hours: *.nestealin.com,nestealin.com, retry after 2024-08-19T15:38:38Z: see https://letsencrypt.org/docs/duplicate-certificate-limit/"</span>,  <span class="token string">"status"</span><span class="token builtin class-name">:</span> <span class="token number">429</span><span class="token punctuation">&#125;</span><span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">18</span>:16:15 CST <span class="token number">2024</span><span class="token punctuation">]</span> Please <span class="token function">add</span> <span class="token string">'--debug'</span> or <span class="token string">'--log'</span> to see <span class="token function">more</span> information.<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> <span class="token number">18</span>:16:15 CST <span class="token number">2024</span><span class="token punctuation">]</span> See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="Cannot-find-DNS-API-hook-for-dns-cf"><a href="#Cannot-find-DNS-API-hook-for-dns-cf" class="headerlink" title="Cannot find DNS API hook for: dns_cf"></a>Cannot find DNS API hook for: dns_cf</h4><p><strong>问题描述</strong></p><p>在使用 DNS 期望自动添加解析并签发证书时，出现如下错误:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> Please <span class="token function">make</span> sure to prepend <span class="token string">'_acme-challenge.'</span> to your domain<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> so that the resulting subdomain is: _acme-challenge.nestealin.com<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> Cannot <span class="token function">find</span> DNS API hook for: dns_cf<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> You need to <span class="token function">add</span> the TXT record manually.<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> Add the following TXT record:<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> Domain: <span class="token string">'_acme-challenge.nestealin.com'</span><span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> TXT value: <span class="token string">'...-of7w'</span><span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> Please <span class="token function">make</span> sure to prepend <span class="token string">'_acme-challenge.'</span> to your domain<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> so that the resulting subdomain is: _acme-challenge.nestealin.com<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> Please <span class="token function">add</span> the TXT records to the domains, and re-run with --renew.<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> Please <span class="token function">add</span> <span class="token string">'--debug'</span> or <span class="token string">'--log'</span> to see <span class="token function">more</span> information.<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> <span class="token number">23</span>:04:08 CST <span class="token number">2024</span><span class="token punctuation">]</span> See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>意味着需要手动添加解析。</p><p><strong>原因</strong></p><ul><li>安装过程有所遗漏，没有使用 <code>--install-online</code> 参数安装依赖。</li></ul><p><strong>解决方式</strong></p><ul><li>重新安装 acme.sh，并在安装时指定 <code>--install-online</code> 参数。</li></ul><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">./acme.sh --install-online<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过本篇前两个自动化实践内容，我们实现了证书的自动申请与部署。这一改进不仅简化了证书管理流程，还通过设置定时任务，实现了单个域名证书签发、部署及更新的自动化闭环管理，从而大幅降低了用户的维护成本。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;前情提要:&lt;/p&gt;
&lt;p&gt;这会是一篇系列文章，本想先从 SSL 基本概念科普讲起，结果坑越挖越大。为了不鸽太久，就</summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="SSL" scheme="https://nestealin.com/tags/SSL/"/>
    
    <category term="Let&#39;s Encrypt" scheme="https://nestealin.com/tags/Let-s-Encrypt/"/>
    
    <category term="证书" scheme="https://nestealin.com/tags/%E8%AF%81%E4%B9%A6/"/>
    
    <category term="域名" scheme="https://nestealin.com/tags/%E5%9F%9F%E5%90%8D/"/>
    
    <category term="CA" scheme="https://nestealin.com/tags/CA/"/>
    
    <category term="群晖" scheme="https://nestealin.com/tags/%E7%BE%A4%E6%99%96/"/>
    
    <category term="Synology" scheme="https://nestealin.com/tags/Synology/"/>
    
    <category term="DSM" scheme="https://nestealin.com/tags/DSM/"/>
    
  </entry>
  
  <entry>
    <title>acme.sh快速入门申请SSL证书</title>
    <link href="https://nestealin.com/89bbe3ef/"/>
    <id>https://nestealin.com/89bbe3ef/</id>
    <published>2024-08-31T15:33:44.000Z</published>
    <updated>2026-03-20T12:06:00.342Z</updated>
    
    <content type="html"><![CDATA[<h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><blockquote><p>前情提要:</p><p>这会是一篇系列文章，本想先从 SSL 基本概念科普讲起，结果坑越挖越大。为了不鸽太久，就先把最近刚更完的证书相关操作先来逐步填坑，等后续再反补科普向内容（但愿）。</p><p>本系列内容大致分为四篇:</p><ul><li>SSL 相关基础知识-科普向 （有生之年）</li><li><a href="https://nestealin.com/89bbe3ef/">acme.sh 快速入门-主要功能及申请SSL证书实践</a> （<strong>本篇</strong>）</li><li><a href="https://nestealin.com/814887c9/">acme.sh 最佳实践-自动签发与自动部署群晖 DSM</a></li><li><a href="https://nestealin.com/450bd21e/">acme.sh 进阶版-多域名自动化管理</a></li><li>acme.sh 阶段性终结-批量部署</li></ul></blockquote><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>早年间，因 certbot-auto 是基于 Python 2 编写的，而 Python 2 即将寿终正寝，将 certbot-auto 迁移至 Python 3 需要大量工作且非常困难，因此<a href="https://community.letsencrypt.org/t/certbot-auto-no-longer-works-on-debian-based-systems/139702/7">团队决定放弃 certbot-auto 的维护</a>。所以笔者在后续改用了 Let’s Encrypt 上首推的 <a href="https://letsencrypt.org/zh-cn/docs/client-options/">ACME 客户端</a>（Certbot）来实现自助申请、更新 SSL 证书。</p><blockquote><p>ref: <a href="https://nestealin.com/63c77f1a/">利用certbot工具申请let’s encrypt证书</a>。</p></blockquote><p>但因为 <a href="https://github.com/certbot/certbot">Certbot</a> 本身强依赖 Python 3 运行环境，导致并不是所有客户端都能完美适用。而接着这次破站证书即将到期，重新看了一下目前的 ACME 客户端，从中找到了一款同样是针对 ACME 协议编写的工具 – acme.sh。</p><h3 id="acme-sh-是什么"><a href="#acme-sh-是什么" class="headerlink" title="acme.sh 是什么"></a>acme.sh 是什么</h3><p>acme.sh 是一个<strong>基于 Shell 脚本的开源工具</strong>，用于自动化管理和获取 SSL/TLS 证书。它提供了一种简单而灵活的方法来与 Let’s Encrypt 进行交互，并支持其他证书颁发机构（CA）。</p><h3 id="使用对比"><a href="#使用对比" class="headerlink" title="使用对比"></a>使用对比</h3><p>Certbot 和 acme.sh 都是用于自动化管理和获取 SSL/TLS 证书的工具，但它们在实现方式和功能上有一些区别。下面是它们之间的两个主要对比：</p><p><strong>实现语言和依赖关系:</strong></p><ul><li>Certbot 是使用 Python 编写的，因此在使用之前需要确保系统上已经安装了 Python 解释器和相关依赖库。这意味着您需要处理 Python 环境的配置和维护。</li><li>acme.sh 是一个基于 Shell 脚本的工具，它在各种 Linux 系统上运行，并且没有其他依赖关系。由于使用 Shell 脚本，它通常更加轻量级和易于安装和使用。</li></ul><p><strong>接口和功能：</strong></p><ul><li>Certbot 提供了一个命令行接口和一个简单的交互式界面，使得使用和管理证书变得更加方便。它有更多的配置选项和功能，例如支持多种 Web 服务器软件和自动配置文件更新。</li><li>acme.sh 同样提供了命令行接口，并且通过简单的命令和选项可以执行证书管理任务。虽然它的功能相对较少，但是它具有可扩展性和自定义性，通过插件机制可以添加更多功能，例如 DNS 验证插件。</li></ul><p>以下，将围绕 acme.sh 来做主要的功能介绍，让你对该工具有个初步认识。</p><hr><h2 id="快速入门"><a href="#快速入门" class="headerlink" title="快速入门"></a>快速入门</h2><h3 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h3><p>在开始之前需要升级系统的 CA 证书，以避免后续在申请 SSL 证书时遇到问题。</p><h4 id="CentOS"><a href="#CentOS" class="headerlink" title="CentOS"></a>CentOS</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yum <span class="token function">install</span> -y ca-certificates<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h4 id="Debian"><a href="#Debian" class="headerlink" title="Debian"></a>Debian</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">apt</span> update <span class="token punctuation">;</span> <span class="token function">apt</span> <span class="token function">install</span> -y ca-certificates<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="安装-acme-sh"><a href="#安装-acme-sh" class="headerlink" title="安装 acme.sh"></a>安装 acme.sh</h3><h4 id="快速安装"><a href="#快速安装" class="headerlink" title="快速安装"></a>快速安装</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">curl</span> https://get.acme.sh <span class="token operator">|</span> <span class="token function">sh</span> -s <span class="token assign-left variable">email</span><span class="token operator">=</span>nestealin@gmail.com<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>安装程序将执行以下 3 个操作：</p><ol><li>创建并复制 acme.sh 到你的主目录（<code>$HOME</code>）：<code>~/.acme.sh/</code>。所有的证书也将放置在这个文件夹中。</li><li>创建别名，例如：设置 <code>alias acme.sh=~/.acme.sh/acme.sh</code>。</li><li>创建每日定时任务来检查并更新证书（如果需要）。</li></ol><blockquote><p>注: acme.sh 工具的安装与执行操作均不需要 root 权限，允许在其他系统用户下直接安装与执行。</p></blockquote><h4 id="手动安装"><a href="#手动安装" class="headerlink" title="手动安装"></a>手动安装</h4><p>虽然普通用户和 root 用户都可以安装使用，但在本例中将以 root 用户进行安装。</p><p>使用如下命令自动安装:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">ACME_HOME</span><span class="token operator">=</span><span class="token string">"/usr/local/acme.sh"</span><span class="token function">mkdir</span> -p <span class="token variable">$ACME_HOME</span>/data<span class="token builtin class-name">cd</span> /usrCertbotithubusercontent.com/acmesh-official/acme.sh/master/acme.sh<span class="token function">chmod</span> +x acme.sh <span class="token operator">&amp;&amp;</span> ./acme.sh --install-online <span class="token punctuation">\</span>--home <span class="token variable">$ACME_HOME</span> <span class="token punctuation">\</span>--cert-home <span class="token variable">$ACME_HOME</span>/data <span class="token punctuation">\</span>--accountemail <span class="token string">"nestealin@gmail.com"</span> <span class="token punctuation">\</span>--nocron<span class="token function">ls</span> ./acme.sh <span class="token operator">&amp;&amp;</span> <span class="token function">rm</span> -f ./acme.sh <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">cd</span> <span class="token variable">$ACME_HOME</span> <span class="token operator">&amp;&amp;</span> <span class="token function">ls</span> -l<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>安装过程输出:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> 00:39:43 CST <span class="token number">2024</span><span class="token punctuation">]</span> It is recommended to <span class="token function">install</span> socat first.<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> 00:39:43 CST <span class="token number">2024</span><span class="token punctuation">]</span> We use socat <span class="token keyword">for</span> the standalone server, <span class="token function">which</span> is used <span class="token keyword">for</span> standalone mode.<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> 00:39:43 CST <span class="token number">2024</span><span class="token punctuation">]</span> If you don<span class="token string">'t want to use standalone mode, you may ignore this warning.[Sat Aug 17 00:39:43 CST 2024] Installing to /usr/local/acme.sh[Sat Aug 17 00:39:43 CST 2024] Installed to /usr/local/acme.sh/acme.sh[Sat Aug 17 00:39:43 CST 2024] Installing alias to '</span>/root/.bashrc<span class="token string">'[Sat Aug 17 00:39:43 CST 2024] Close and reopen your terminal to start using acme.sh[Sat Aug 17 00:39:43 CST 2024] Installing alias to '</span>/root/.cshrc<span class="token string">'[Sat Aug 17 00:39:43 CST 2024] Installing alias to '</span>/root/.tcshrc'<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> 00:39:43 CST <span class="token number">2024</span><span class="token punctuation">]</span> <span class="token function">bash</span> has been found. Changing the shebang to use <span class="token function">bash</span> as preferred.<span class="token punctuation">[</span>Sat Aug <span class="token number">17</span> 00:39:44 CST <span class="token number">2024</span><span class="token punctuation">]</span> OK<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>如果一切顺利出现上述输出，则表示安装完成。</p><p>根据上述输出，安装过程中会进行如下操作:</p><ul><li>创建并复制 <code>acme.sh</code> 到你显式指定的主目录（<code>--home</code>）: <code>/usr/local/acme.sh/</code> ，并且工具文件 <code>acme.sh</code> 也放于此，包括所有的证书也将放置在这个文件夹中（<code>--config-home</code>）: <code>/usr/local/acme.sh/data</code>。</li><li>创建别名，例如：在 <code>/root/.bashrc</code> 环境文件中设置 <code>. &quot;/usr/local/acme.sh/acme.sh.env&quot;</code> 环境声明。</li><li>创建每日定时任务来检查并更新证书（本次安装已显式忽略）。</li></ul><blockquote><p>acme.sh.env 文件内容参考:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">LE_WORKING_DIR</span><span class="token operator">=</span><span class="token string">"/usr/local/acme.sh"</span><span class="token builtin class-name">alias</span> acme.sh<span class="token operator">=</span><span class="token string">"/usr/local/acme.sh/acme.sh"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></blockquote><p>或参考官方默认安装 （方式二选一即可）</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">git</span> clone --depth <span class="token number">1</span> https://github.com/acmesh-official/acme.sh.git<span class="token builtin class-name">cd</span> acme.sh./acme.sh --install-online <span class="token punctuation">\</span>--home ~/myacme <span class="token punctuation">\</span>--config-home ~/myacme/data <span class="token punctuation">\</span>--cert-home  ~/mycerts <span class="token punctuation">\</span>--accountemail  <span class="token string">"my@example.com"</span> <span class="token punctuation">\</span>--accountkey  ~/myaccount.key <span class="token punctuation">\</span>--accountconf ~/myaccount.conf <span class="token punctuation">\</span>--useragent  <span class="token string">"this is my client."</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>参数释义:</p><ul><li><code>--home</code>: 表示安装主目录(默认含 <code>config-home</code>)，用于安装 <code>acme.sh</code>。默认情况下，它安装在 <code>~/.acme.sh</code>。</li><li><code>--config-home</code>: 证书配置文件目录，需要是一个当前用户<strong>可写的文件夹</strong>，<code>acme.sh</code> 会在这里写入所有文件（主要是证书/密钥的配置文件）。默认情况下，它位于 <code>--home</code>。</li><li><code>--cert-home</code>: 用于保存你签发的证书 ( 如: <code>/usr/local/acme.sh/data/</code> )。默认情况下，它保存在 <code>--config-home</code>。</li><li><code>--accountkey</code>: 是保存你账户私钥的文件。默认情况下，它保存在 <code>--config-home</code>。</li><li><code>--accountemail</code>: 用于在 Let’s Encrypt 注册账户的电子邮件地址，以便后续收到续期通知邮件。</li><li><code>--useragent</code>: 是 <code>acme.sh</code> 发送给 CA 时的 UA 值。</li><li><code>--nocron</code>: 安装 <code>acme.sh</code> 后不自动创建定时任务。</li></ul><blockquote><p>Crontab 示例:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token number">0</span> <span class="token number">0</span> * * * <span class="token string">"/home/user/.acme.sh"</span>/acme.sh --cron --home <span class="token string">"/home/user/.acme.sh"</span> <span class="token operator">></span> /dev/null<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></blockquote><blockquote><p>再次提醒:</p><ul><li>acme.sh 的安装不需要 root 权限，安装过程不会污染已有的系统任何功能和文件，所有的修改都被限制在  <code>~/.acme.sh/</code> 中</li><li>如果你想在安装的时候指定各种参数，也可以克隆 GitHub 仓库手动安装，更多详细参数可参考<a href="https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E">官方说明</a></li></ul></blockquote><h3 id="申请证书-手动签发"><a href="#申请证书-手动签发" class="headerlink" title="申请证书 | 手动签发"></a>申请证书 | 手动签发</h3><p>使用 Let’s Encrypt 作为签发 CA</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --set-default-ca --server letsencrypt<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>申请证书</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">./acme.sh --issue <span class="token punctuation">\</span>-d <span class="token string">"nestealin.com"</span> <span class="token punctuation">\</span>-d <span class="token string">"*.nestealin.com"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>参数释义:</p><ul><li>默认以<strong>第一个 <code>-d</code> 参数域名作为证书主域名</strong>，如有多个域名，则继续用 <code>-d</code> 以 SAN 域名进行追加即可，各 CA 证书支持域名的数量上限详见: <a href="https://nestealin.com/89bbe3ef/#toc-heading-30">申请限制</a>；</li><li>默认采用”<strong>DNS-01</strong>“方式验证；</li><li>默认采用”<strong>ec-256</strong>“ KeyLength 申请；如需特殊需求可用 <code>--keylength</code> 参数声明，如: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521 ；</li><li>如果需要使用网页验证，需要用 <code>-w /html/path</code> 方式声明；</li></ul><p><strong>提示: 后续步骤中的所有证书操作，均以”证书主域名”为准</strong>，如有 SAN 域名无需携带。</p><p>关于如何联动各 DNS API 实现<strong>自动签发</strong>，查看: <a href="https://nestealin.com/814887c9/#toc-heading-7">最佳实践</a></p><h3 id="查看维护中的证书"><a href="#查看维护中的证书" class="headerlink" title="查看维护中的证书"></a>查看维护中的证书</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --list<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="移除证书-删除证书"><a href="#移除证书-删除证书" class="headerlink" title="移除证书 | 删除证书"></a>移除证书 | 删除证书</h3><p>通过如下命令只会移除本地证书文件，不会注销证书</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --remove -d nestealin.com<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>移除后提示:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> 00:58:18 CST <span class="token number">2024</span><span class="token punctuation">]</span> The domain <span class="token string">'nestealin.com'</span> seems to already have an ECC cert, let's use it.<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> 00:58:18 CST <span class="token number">2024</span><span class="token punctuation">]</span> nestealin.com has been removed. The key and cert files are <span class="token keyword">in</span> /usr/local/acme.sh/data/nestealin.com_ecc<span class="token punctuation">[</span>Sun Aug <span class="token number">18</span> 00:58:18 CST <span class="token number">2024</span><span class="token punctuation">]</span> You can remove them by yourself.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>意味着管理脚本已经移除域名管控，但证书文件仍在本地保留，<strong>需要手动移除</strong>。</p><h3 id="证书续期"><a href="#证书续期" class="headerlink" title="证书续期"></a>证书续期</h3><p>默认情况下，acme.sh 会在安装后默认添加 crontab 定时任务，每 60 天执行一次自动续期。</p><p>当然也可以根据实际情况使用如下命令进行手动续期。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --renew -d nestealin.com --force<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>对于 ECC 证书:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --renew -d nestealin.com --force --ecc<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><blockquote><p>ref: <a href="https://blog.dnomd343.top/acme.sh-usage/#ECC%E8%AF%81%E4%B9%A6">acme.sh 使用说明 - ECC 证书</a></p></blockquote><h3 id="吊销证书"><a href="#吊销证书" class="headerlink" title="吊销证书"></a>吊销证书</h3><p>如果确认证书不需要了，可以通过如下命令先向 CA 注销，然后再删除本地证书文件。</p><p>首先通过下列命令吊销证书:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --revoke -d nestealin.com<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>出现<code>Revoke success</code>说明吊销成功</p><p>此时，只是 CA 注销成功，但证书文件还残留在服务器上，需要通过下列命令移除:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --remove -d nestealin.com<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>然后手动删除本地证书文件:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">rm</span> -rf /usr/local/acme.sh/data/nest申请限制期定时任务```bash/usr/local/acme.sh/acme.sh --cron --home /usr/local/acme.sh/<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><h3 id="升级-acme-sh-更新-acme-sh"><a href="#升级-acme-sh-更新-acme-sh" class="headerlink" title="升级 acme.sh | 更新 acme.sh"></a>升级 acme.sh | 更新 acme.sh</h3><p>目前由于 ACME 协议和各大 CA 都会频繁地更新, 因此 acme.sh 也要经常更新以保持同步。或在每次执行前手动更新一次。</p><h4 id="升至最新版"><a href="#升至最新版" class="headerlink" title="升至最新版"></a>升至最新版</h4><p>升级 acme.sh 到最新版:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --upgrade<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h4 id="开启自动升级"><a href="#开启自动升级" class="headerlink" title="开启自动升级"></a>开启自动升级</h4><p>如果你不想手动升级, 可以开启自动升级:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --upgrade --auto-upgrade<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>之后，acme.sh 就会自动保持更新了。</p><h4 id="还原环境"><a href="#还原环境" class="headerlink" title="还原环境"></a>还原环境</h4><p>同样地，如果遭遇环境破坏，还可以通过 <code>--force --upgrade</code> 的方式修复:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /usr/local/acme.sh./acme.sh --force --upgrade --nocron --home /usr/local/acme.sh<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><blockquote><p>ref: <a href="https://github.com/acmesh-official/acme.sh/wiki/Synology-NAS-Guide#deploy-with-existing-admin-user">Synology NAS Guide · acmesh-official/acme.sh Wiki · GitHub</a></p></blockquote><h4 id="关闭自动升级"><a href="#关闭自动升级" class="headerlink" title="关闭自动升级"></a>关闭自动升级</h4><p>你也可以随时关闭自动更新:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --upgrade --auto-upgrade <span class="token number">0</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="更换签发-CA"><a href="#更换签发-CA" class="headerlink" title="更换签发 CA"></a>更换签发 CA</h3><p>其实，acme.sh 脚本并不只是针对 Let’s Encrypt 单一 CA 进行证书申请，它还支持向其它 CA 申请，如: Buypass、ZeroSSL、SSL.com 和 Google Public CA，而 <strong>acme.sh 当前默认的 CA 是 ZeroSSL</strong>。</p><blockquote><p>ref: <a href="https://github.com/acmesh-official/acme.sh/wiki/Server">Server · acmesh-official/acme.sh Wiki · GitHub</a></p></blockquote><blockquote><p>注:</p><ul><li>本篇文章使用 Let’s Encrypt 来做讲解；</li><li>如果 CA 不变，则命令只需要执行一次，可以不必每次执行 acme.sh 前都进行 <code>--set-default-ca --server xxx</code>；</li><li>Google Public CA 需要按照官方博客申请内测，然后获取 Key；</li></ul></blockquote><h4 id="切换-Let’s-Encrypt"><a href="#切换-Let’s-Encrypt" class="headerlink" title="切换 Let’s Encrypt"></a>切换 Let’s Encrypt</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --set-default-ca --server letsencrypt<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>只需执行一次，切换后在下次执行 <code>acme.sh --issue ...</code> 时默认就会向 Let’s Encrypt 进行申请。</p><h4 id="切换-Buypass"><a href="#切换-Buypass" class="headerlink" title="切换 Buypass"></a>切换 Buypass</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --set-default-ca --server buypass<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h4 id="切换-ZeroSSL"><a href="#切换-ZeroSSL" class="headerlink" title="切换 ZeroSSL"></a>切换 ZeroSSL</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --set-default-ca --server zerossl<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>如果已有 ZeroSSL 帐号，可以在后台控制面板拿到 API Key，然后执行如下命令：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">apt</span> update<span class="token function">apt</span> <span class="token function">install</span> -y jq<span class="token function">curl</span> -s -X POST <span class="token string">"https://api.zerossl.com/acme/eab-credentials?access_key=你的API_Key"</span> <span class="token operator">|</span> jq<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>输出内容如下：</p><pre class="line-numbers language-json" data-language="json"><code class="language-json"><span class="token punctuation">&#123;</span>  <span class="token property">"success"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>  <span class="token property">"eab_kid"</span><span class="token operator">:</span> <span class="token string">"kid字符串"</span><span class="token punctuation">,</span>  <span class="token property">"eab_hmac_key"</span><span class="token operator">:</span> <span class="token string">"hmac_key字符串"</span><span class="token punctuation">,</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>然后手动添加帐号：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --register-account --server zerossl <span class="token punctuation">\</span>        --eab-kid kid字符串  <span class="token punctuation">\</span>        --eab-hmac-key hmac_key字符串<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h4 id="切换-SSL-com"><a href="#切换-SSL-com" class="headerlink" title="切换 SSL.com"></a>切换 SSL.com</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --set-default-ca --server ssl.com<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h4 id="切换-Google-Public-CA"><a href="#切换-Google-Public-CA" class="headerlink" title="切换 Google Public CA"></a>切换 Google Public CA</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --set-default-ca --server google<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="更换证书链"><a href="#更换证书链" class="headerlink" title="更换证书链"></a>更换证书链</h3><p>如果 ACME CA 提供多个证书链，可以使用 <code>--preferred-chain</code> 选择其中一个。 否则，它将获取默认链。</p><p>例如 Let’s Encrypt 在<a href="https://letsencrypt.org/docs/staging-environment/">测试环境</a>提供了两种证书链:</p><table><thead><tr><th>Name</th><th>Default</th></tr></thead><tbody><tr><td>(STAGING) Pretend Pear X1</td><td>No</td></tr><tr><td>(STAGING) Bogus Broccoli X2</td><td>Yes</td></tr></tbody></table><p>可以根据关键名称（Name）<strong>任选一种</strong>关键字输入:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">acme.sh --issue -d example.com <span class="token punctuation">..</span><span class="token punctuation">..</span>.  --test --preferred-chain  <span class="token string">"(STAGING) Pretend Pear X1"</span>acme.sh --issue -d example.com <span class="token punctuation">..</span><span class="token punctuation">..</span>.  --test --preferred-chain  <span class="token string">"X1"</span>acme.sh --issue -d example.com <span class="token punctuation">..</span><span class="token punctuation">..</span>.  --test --preferred-chain  <span class="token string">"x1"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><blockquote><p>ref: <a href="https://github.com/acmesh-official/acme.sh/wiki/Preferred-Chain">Preferred Chain · acmesh-official/acme.sh Wiki · GitHub</a></p></blockquote><hr><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><h3 id="申请限制"><a href="#申请限制" class="headerlink" title="申请限制"></a>申请限制</h3><p>使用 acme.sh 申请证书时，证书的数量受到 Let’s Encrypt 的速率限制的影响。以下是主要的限制信息：</p><ol><li><strong>每个注册域名的证书数量</strong>：每周最多可以为每个注册域名申请 50 份证书。例如，如果你的域名是<code>example.com</code>，那么在一周内，你最多可以申请 50 个不同的证书。</li><li><strong>每个账户的订单限制</strong>：每个账户每三小时最多可以创建 300 份新订单。每次申请证书时，都会生成一个新订单。</li><li><strong>每份证书的域名数量</strong>：每份证书最多可以包含 100 个域名。这意味着你可以在一张证书中为多个域名申请 SSL/TLS 证书。</li><li><strong>续期证书的特殊规则</strong>：续期证书不计入每个注册域名的证书数量限制，但每周最多只能续期 5 张重复证书。如果你尝试续期的证书与已有证书的域名列表完全相同，就会触发限制。</li></ol><p>目前支持的 CA 厂商特性如下：</p><table><thead><tr><th align="center">CA 厂商</th><th align="center">证书有效期</th><th align="center">ECC 证书</th><th align="center">域名数量</th><th align="center">支持通配符</th><th align="center">NotAfter</th><th align="center">国际化域名</th></tr></thead><tbody><tr><td align="center">Let’s Encrypt</td><td align="center">90</td><td align="center">是</td><td align="center">100</td><td align="center">是</td><td align="center">否</td><td align="center">是</td></tr><tr><td align="center">ZeroSSL</td><td align="center">90</td><td align="center">是</td><td align="center">100</td><td align="center">是</td><td align="center">是</td><td align="center">是</td></tr><tr><td align="center">Google</td><td align="center">90</td><td align="center">是</td><td align="center">100</td><td align="center">是</td><td align="center">是</td><td align="center">否</td></tr><tr><td align="center">Buypass</td><td align="center">180</td><td align="center">是</td><td align="center">5</td><td align="center">付费</td><td align="center">否</td><td align="center">是</td></tr><tr><td align="center">SSL.com</td><td align="center">90</td><td align="center">是</td><td align="center">2</td><td align="center">付费</td><td align="center">否</td><td align="center">是</td></tr></tbody></table><blockquote><p>ref: <a href="https://github.com/acmesh-official/acme.sh/wiki/CA">CA · acmesh-official/acme.sh Wiki · GitHub</a></p></blockquote><p>小提示: 如果证书域名触发了申请上限，可以尝试增删或更改证书 SAN 域名进行规避。</p><blockquote><p>注: 因为 SSL 证书签发限制只以域名组合（主域名 + SAN 域名）作为唯一判断，例如 SAN 域名的增删都会被认为是一个新的域名组合。</p></blockquote><h3 id="环境变量"><a href="#环境变量" class="headerlink" title="环境变量"></a>环境变量</h3><ul><li>如果准备使用脚本二次封装执行，请勿使用 <code>CERT_PATH</code> 和 <code>SSL_CERT_FILE</code> 否则可能引起各种问题；</li></ul><hr><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><h4 id="1-关于域名验证方式"><a href="#1-关于域名验证方式" class="headerlink" title="1. 关于域名验证方式"></a>1. 关于域名验证方式</h4><p>通常情况下，可以支持两种域名验证方式:</p><ul><li>端口验证，有且只能使用 80、443 端口访问测试；</li><li>TXT 记录验证，通过添加指定域名的 TXT 记录验证归属；</li></ul><blockquote><p>此外，还支持一种隐式验证，即 DNS 别名模式，详情查看: <a href="https://github.com/acmesh-official/acme.sh/wiki/DNS-alias-mode">DNS alias mode · acmesh-official/acme.sh Wiki · GitHub</a></p></blockquote><h4 id="2-修改-acme-sh-安装目录-config-home-路径修改"><a href="#2-修改-acme-sh-安装目录-config-home-路径修改" class="headerlink" title="2. 修改 acme.sh 安装目录 | config-home 路径修改"></a>2. 修改 acme.sh 安装目录 | config-home 路径修改</h4><p>假设初始安装 acme.sh 的 config-home 目录位于 <code>/opt/acme</code> 目录，即执行 acme.sh 的执行脚本位于 <code>/opt/acme/acme.sh</code> 现在想将 config-home 路径修改至 <code>/usr/local/acme.sh</code> 可以通过如下方式修改。</p><p><strong>修改流程</strong></p><p>迁移目录:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">mv</span> /opt/acme /usr/local/acme.sh<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>修改环境变量:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">vim</span> ~/.bashrc<span class="token function">vim</span> ~/.cshrc<span class="token function">vim</span> ~/.tcshrc<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>一共需要修改上述三个环境变量文件</p><p>修改内容前后对照:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># ~/.bashrc</span>- <span class="token builtin class-name">.</span> <span class="token string">"/opt/acme/acme.sh.env"</span>+ <span class="token builtin class-name">.</span> <span class="token string">"/usr/local/acme.sh/acme.sh.env"</span><span class="token comment"># ~/.cshrc</span>- <span class="token builtin class-name">source</span> <span class="token string">"/opt/acme/acme.sh.csh"</span>+ <span class="token builtin class-name">source</span> <span class="token string">"/usr/local/acme.sh/acme.sh.csh"</span><span class="token comment"># ~/.tcshrc</span>- <span class="token builtin class-name">source</span> <span class="token string">"/opt/acme/acme.sh.csh"</span>+ <span class="token builtin class-name">source</span> <span class="token string">"/usr/local/acme.sh/acme.sh.csh"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong>原理说明</strong></p><ol><li>例如在 bash shell 下时，登陆时默认加载 <code>~/.bashrc</code> 文件</li><li>在 <code>~/.bashrc</code> 文件内默认加载 <code>/usr/local/acme.sh/acme.sh.env</code> 环境变量</li><li><code>/usr/local/acme.sh/acme.sh.env</code> 环境变量默认声明 <code>export LE_WORKING_DIR=&quot;/usr/local/acme.sh&quot;</code></li></ol><blockquote><p>注:</p><ul><li>如果 config-home 与 home 有单独拆分路径，可能还会有 <code>export LE_CONFIG_HOME=&quot;/usr/local/acme.sh/data&quot;</code> 单独的环境变量。</li><li>ref: <a href="https://github.com/arabezar/acme.sh/wiki#4-updating-cert">GitHub - acme.sh | 4-updating-cert</a></li></ul></blockquote><h4 id="3-自动-DNS-API-简称及变量速查"><a href="#3-自动-DNS-API-简称及变量速查" class="headerlink" title="3. 自动 DNS API 简称及变量速查"></a>3. 自动 DNS API 简称及变量速查</h4><table><thead><tr><th>服务商名称</th><th>服务商简称</th><th>所需 API 参数</th><th>获取 API 参数地址</th></tr></thead><tbody><tr><td>cloudxns</td><td>cx</td><td><code>export CX_Key=&quot;123456&quot;</code>  <code>export CX_Secret=&quot;abcdef&quot;</code></td><td><a href="https://www.cloudxns.net/AccountManage/apimanage.html">点击访问</a></td></tr><tr><td>dnspod.cn</td><td>dp</td><td><code>export DP_Id=&quot;123456&quot;</code>  <code>export DP_Key=&quot;abcdef&quot;</code></td><td><a href="https://www.dnspod.cn/console/user/security">点击访问</a></td></tr><tr><td>aliyun</td><td>ali</td><td><code>export Ali_Key=&quot;123456&quot;</code>  <code>export Ali_Secret=&quot;abcdef&quot;</code></td><td><a href="https://ram.console.aliyun.com/manage/ak">点击访问</a></td></tr><tr><td>cloudflare</td><td>cf</td><td><code>export CF_Key=&quot;123456&quot;</code>  <code>export CF_Email=&quot;abc@example.com&quot;</code></td><td><a href="https://dash.cloudflare.com/profile/api-tokens">点击访问</a></td></tr><tr><td>linode</td><td>linode</td><td><code>export LINODE_API_KEY=&quot;123456&quot;</code></td><td><a href="https://manager.linode.com/profile/api">点击访问</a></td></tr><tr><td>he</td><td>he</td><td><code>export HE_Username=&quot;username&quot;</code>  <code>export HE_Password=&quot;password&quot;</code></td><td><a href="https://dns.he.net/">he</a>的用户名密码</td></tr><tr><td>digitalocean</td><td>dgon</td><td><code>export DO_API_KEY=&quot;123456&quot;</code></td><td><a href="https://cloud.digitalocean.com/settings/applications">点击访问</a></td></tr><tr><td>namesilo</td><td>namesilo</td><td><code>export Namesilo_Key=&quot;123456&quot;</code></td><td><a href="https://www.namesilo.com/account/api-manager">点击访问</a></td></tr><tr><td>aws</td><td>aws</td><td><code>export AWS_ACCESS_KEY_ID=123456</code>  <code>export AWS_SECRET_ACCESS_KEY=abcdef</code></td><td><a href="http://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html">点击访问</a></td></tr><tr><td>namecom</td><td>namecom</td><td><code>export Namecom_Username=&quot;username&quot;</code>  <code>export Namecom_Token=&quot;123456&quot;</code></td><td><a href="https://www.name.com/reseller/apply">点击访问</a></td></tr><tr><td>freedns</td><td>freedns</td><td><code>export FREEDNS_User=&quot;username&quot;</code>  <code>export FREEDNS_Password=&quot;password&quot;</code></td><td><a href="https://freedns.afraid.org/">freedns</a>的用户名密码</td></tr><tr><td>godaddy</td><td>gd</td><td><code>export GD_Key=&quot;123456&quot;</code>  <code>export GD_Secret=&quot;abcdef&quot;</code></td><td><a href="https://developer.godaddy.com/keys/">点击访问</a></td></tr><tr><td>yandex</td><td>yandex</td><td><code>export PDD_Token=&quot;abcdef&quot;</code></td><td><a href="https://tech.yandex.com/domain/doc/concepts/access-docpage/">点击访问</a></td></tr></tbody></table><p>更多 dnsapi 的使用，可以查看<a href="https://github.com/acmesh-official/acme.sh/wiki/dnsapi">文档</a>。</p><h4 id="4-转换为p12证书"><a href="#4-转换为p12证书" class="headerlink" title="4. 转换为p12证书"></a>4. 转换为<code>p12</code>证书</h4><p>虽然<code>acme.sh</code>生成的证书可以直接配置到 Nginx、Apache 等等 Web 服务器使用，不过有少数时候如果说想直接配置证书到 Tomcat 中（Spring Boot）那就需要将证书转换成<code>p12</code>格式了！</p><p>生成证书后，将<strong>证书文件</strong>和<strong>证书密钥文件</strong>复制出来，通过<code>openssl</code>命令转换：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">openssl pkcs12 -export -in <span class="token string">"证书文件路径"</span> -inkey <span class="token string">"证书密钥文件路径"</span> -out <span class="token string">"指定生成的p12证书文件路径"</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>执行命令会让你设定<code>p12</code>证书的密码，自行设定即可。</p><p>然后在 Spring Boot 配置文件配置如下：</p><pre class="line-numbers language-properties" data-language="properties"><code class="language-properties"><span class="token comment"># SSL证书设置</span><span class="token attr-name">server.ssl.key-store</span><span class="token punctuation">=</span><span class="token attr-value">证书p12文件所在位置</span><span class="token attr-name">server.ssl.key-store-password</span><span class="token punctuation">=</span><span class="token attr-value">证书密码</span><span class="token attr-name">server.ssl.keyStoreType</span><span class="token punctuation">=</span><span class="token attr-value">PKCS12</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p><code>server.ssl.key-store</code>配置项需要以<code>classpath:</code>或者<code>file:</code>开头，一般<code>classpath:</code>开头的表示<code>jar</code>包内路径，Maven 项目中<code>src\main\resources</code>文件夹即可对应为<code>classpath</code>的根目录，而<code>file:</code>对应的是<code>jar</code>包外相对路径或者绝对路径。</p><pre class="line-numbers language-properties" data-language="properties"><code class="language-properties"><span class="token comment"># classpath路径</span><span class="token attr-name">server.ssl.key-store</span><span class="token punctuation">=</span><span class="token attr-value">classpath:ssl.p12</span><span class="token comment"># jar包外路径</span><span class="token attr-name">server.ssl.key-store</span><span class="token punctuation">=</span><span class="token attr-value">file:ssl/ssl.p12</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="5-创建腾讯云-DNSPod-Token"><a href="#5-创建腾讯云-DNSPod-Token" class="headerlink" title="5. 创建腾讯云 DNSPod Token"></a>5. 创建腾讯云 DNSPod Token</h4><p><a href="https://console.dnspod.cn/account/token/token">DNSPod - 账号中心 | API 密钥</a> ，在<code>API秘钥 -&gt; DNSPod Token</code> 下创建一个秘钥</p><img src="/89bbe3ef/432971eb5eae0c2fa80c311d213d2dd4.png" class=""><p>接着复制 ID 和 Token，执行如下命令将其配置到环境变量中：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">DP_Id</span><span class="token operator">=</span><span class="token string">"&lt;DNSPod_Token_ID>"</span><span class="token builtin class-name">export</span> <span class="token assign-left variable">DP_Key</span><span class="token operator">=</span><span class="token string">"&lt;DNSPod_Token>"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h4 id="6-创建阿里云-Key-和-Secret"><a href="#6-创建阿里云-Key-和-Secret" class="headerlink" title="6. 创建阿里云 Key 和 Secret"></a>6. 创建阿里云 Key 和 Secret</h4><p><a href="https://ram.console.aliyun.com/manage/ak">阿里云 - RAM 访问控制 | AccessKey</a>，点击”<strong>创建 AccessKey</strong>“</p><img src="/89bbe3ef/01bd4c9fabbb0a662ffb90900acd3b16.png" class=""><p>接着复制 AccessKey ID 和 Secret，执行如下命令将其配置到环境变量中：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">Ali_Key</span><span class="token operator">=</span><span class="token string">"&lt;AccessKey_ID>"</span><span class="token builtin class-name">export</span> <span class="token assign-left variable">Ali_Secret</span><span class="token operator">=</span><span class="token string">"&lt;AccessKey_Secret>"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><hr><h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><ul><li><a href="https://letsencrypt.org/zh-cn/docs/challenge-types/">验证方式 - Let’s Encrypt - 免费的 SSL/TLS 证书</a></li><li><a href="https://letsencrypt.org/zh-cn/docs/client-options/">ACME 客户端 - Let’s Encrypt</a></li><li><a href="https://developer.aliyun.com/article/692073">acme.sh 使用教程-阿里云开发者社区</a></li><li><a href="https://blog.csdn.net/weixin_57025326/article/details/136286399">自动化部署证书 acme.sh 使用教程_acme.sh 部署命令-CSDN 博客</a></li><li><a href="https://tech.mornlong.com/post/97.html">通过 ACME 让群晖（Synology）自动申请部署 Let’s Encrypt 的 SSL 证书 - M 学院</a></li><li><a href="https://juejin.cn/post/7341314453575516175">快速且自动化的证书申请-acme.sh 申请和管理证书如果是个人部署网站，那么现在有许多免费的证书供我们选择，例如 Let’ - 掘金</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;概述&quot;&gt;&lt;a href=&quot;#概述&quot; class=&quot;headerlink&quot; title=&quot;概述&quot;&gt;&lt;/a&gt;概述&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;前情提要:&lt;/p&gt;
&lt;p&gt;这会是一篇系列文章，本想先从 SSL 基本概念科普讲起，结果坑越挖越大。为了不鸽太久，就</summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="SSL" scheme="https://nestealin.com/tags/SSL/"/>
    
    <category term="Let&#39;s Encrypt" scheme="https://nestealin.com/tags/Let-s-Encrypt/"/>
    
    <category term="证书" scheme="https://nestealin.com/tags/%E8%AF%81%E4%B9%A6/"/>
    
    <category term="域名" scheme="https://nestealin.com/tags/%E5%9F%9F%E5%90%8D/"/>
    
    <category term="CA" scheme="https://nestealin.com/tags/CA/"/>
    
  </entry>
  
  <entry>
    <title>Nginx中server_name的一些无用冷知识</title>
    <link href="https://nestealin.com/49c24897/"/>
    <id>https://nestealin.com/49c24897/</id>
    <published>2024-04-05T18:00:11.000Z</published>
    <updated>2024-08-04T06:56:53.350Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>在早前 <a href="https://nestealin.com/d21bac89/">初识Nginx中server和location的匹配顺序</a> 中有简单提到 <code>server_name</code> 的匹配顺序。然而，在日常的使用过程中不免会遇到一些”坑”，在不断踩坑的过程中加深了对现有知识的理解，并借此机会进行了补充。</p><hr><h2 id="关于-server-name-的匹配顺序"><a href="#关于-server-name-的匹配顺序" class="headerlink" title="关于 server_name 的匹配顺序"></a>关于 server_name 的匹配顺序</h2><blockquote><p>以下内容其实在 <a href="https://nginx.org/en/docs/http/request_processing.html">How nginx processes a request</a> 也有说明，下文主要是基于日常配置过程中加以补充。</p></blockquote><ol><li>listen 匹配（作为大前提，如果访问端口都不对，就不会进行后续的域名匹配）</li><li>精确域名匹配</li><li>以 <code>*</code> 开头，最长匹配的泛域名匹配，如: <code>*.test.com</code></li><li>以 <code>*</code> 结尾，最长匹配的泛域名匹配，如: <code>www.test.*</code></li><li>正则域名匹配，如: <code>~^\.www\.test\.com$</code></li><li>如果都不匹配<ol><li>优先选择 listen 配置项后有 default 或 default_server 的 server 块匹配</li><li>根据 <code>server_name localhost</code> 匹配 （当且仅当请求 Host 为 localhost 且 <code>server_name</code> 也为 localhost 时才生效）</li><li>根据 Nginx 配置文件/目录中， <code>ls -l</code> 结果从上至下（按 0-9 -&gt; a-z）顺序匹配，匹配到的第一个符合条件的即止<ul><li>例如: 有 80 监听的第一个 server 块，忽略 <code>server_name</code>，直接匹配对应 location</li></ul></li></ol></li></ol><p><strong>注意事项</strong></p><ul><li>在条件允许的情况下，<strong>请尽量使用精确域名</strong>；</li><li>当出现多个相同的 <code>server_name</code> 时，会根据站点配置文件排序优先匹配；</li><li>在普通 <code>server_name</code> 配置下，<code>*</code> 符号可以代表多字符匹配，但<strong>只能用在 <code>server_name</code> 的开头或末尾</strong>；<ul><li>例如:  <code>www.*.example.org</code> 和 <code>w*.example.org</code> 是无效的</li></ul></li><li>Nginx 的正则表达式与 Perl 语言（PCRE）使用的正则表达式兼容；</li><li>正则匹配<strong>必须以 <code>~</code> 开头</strong>（否则将会认为是精确字符匹配），并建议使用 <code>^</code> 和 <code>$</code> 符号分别作为”开头”和”结束”的锚点；<ul><li>例如: <code>server_name  ~^www\d+\.example\.net$;</code></li></ul></li><li>正则域名下允许在 <code>server_name</code> 中使用 <code>*</code> 符号匹配多字符；<ul><li>例如: <code>~^w.*\.example\.org$</code> 不仅匹配 <code>www.example.org</code>，还匹配 <code>www.sub.example.org</code></li></ul></li></ul><hr><h2 id="关于泛域名匹配"><a href="#关于泛域名匹配" class="headerlink" title="关于泛域名匹配"></a>关于泛域名匹配</h2><h3 id="泛域名配置"><a href="#泛域名配置" class="headerlink" title="泛域名配置"></a>泛域名配置</h3><p>根据 <a href="https://nginx.org/en/docs/http/server_names.html#wildcard_names">Server names#wildcard_names</a> 中说明，在普通泛域名配置中，<code>*</code> 符号只能对域名”前缀”或”后缀”进行配置，其他位置则不生效。</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span>       <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span>  *.example.org</span><span class="token punctuation">;</span>    ...<span class="token punctuation">&#125;</span><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span>       <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span>  mail.*</span><span class="token punctuation">;</span>    ...<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="正则泛域名配置"><a href="#正则泛域名配置" class="headerlink" title="正则泛域名配置"></a>正则泛域名配置</h3><p>如果想对固定域名的部分字符进行泛域名匹配时（例如匹配: <code>api.dev.nestealin.com</code>、<code>api.pre.nestealin.com</code>、<code>api.prod.nestealin.com</code> 等 <code>api.*.nestealin.com</code> 格式的域名），则可以使用正则表达式的方式进行。</p><blockquote><p>参考: <a href="https://nginx.org/en/docs/http/server_names.html#regex_names">Server names#regex_names</a></p></blockquote><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span>       <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span>  ~^api\.*\.nestealin\.com$</span><span class="token punctuation">;</span>    ...<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="泛域名误区-“无意义域名”"><a href="#泛域名误区-“无意义域名”" class="headerlink" title="泛域名误区 - “无意义域名”"></a>泛域名误区 - “无意义域名”</h3><p>在一些教程网站中，也有一些配置会用 <code>server_name  &quot;&quot;</code> 或 <code>server_name  _</code> 来表示”泛域名”匹配，但这其实并不完全符合匹配原则，只是”恰好”在规则条件上得以命中，看似解决了这方面问题罢了。下面将针对最常见的几个”泛域名” <code>server_name</code> 配置进行主要说明。</p><h4 id="server-name-“”"><a href="#server-name-“”" class="headerlink" title="server_name  “”"></a>server_name  “”</h4><p>Nginx 的官方文档是这么描述 <code>server_name &quot;&quot;</code> 的：</p><blockquote><p>If it is required to process requests without the “Host” header field in a server block which is not the default, an empty name should be specified.</p></blockquote><p>也就是说，如果想让一个没有被标注为 <code>default_server</code> 的 server 块来处理一个没有带有 Host header 的请求的话，就需要使用 <code>server_name &quot;&quot;</code> 指令。但问题是，在 RFC 7230, Section 5.4 中 HTTP/1.1 （也就是当前主流的 HTTP version）对 Host 的规定[^3]，如果一个请求没有带有 Host header 的话，服务器必须得返回 400（Bad Request）：</p><img src="/49c24897/bb05733f1c071c1c3f3da5e383f3adcb.png" class=""><p>所以，使用了 <code>server_name &quot;&quot;</code> 的<strong>非 default server 块</strong>压根就没有机会去处理一个没有带有 Host header 的请求，因为在把这个请求交给 server 块之前就已经先被 Nginx 处理然后响应 400 状态码了。（即便客户端为 HTTP/1.0 结果也是同样）</p><p>因此，当 <code>server_name &quot;&quot;</code> 单独使用时，该 server 块是处理不了任何请求的（按正常匹配顺序来说），它通常要跟 listen 中的 <code>default</code> 或 <code>default_server</code> 配合使用，表示这个 server 块可以集中处理那些无法被其他 server 块处理的请求。</p><h4 id="server-name-server-name-server-name"><a href="#server-name-server-name-server-name" class="headerlink" title="server_name _  | server_name $ | server_name @"></a>server_name _  | server_name $ | server_name @</h4><p><code>server_name _</code> 是可以匹配到 Host header 的值的，因为它可以匹配到 Host header 值为 “<code>_</code>“ 的请求。但是这种匹配其实也是没有意义的，因为对于浏览器而言，请求中的 Host header 的值就是你所输入的网站地址（可以是 IP 地址也可以是域名），但是 “<code>_</code>“ 根本就不是一个域名，它根本就无法被解析成 ip 地址，无法被解析成 ip 地址就意味着这个请求根本就没办法发送到对应的服务器上，所以 <code>server_name _</code> 跟 <code>server_name &quot;&quot;</code> 一样根本就没有用武之地。</p><p>同样地，我们可以认为 <code>server_name _</code> 跟 <code>server_name &quot;&quot;</code> 一样本身是没有任何意义；其实除了 <code>server_name _</code> 之外，像 <code>server_name !</code>、 <code>server_name $</code> 、 <code>server_name @</code>、<code>server_name --</code> 等这类都是属于”无意义域名”。</p><p>因此，<code>server_name _</code> 其实跟 <code>server_name &quot;&quot;</code> 一样，在 <code>server_name _</code> 单独使用的 server 块中是处理不了任何请求的，一般也是要跟 listen 中的 <code>default</code> 或 <code>default_server</code> 一起配合使用才有最佳效果，也是表示这个 server 块可以集中处理那些无法被其他 server 块处理的请求。</p><hr><h2 id="关于国际化域名"><a href="#关于国际化域名" class="headerlink" title="关于国际化域名"></a>关于国际化域名</h2><h3 id="什么是国际化域名"><a href="#什么是国际化域名" class="headerlink" title="什么是国际化域名"></a>什么是国际化域名</h3><p>在全球域名规范中，除了英文点分域名格式以外，还可能存在中文、俄文等国家文字作为域名，统称为国际化域名( Internationalized Domain Names (IDNs) )[^1][^2]。</p><h3 id="如何配置国际化域名"><a href="#如何配置国际化域名" class="headerlink" title="如何配置国际化域名"></a>如何配置国际化域名</h3><p>假设现在要为一个俄文域名（<code>пример.испытание</code>）进行配置，此时就需要将域名转为 ASCII (Punycode) 格式。</p><p>例如:</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span>       <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span>  xn--e1afmkfd.xn--80akhbyknj4f</span><span class="token punctuation">;</span>  <span class="token comment"># 实际域名: пример.испытание</span>    ...<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="Punycode-转换"><a href="#Punycode-转换" class="headerlink" title="Punycode 转换"></a>Punycode 转换</h3><p>在线转换工具: <a href="https://myssl.com/punycode.html">Punycode编码转换</a></p><img src="/49c24897/c207c17d2b41b8f0e98289f345c6da5f.png" class=""><hr><h2 id="关于匹配规则的实验"><a href="#关于匹配规则的实验" class="headerlink" title="关于匹配规则的实验"></a>关于匹配规则的实验</h2><h3 id="环境说明"><a href="#环境说明" class="headerlink" title="环境说明"></a>环境说明</h3><p><strong>服务端(Nginx)</strong></p><p>Nginx IP: 192.168.7.27</p><p>在 Nginx 配置目录（<code>/usr/local/nginx/conf/sites</code>）下创建两个配置文件:</p><blockquote><p>注: 为了避免”兜底配置”在站点文件的首位，因此，在本次实验中会将”兜底配置”文件根据匹配规则放到目录”末尾”。</p></blockquote><p>正常域名配置: （a-test.conf）</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span> <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span> abc.nestealin.com</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">add_header</span> content-type application/json</span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">return</span> <span class="token number">200</span> <span class="token string">'&#123;"status": "This is the a-test.conf"&#125;'</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>兜底域名配置: （z-default_test.conf）</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token comment">#listen 80 default_server ;</span>    <span class="token directive"><span class="token keyword">listen</span> <span class="token number">80</span></span> <span class="token punctuation">;</span>    <span class="token comment">#server_name "";</span>    <span class="token directive"><span class="token keyword">server_name</span> _</span><span class="token punctuation">;</span>    <span class="token comment">#server_name $;</span>    <span class="token comment">#server_name localhost;</span>    <span class="token comment">#server_name ~^(.+)$;</span>    <span class="token comment">#server_name ~^.*$;</span>    <span class="token comment">#server_name ~. "";</span>    <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">add_header</span> content-type application/json</span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">return</span> <span class="token number">200</span> <span class="token string">'&#123;"status": "This is the z-default_test.conf"&#125;'</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong>客户端</strong></p><p>使用 curl 命令进行请求测试:</p><ul><li>curl 版本: 8.4.0</li><li>请求协议版本: HTTP/1.1</li></ul><p><strong>验证方式</strong></p><p>在”正常域名”配置不变的情况下，不断修改兜底域名配置，客户端重复请求进行验证。</p><h3 id="实验过程"><a href="#实验过程" class="headerlink" title="实验过程"></a>实验过程</h3><h4 id="server-name-“”-并且是-default-server"><a href="#server-name-“”-并且是-default-server" class="headerlink" title="server_name “” 并且是 default_server"></a>server_name “” 并且是 default_server</h4><p><strong>客户端请求携带 Host</strong></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># curl http://192.168.7.27 -v</span>*   Trying <span class="token number">192.168</span>.7.27:80<span class="token punctuation">..</span>.* Connected to <span class="token number">192.168</span>.7.27 <span class="token punctuation">(</span><span class="token number">192.168</span>.7.27<span class="token punctuation">)</span> port <span class="token number">80</span><span class="token operator">></span> GET / HTTP/1.1<span class="token operator">></span> Host: <span class="token number">192.168</span>.7.27<span class="token operator">></span> User-Agent: curl/8.4.0<span class="token operator">></span> Accept: */*<span class="token operator">></span><span class="token operator">&lt;</span> HTTP/1.1 <span class="token number">200</span> OK<span class="token operator">&lt;</span> Server: nginx<span class="token operator">&lt;</span> Date: Fri, 05 Apr <span class="token number">2024</span> 07:47:51 GMT<span class="token operator">&lt;</span> Content-Type: application/octet-stream<span class="token operator">&lt;</span> Content-Length: <span class="token number">37</span><span class="token operator">&lt;</span> Connection: close<span class="token operator">&lt;</span> content-type: application/json<span class="token operator">&lt;</span>* Closing connection<span class="token punctuation">&#123;</span><span class="token string">"status"</span><span class="token builtin class-name">:</span> <span class="token string">"This is the a-test.conf"</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong>客户端请求不携带 Host</strong></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># curl 192.168.7.27 -v -H "Host: "</span>*   Trying <span class="token number">192.168</span>.7.27:80<span class="token punctuation">..</span>.* Connected to <span class="token number">192.168</span>.7.27 <span class="token punctuation">(</span><span class="token number">192.168</span>.7.27<span class="token punctuation">)</span> port <span class="token number">80</span><span class="token operator">></span> GET / HTTP/1.1<span class="token operator">></span> Host:<span class="token operator">></span> User-Agent: curl/8.4.0<span class="token operator">></span> Accept: */*<span class="token operator">></span><span class="token operator">&lt;</span> HTTP/1.1 <span class="token number">400</span> Bad Request<span class="token operator">&lt;</span> Server: nginx<span class="token operator">&lt;</span> Date: Fri, 05 Apr <span class="token number">2024</span> 03:51:50 GMT<span class="token operator">&lt;</span> Content-Type: text/html<span class="token punctuation">;</span> <span class="token assign-left variable">charset</span><span class="token operator">=</span>utf-8<span class="token operator">&lt;</span> Content-Length: <span class="token number">150</span><span class="token operator">&lt;</span> Connection: close<span class="token operator">&lt;</span><span class="token operator">&lt;</span>html<span class="token operator">></span><span class="token operator">&lt;</span>head<span class="token operator">></span><span class="token operator">&lt;</span>title<span class="token operator">></span><span class="token number">400</span> Bad Request<span class="token operator">&lt;</span>/title<span class="token operator">></span><span class="token operator">&lt;</span>/head<span class="token operator">></span><span class="token operator">&lt;</span>body<span class="token operator">></span><span class="token operator">&lt;</span>center<span class="token operator">></span><span class="token operator">&lt;</span>h<span class="token operator"><span class="token file-descriptor important">1</span>></span><span class="token number">400</span> Bad Request<span class="token operator">&lt;</span>/h<span class="token operator"><span class="token file-descriptor important">1</span>></span><span class="token operator">&lt;</span>/center<span class="token operator">></span><span class="token operator">&lt;</span>hr<span class="token operator">></span><span class="token operator">&lt;</span>center<span class="token operator">></span>nginx<span class="token operator">&lt;</span>/center<span class="token operator">></span><span class="token operator">&lt;</span>/body<span class="token operator">></span><span class="token operator">&lt;</span>/html<span class="token operator">></span>* Closing connection<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="server-name-“”-但不是-default-server"><a href="#server-name-“”-但不是-default-server" class="headerlink" title="server_name “” 但不是 default_server"></a>server_name “” 但不是 default_server</h4><p><strong>Nginx 兜底域名配置改为如下</strong></p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span> <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span> <span class="token string">""</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">add_header</span> content-type application/json</span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">return</span> <span class="token number">200</span> <span class="token string">'&#123;"status": "ok"&#125;'</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong>客户端请求携带 Host</strong></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># curl 192.168.7.27 -v</span>*   Trying <span class="token number">192.168</span>.7.27:80<span class="token punctuation">..</span>.* Connected to <span class="token number">192.168</span>.7.27 <span class="token punctuation">(</span><span class="token number">192.168</span>.7.27<span class="token punctuation">)</span> port <span class="token number">80</span><span class="token operator">></span> GET / HTTP/1.1<span class="token operator">></span> Host: <span class="token number">192.168</span>.7.27<span class="token operator">></span> User-Agent: curl/8.4.0<span class="token operator">></span> Accept: */*<span class="token operator">></span><span class="token operator">&lt;</span> HTTP/1.1 <span class="token number">200</span> OK<span class="token operator">&lt;</span> Server: nginx<span class="token operator">&lt;</span> Date: Fri, 05 Apr <span class="token number">2024</span> 08:16:27 GMT<span class="token operator">&lt;</span> Content-Type: application/octet-stream<span class="token operator">&lt;</span> Content-Length: <span class="token number">45</span><span class="token operator">&lt;</span> Connection: close<span class="token operator">&lt;</span> content-type: application/json<span class="token operator">&lt;</span>* Closing connection<span class="token punctuation">&#123;</span><span class="token string">"status"</span><span class="token builtin class-name">:</span> <span class="token string">"This is the z-default_test.conf"</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong>客户端请求不携带 Host</strong></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># curl http://192.168.7.27 -v -H "Host: "</span>*   Trying <span class="token number">192.168</span>.7.27:80<span class="token punctuation">..</span>.* Connected to <span class="token number">192.168</span>.7.27 <span class="token punctuation">(</span><span class="token number">192.168</span>.7.27<span class="token punctuation">)</span> port <span class="token number">80</span><span class="token operator">></span> GET / HTTP/1.1<span class="token operator">></span> Host:<span class="token operator">></span> User-Agent: curl/8.4.0<span class="token operator">></span> Accept: */*<span class="token operator">></span><span class="token operator">&lt;</span> HTTP/1.1 <span class="token number">400</span> Bad Request<span class="token operator">&lt;</span> Server: nginx<span class="token operator">&lt;</span> Date: Fri, 05 Apr <span class="token number">2024</span> 03:49:14 GMT<span class="token operator">&lt;</span> Content-Type: text/html<span class="token punctuation">;</span> <span class="token assign-left variable">charset</span><span class="token operator">=</span>utf-8<span class="token operator">&lt;</span> Content-Length: <span class="token number">150</span><span class="token operator">&lt;</span> Connection: close<span class="token operator">&lt;</span><span class="token operator">&lt;</span>html<span class="token operator">></span><span class="token operator">&lt;</span>head<span class="token operator">></span><span class="token operator">&lt;</span>title<span class="token operator">></span><span class="token number">400</span> Bad Request<span class="token operator">&lt;</span>/title<span class="token operator">></span><span class="token operator">&lt;</span>/head<span class="token operator">></span><span class="token operator">&lt;</span>body<span class="token operator">></span><span class="token operator">&lt;</span>center<span class="token operator">></span><span class="token operator">&lt;</span>h<span class="token operator"><span class="token file-descriptor important">1</span>></span><span class="token number">400</span> Bad Request<span class="token operator">&lt;</span>/h<span class="token operator"><span class="token file-descriptor important">1</span>></span><span class="token operator">&lt;</span>/center<span class="token operator">></span><span class="token operator">&lt;</span>hr<span class="token operator">></span><span class="token operator">&lt;</span>center<span class="token operator">></span>nginx<span class="token operator">&lt;</span>/center<span class="token operator">></span><span class="token operator">&lt;</span>/body<span class="token operator">></span><span class="token operator">&lt;</span>/html<span class="token operator">></span>* Closing connection<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="实验结果"><a href="#实验结果" class="headerlink" title="实验结果"></a>实验结果</h3><p>由于繁复性结果相近，所以省略了其他过程内容，以下是整体结果:</p><h4 id="当兜底配置的-listen-仅为-80-时"><a href="#当兜底配置的-listen-仅为-80-时" class="headerlink" title="当兜底配置的 listen 仅为 80 时"></a>当兜底配置的 listen 仅为 80 时</h4><p>即类似如下配置:</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span><span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span> <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span> XXXX</span><span class="token punctuation">;</span>    ...<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>注: </p><ul><li><strong>表格首列</strong>为客户端的请求 Host；</li><li><strong>表格首行</strong>为 Nginx 站点配置中的 <code>server_name</code> 配置；</li><li><strong>表格内容</strong>为 Nginx 的响应状态码/请求命中的站点配置；</li></ul></blockquote><table><thead><tr><th>访问Host</th><th><code>server_name &quot;&quot;</code></th><th><code>server_name _</code></th><th><code>server_name localhost</code></th><th><code>server_name ~^.*$</code></th></tr></thead><tbody><tr><td>Null(空)</td><td>400</td><td>400</td><td>400</td><td>400</td></tr><tr><td>localhost</td><td>a-test.conf</td><td>a-test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td></tr><tr><td>abc.nestealin.com</td><td>a-test.conf</td><td>a-test.conf</td><td>a-test.conf</td><td>a-test.conf</td></tr><tr><td>a1b2c3.nestealin.com</td><td>a-test.conf</td><td>a-test.conf</td><td>a-test.conf</td><td>z-default_test.conf</td></tr><tr><td>192.168.1.1</td><td>a-test.conf</td><td>a-test.conf</td><td>a-test.conf</td><td>z-default_test.conf</td></tr><tr><td>192.168.7.27</td><td>a-test.conf</td><td>a-test.conf</td><td>a-test.conf</td><td>z-default_test.conf</td></tr><tr><td>127.0.0.1</td><td>a-test.conf</td><td>a-test.conf</td><td>a-test.conf</td><td>z-default_test.conf</td></tr></tbody></table><h4 id="当兜底配置的-listen-为-80-default-server-时"><a href="#当兜底配置的-listen-为-80-default-server-时" class="headerlink" title="当兜底配置的 listen 为 80 default_server 时"></a>当兜底配置的 listen 为 80 default_server 时</h4><p>即类似如下配置:</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span><span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span> <span class="token number">80</span> default_server</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span> XXXX</span><span class="token punctuation">;</span>    ...<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>注: </p><ul><li><strong>表格首列</strong>为客户端的请求 Host；</li><li><strong>表格首行</strong>为 Nginx 站点配置中的 <code>server_name</code> 配置；</li><li><strong>表格内容</strong>为 Nginx 的响应状态码/请求命中的站点配置；</li></ul></blockquote><table><thead><tr><th>访问Host</th><th><code>server_name &quot;&quot;</code></th><th><code>server_name _</code></th><th><code>server_name localhost</code></th><th><code>server_name ~^.*$</code></th></tr></thead><tbody><tr><td>Null(空)</td><td>400</td><td>400</td><td>400</td><td>400</td></tr><tr><td>localhost</td><td>z-default_test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td></tr><tr><td>abc.nestealin.com</td><td>a-test.conf</td><td>a-test.conf</td><td>a-test.conf</td><td>a-test.conf</td></tr><tr><td>a1b2c3.nestealin.com</td><td>z-default_test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td></tr><tr><td>192.168.1.1</td><td>z-default_test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td></tr><tr><td>192.168.7.27</td><td>z-default_test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td></tr><tr><td>127.0.0.1</td><td>z-default_test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td><td>z-default_test.conf</td></tr></tbody></table><h3 id="实验小结"><a href="#实验小结" class="headerlink" title="实验小结"></a>实验小结</h3><ul><li>无论是否存在默认监听（<code>listen $&#123;Port&#125; default_server;</code>），当请求 Host 为空时，响应结果均为 400；</li><li>当没有默认监听且请求 Host 为 localhost 时，如果存在 <code>server_name  localhost</code> 的话，在 Nginx 看来该 <code>server_name</code> 也是一个”精确域名”，可以命中对应 server 配置；</li><li>当没有默认监听且请求 Host 不为空时，<code>server_name</code> 匹配顺序: 精准域名 &gt; 泛域名 &gt; 正则域名 &gt; <code>localhost</code> （如果恰好有 Host 也为 localhost 的话） &gt; 站点(配置文件)顺序；即”无意义域名”（<code>server_name _</code> 等）并非真正意义上的”兜底域名”；</li><li>当存在默认监听且请求 Host 不为空时，”无意义域名”、”localhost”、”<code>~^.*$</code>“配置等价，都能作为”兜底域名”存在，实现拦截对应 listen 端口中所有 server 配置外的 HTTP 请求；</li></ul><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ul><li>在条件允许的情况下，应尽量使用精确域名，其次泛域名，最后是正则域名，请尽量少用无意义域名；</li><li>在使用正则域名时，必须以 <code>~</code> 开头（否则将会认为是精确字符匹配），并建议使用 <code>^</code> 和 <code>$</code> 符号分别作为”开头”和”结束”的锚点；</li><li>在 listen 指令中，<code>default</code> 与 <code>default_server</code> 作用相同，在 0.8.21 及以后的 Nginx 版本中，推荐使用 <code>default_server</code> 更符合官方规范；</li><li>当请求 Host 为空时，Nginx 会遵循 RFC 7230, Section 5.4 中的规定[^3]直接响应 400 状态码，无视所有匹配规则；</li><li>当 <code>server_name &quot;&quot;</code> 等无意义域名期望作为”兜底配置”存在时，其 listen 指令必须要有 <code>default_server</code> 参数，否则可能会因匹配顺序而无法实现相应兜底逻辑；</li><li>当没有默认监听且请求 Host 为 localhost 时，如果存在 <code>server_name  localhost</code> 的配置，则该 <code>server_name</code> 也是一个”精确域名”，可以命中对应 server 配置；</li></ul><hr><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><h3 id="1-匹配-80-端口的所有-HTTP-请求-（兜底）"><a href="#1-匹配-80-端口的所有-HTTP-请求-（兜底）" class="headerlink" title="1. 匹配 80 端口的所有 HTTP 请求 （兜底）"></a>1. 匹配 80 端口的所有 HTTP 请求 （兜底）</h3><h4 id="写法一-正则域名"><a href="#写法一-正则域名" class="headerlink" title="写法一: 正则域名"></a>写法一: 正则域名</h4><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span><span class="token directive"><span class="token keyword">listen</span>       <span class="token number">80</span> default_server</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">server_name</span>  ~^.*$</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">access_log</span> logs/default.access.log main</span><span class="token punctuation">;</span>...<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>通常，这种配置会作为兜底模块，其 listen 也建议设置成 <code>default_server</code> 进行兜底拦截，实现捕获所有规则外的请求。</p><blockquote><p>注: 在 Nginx 0.8.21 之前的版本里，需要”默认监听”使用”<code>default</code>“进行声明；从 0.8.21 开始的版本新加入了”<code>default_server</code>“参数，其作用与”<code>default</code>“等价并兼容旧版本写法，可以选择任一声明。</p></blockquote><h4 id="写法二-无意义域名"><a href="#写法二-无意义域名" class="headerlink" title="写法二: 无意义域名"></a>写法二: 无意义域名</h4><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span><span class="token directive"><span class="token keyword">listen</span>       <span class="token number">80</span> default_server</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">server_name</span>  _</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">access_log</span> logs/default.access.log main</span><span class="token punctuation">;</span>...<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>虽然不推荐这种方式，但其匹配顺序可以作为正则域名后的补充，可以提供参考。（例如: 存在大量正则域名，怕影响现存正则写法的情况。）</p><blockquote><p><strong>注意:</strong> 该配置的 <code>default_server</code> <strong>不能去除</strong>，否则可能导致配置无效。</p></blockquote><h3 id="2-匹配-80-端口所有-HTTP-请求并响应断开连接-（兜底）"><a href="#2-匹配-80-端口所有-HTTP-请求并响应断开连接-（兜底）" class="headerlink" title="2. 匹配 80 端口所有 HTTP 请求并响应断开连接 （兜底）"></a>2. 匹配 80 端口所有 HTTP 请求并响应断开连接 （兜底）</h3><p>如果 Nginx 对客户端请求有要求，客户端必须携带合规的 “Host” 标头字段才能访问（即自己没有配置的 <code>server_name</code> 都不允许访问），则可以定义一个 server 块来直接丢弃非法请求：</p><blockquote><p>注: “Host”字段可以是 IP 地址，也可以是域名。</p></blockquote><h4 id="写法一-正则域名-1"><a href="#写法一-正则域名-1" class="headerlink" title="写法一: 正则域名"></a>写法一: 正则域名</h4><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span><span class="token directive"><span class="token keyword">listen</span>       <span class="token number">80</span> default_server</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">server_name</span>  ~^.*$</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">access_log</span> logs/default.access.log main</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">return</span>      <span class="token number">444</span></span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="写法二-无意义域名-1"><a href="#写法二-无意义域名-1" class="headerlink" title="写法二: 无意义域名"></a>写法二: 无意义域名</h4><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span><span class="token directive"><span class="token keyword">listen</span>       <span class="token number">80</span> default_server</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">server_name</span>  _</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">access_log</span> logs/default.access.log main</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">return</span>      <span class="token number">444</span></span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><hr><h2 id="References"><a href="#References" class="headerlink" title="References"></a>References</h2><ul><li><a href="https://nginx.org/en/docs/http/server_names.html">Nginx Doc - Server names</a></li><li><a href="https://nicechiblog.com/article/22/article_1599041059396.html">我所理解的 nginx 中 server_name “” 与 server_name _ 之间的区别 - Nginx - NICECHI 博客</a></li><li><a href="https://serverfault.com/questions/914906/what-is-the-difference-between-server-name-and-server-name-in-nginx">virtualhost - What is the difference between server_name _ and server_name “” in Nginx? - Server Fault</a></li><li><a href="https://nginx.org/en/docs/http/request_processing.html">How nginx processes a request</a></li><li><a href="https://www.nginx.com/resources/wiki/start/topics/examples/server_blocks/#a-default-catch-all-server-block">Server Block Examples | NGINX</a></li><li><a href="https://mynotebook.readthedocs.io/en/latest/linux/services/nginx/nginx_handle_servername.html">nginx中server_name查询顺序 — Learning Notebook v1.0 documentation</a></li><li><a href="https://www.cnblogs.com/gongjingyun123--/p/11449023.html">Nginx常见问题 - gong^_^ - 博客园</a></li></ul><p>[^1]: <a href="https://icannwiki.org/Internationalized_Domain_Name">Internationalized Domain Name - ICANNWIki</a><br>[^2]: <a href="https://en.wikipedia.org/wiki/Internationalized_domain_name">Internationalized domain name - Wikipedia</a><br>[^3]: <a href="https://datatracker.ietf.org/doc/html/rfc7230#section-5.4">RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;在早前 &lt;a href=&quot;https://nestealin.com/d21bac89/&quot;&gt;初识Nginx中server和location的</summary>
      
    
    
    
    <category term="nginx" scheme="https://nestealin.com/categories/nginx/"/>
    
    
    <category term="nginx" scheme="https://nestealin.com/tags/nginx/"/>
    
    <category term="无意义域名" scheme="https://nestealin.com/tags/%E6%97%A0%E6%84%8F%E4%B9%89%E5%9F%9F%E5%90%8D/"/>
    
    <category term="国际化域名" scheme="https://nestealin.com/tags/%E5%9B%BD%E9%99%85%E5%8C%96%E5%9F%9F%E5%90%8D/"/>
    
    <category term="server_name匹配顺序及规则" scheme="https://nestealin.com/tags/server-name%E5%8C%B9%E9%85%8D%E9%A1%BA%E5%BA%8F%E5%8F%8A%E8%A7%84%E5%88%99/"/>
    
    <category term="server_name泛域名及兜底域名配置" scheme="https://nestealin.com/tags/server-name%E6%B3%9B%E5%9F%9F%E5%90%8D%E5%8F%8A%E5%85%9C%E5%BA%95%E5%9F%9F%E5%90%8D%E9%85%8D%E7%BD%AE/"/>
    
    <category term="server_name正则域名" scheme="https://nestealin.com/tags/server-name%E6%AD%A3%E5%88%99%E5%9F%9F%E5%90%8D/"/>
    
  </entry>
  
  <entry>
    <title>Python3及虚拟环境(virtualenv)一键安装脚本(含升级OpenSSL-1.1.1)</title>
    <link href="https://nestealin.com/77134c2c/"/>
    <id>https://nestealin.com/77134c2c/</id>
    <published>2024-01-14T16:59:23.000Z</published>
    <updated>2024-08-04T06:56:53.351Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>对于混合部署的实例需要共存多个 Python 环境，为了避免依赖冲突本脚本使用了 virtualenv 管理虚拟环境，实现相互隔离。</p><h3 id="脚本说明"><a href="#脚本说明" class="headerlink" title="脚本说明"></a>脚本说明</h3><p>该脚本默认是基于 OpenSSL-1.1.1 来安装 3.7.11 版本的 Python 。</p><p>源码包目录，默认位于执行脚本当前目录的 packages 中。（ 如有自定义路径需求，请修改脚本中 <code>packages_dir</code> 变量。 ）</p><p>安装目录，默认分别位于 <code>/usr/local/openssl-1.1.1k</code> 及 <code>/usr/local/python-3.7.11</code> 中。 （ 脚本内写死 ）</p><p>虚拟环境目录，默认位于 <code>/data1/virtualpython</code> 目录下。 （ 脚本内写死 ）</p><h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><ul><li>对于环境变量的改变:<ul><li>安装完 Python 后，默认会将新版 OpenSSL 加载至系统环境中，加载配置文件 <code>/etc/ld.so.conf.d/openssl-1.1.1k-x86_64.conf</code> 。</li><li>安装完 Python 后，默认会添加 <code>/usr/local/python3</code> 、 <code>/usr/bin/python3</code> 、 <code>/usr/bin/pip3</code> 三个软链。</li></ul></li></ul><hr><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><h3 id="脚本内容"><a href="#脚本内容" class="headerlink" title="脚本内容"></a>脚本内容</h3><p>创建脚本文件</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">vim</span> py3_auto_install.sh<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>脚本内容</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token shebang important">#!/bin/bash</span><span class="token comment"># Author: nestealin</span><span class="token comment"># Created: 2022-12-11</span><span class="token comment"># Update: 2023-05-13 change openssl version from 1.1.1a to 1.1.1k</span><span class="token comment"># Update: 2023-09-23 promt Python and Openssl version to variables</span><span class="token assign-left variable">command</span><span class="token operator">=</span><span class="token variable">$1</span><span class="token assign-left variable">install_script_dir</span><span class="token operator">=</span><span class="token string">"$( cd "<span class="token variable"><span class="token variable">$(</span> <span class="token function">dirname</span> <span class="token string">"<span class="token variable">$0</span>"</span>  <span class="token variable">)</span></span>"</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">pwd</span>  <span class="token punctuation">)</span><span class="token string">"packages_dir="</span><span class="token variable">$install_script_dir</span>/packages<span class="token string">"PYTHON_VERSION="</span><span class="token number">3.7</span>.11<span class="token string">"PYTHON_MAIN_VERSION=<span class="token variable"><span class="token variable">$(</span><span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$PYTHON_VERSION</span>"</span> <span class="token operator">|</span> <span class="token function">cut</span> -d. -f1-2<span class="token variable">)</span></span>OPENSSL_VERSION="</span><span class="token number">1.1</span>.1k<span class="token string">"# EnvPreparefunction Setup_Install_Env() &#123;    yum install gcc zlib-devel make libffi-devel -y    yum install -y ca-certificates    [ ! -d <span class="token variable">$packages_dir</span> ] &amp;&amp; mkdir <span class="token variable">$packages_dir</span>    echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>32mpackages directory: <span class="token variable">$packages_dir</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">"&#125;# Download Packagesfunction Download_Python_Package() &#123;    cd <span class="token variable">$packages_dir</span>    tarball="</span>Python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>.tar.xz<span class="token string">"    if [ ! -f <span class="token variable">$tarball</span> ]; then        echo "</span>Downloading <span class="token variable">$tarball</span><span class="token string">"        wget https://www.python.org/ftp/python/<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/<span class="token variable">$tarball</span>    [ ! -f <span class="token variable">$tarball</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to download <span class="token variable">$tarball</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Download_Openssl_Packages() &#123;    cd <span class="token variable">$packages_dir</span>    tarball="</span>openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>.tar.gz<span class="token string">"    if [ ! -f <span class="token variable">$tarball</span> ]; then        echo "</span>Downloading <span class="token variable">$tarball</span><span class="token string">"        wget https://www.openssl.org/source/<span class="token variable">$tarball</span>        echo "</span>Downloading cacert.pem<span class="token string">"        wget http://curl.haxx.se/ca/cacert.pem    [ ! -f <span class="token variable">$tarball</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to download <span class="token variable">$tarball</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Download_Pip3_Package() &#123;    cd <span class="token variable">$packages_dir</span>    tarball="</span>ez_setup.py<span class="token string">"    if [ ! -f <span class="token variable">$tarball</span> ]; then        echo "</span>Downloading <span class="token variable">$tarball</span><span class="token string">"        wget https://bootstrap.pypa.io/<span class="token variable">$tarball</span> --no-check-certificate    [ ! -f <span class="token variable">$tarball</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to download <span class="token variable">$tarball</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Install_Openssl() &#123;    install_dir="</span>/usr/local/openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span><span class="token string">"    cd <span class="token variable">$packages_dir</span>    tarball="</span>openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>.tar.gz<span class="token string">"    tar -zxvf <span class="token variable">$tarball</span>    cd openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>    ./config --prefix=<span class="token variable">$install_dir</span> --openssldir=<span class="token variable">$install_dir</span>    make -j <span class="token variable"><span class="token variable">`</span><span class="token function">cat</span> /proc/cpuinfo <span class="token operator">|</span> <span class="token function">grep</span> -i name <span class="token operator">|</span> <span class="token function">wc</span> -l<span class="token variable">`</span></span> &amp;&amp; make install    if [ -d <span class="token variable">$install_dir</span> ]; then        mv <span class="token variable">$packages_dir</span>/cacert.pem /usr/local/openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>/cert.pem        echo "</span>/usr/local/openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>/lib<span class="token string">" > /etc/ld.so.conf.d/openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>-x86_64.conf        ldconfig    [ ! -d <span class="token variable">$install_dir</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to <span class="token function">install</span> <span class="token variable">$install_dir</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Install_Python3() &#123;    install_dir="</span>/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span><span class="token string">"    openssl_dir="</span>/usr/local/openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span><span class="token string">"    cd <span class="token variable">$packages_dir</span>    tar xvf Python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>.tar.xz    cd Python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>    ./configure --prefix=/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span> --enable-optimizations --with-openssl=<span class="token variable">$openssl_dir</span>    make -j <span class="token variable"><span class="token variable">`</span><span class="token function">cat</span> /proc/cpuinfo <span class="token operator">|</span> <span class="token function">grep</span> -i name <span class="token operator">|</span> <span class="token function">wc</span> -l<span class="token variable">`</span></span> &amp;&amp; make install    if [ -d <span class="token variable">$install_dir</span> ]; then        ln -s /usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span> /usr/local/python3        ln -s /usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/python<span class="token variable">$&#123;PYTHON_MAIN_VERSION&#125;</span> /usr/bin/python3        ln -s /usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/pip3 /usr/bin/pip3    [ ! -d <span class="token variable">$install_dir</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to <span class="token function">install</span> <span class="token variable">$install_dir</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Install_Pip3() &#123;    install_dir="</span>/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin<span class="token string">"    cd <span class="token variable">$packages_dir</span>    if [ -d <span class="token variable">$install_dir</span> ]; then        <span class="token variable">$install_dir</span>/python3 ez_setup.py    [ ! -d <span class="token variable">$install_dir</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to <span class="token function">install</span> <span class="token variable">$install_dir</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Install_Virtualenv() &#123;    install_dir="</span>/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin<span class="token string">"    if [ -d <span class="token variable">$install_dir</span> ]; then        <span class="token variable">$install_dir</span>/pip3 install virtualenv virtualenvwrapper    [ ! -d <span class="token variable">$install_dir</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to <span class="token function">install</span> <span class="token variable">$install_dir</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi    virtualenvwrapper_script="</span>virtualenvwrapper.sh<span class="token string">"    if [ -f <span class="token variable">$install_dir</span>/virtualenvwrapper.sh ]; then        mkdir -p /data1/virtualpython/virtualenvs &amp;&amp; mkdir /data1/virtualpython/PyEnv        mkdir -p /data1/virtualpython_others/virtualenvs &amp;&amp; mkdir /data1/virtualpython_others/PyEnv        env=<span class="token variable"><span class="token variable">$(</span><span class="token function">cat</span> <span class="token operator">&lt;&lt;</span><span class="token string">EOF<span class="token bash punctuation"> <span class="token operator">>></span>~/.bashrc</span># 为非root用户提供if [ <span class="token variable"><span class="token variable">`</span><span class="token function">id</span> -u<span class="token variable">`</span></span> != '0' ]; then    export WORKON_HOME=/data1/virtualpython_others/virtualenvs    export PROJECT_HOME=/data1/virtualpython_others/PyEnvs    source /usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/virtualenvwrapper.shfi# 如果root用户添加如下:export WORKON_HOME=/data1/virtualpython/virtualenvsexport PROJECT_HOME=/data1/virtualpython/PyEnvsexport VIRTUALENVWRAPPER_PYTHON=/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/python<span class="token variable">$&#123;PYTHON_MAIN_VERSION&#125;</span>export VIRTUALENVWRAPPER_VIRTUALENV=/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/virtualenvsource /usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/virtualenvwrapper.shEOF</span><span class="token variable">)</span></span>        <span class="token variable">$env</span>        source ~/.bashrc    [ ! -f <span class="token variable">$install_dir</span>/virtualenvwrapper.sh ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to <span class="token function">install</span> virtualenvwrapper.sh<span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;# HELP，-p|--python-only 仅安装python，默认项 , -v|--with-virtualEnv 虚拟环境function help()&#123;    echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31musage: <span class="token variable">$0</span> Options: <span class="token punctuation">[</span>-d<span class="token operator">|</span>-p<span class="token punctuation">]</span> <span class="token punctuation">[</span>-v<span class="token punctuation">]</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">"    echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mOPTIONS:<span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">"    echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31m    -d<span class="token operator">|</span>-p<span class="token operator">|</span>--python-only    <span class="token function">install</span> python only, Default option<span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">"    echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31m    -v<span class="token operator">|</span>--with-virtualEnv   instal python with virtualEnv<span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">"&#125;case <span class="token variable">$command</span> in    (-d|-p|--python-only)        Setup_Install_Env        Download_Openssl_Packages        Install_Openssl        Download_Python_Package        Download_Pip3_Package        Install_Python3        Install_Pip3        ;;    (-v|--with-virtualEnv)        Setup_Install_Env        Download_Openssl_Packages        Install_Openssl        Download_Python_Package        Download_Pip3_Package        Install_Python3        Install_Pip3        Install_Virtualenv        ;;    (-h|--help|help)        help        ;;    (*)        echo "</span>Error command"        <span class="token builtin class-name">help</span>        <span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token keyword">esac</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="使用方式"><a href="#使用方式" class="headerlink" title="使用方式"></a>使用方式</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">chmod</span> +x py3_auto_install.sh<span class="token comment"># 只安装Python3</span>./py3_auto_install.sh -d<span class="token comment"># 安装Python3，同时安装并配置虚拟环境</span>./py3_auto_install.sh -v<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;对于混合部署的实例需要共存多个 Python 环境，为了避免依赖冲突本脚本使用了 virtualenv 管理虚拟环境，实现相互隔离。&lt;/p&gt;</summary>
      
    
    
    
    <category term="coding" scheme="https://nestealin.com/categories/coding/"/>
    
    
    <category term="python" scheme="https://nestealin.com/tags/python/"/>
    
    <category term="virtualenv" scheme="https://nestealin.com/tags/virtualenv/"/>
    
    <category term="虚拟环境" scheme="https://nestealin.com/tags/%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83/"/>
    
    <category term="shell" scheme="https://nestealin.com/tags/shell/"/>
    
  </entry>
  
  <entry>
    <title>Python3使用socket访问HTTPS链接报错: unable to get local issuer certificate</title>
    <link href="https://nestealin.com/d81f4203/"/>
    <id>https://nestealin.com/d81f4203/</id>
    <published>2024-01-14T16:07:10.000Z</published>
    <updated>2024-08-04T06:56:53.350Z</updated>
    
    <content type="html"><![CDATA[<h3 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h3><p>当使用 <code>urllib.urlopen</code> 或 <code>socket</code> 打开一个 HTTPS 链接时抛出如下异常：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">urllib.error.URLError: <span class="token operator">&lt;</span>urlopen error <span class="token punctuation">[</span>SSL: CERTIFICATE_VERIFY_FAILED<span class="token punctuation">]</span> certificate verify failed: unable to get <span class="token builtin class-name">local</span> issuer certificate <span class="token punctuation">(</span>_ssl.c:1076<span class="token punctuation">)</span><span class="token operator">></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h3><ul><li>OpenSSL 本地 CA 证书不存在。</li></ul><h3 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h3><ol><li>查看默认证书位置</li></ol>  <pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> ssl<span class="token keyword">print</span><span class="token punctuation">(</span>ssl<span class="token punctuation">.</span>get_default_verify_paths<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><ul><li><p>执行结果：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">DefaultVerifyPaths<span class="token punctuation">(</span><span class="token assign-left variable">cafile</span><span class="token operator">=</span>None, <span class="token assign-left variable">capath</span><span class="token operator">=</span><span class="token string">'/usr/local/openssl-1.1.1/certs'</span>, <span class="token assign-left variable">openssl_cafile_env</span><span class="token operator">=</span><span class="token string">'SSL_CERT_FILE'</span>, <span class="token assign-left variable">openssl_cafile</span><span class="token operator">=</span><span class="token string">'/usr/local/openssl-1.1.1/cert.pem'</span>, <span class="token assign-left variable">openssl_capath_env</span><span class="token operator">=</span><span class="token string">'SSL_CERT_DIR'</span>, <span class="token assign-left variable">openssl_capath</span><span class="token operator">=</span><span class="token string">'/usr/local/openssl-1.1.1/certs'</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>由结果可见，CA 文件不存在。</li></ul></li></ul><ol start="2"><li>下载 CA 文件</li></ol><ul><li><p>将下载的 CA 文件放到 <code>openssl_cafile</code> 指定位置，并创建 <code>openssl_capath</code> 指定目录</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">mkdir</span> /usr/local/openssl-1.1.1/certs<span class="token comment"># 切换到当前openssl目录，并下载ca文件</span><span class="token builtin class-name">cd</span> /usr/local/openssl-1.1.1/<span class="token function">wget</span> http://curl.haxx.se/ca/cacert.pem<span class="token function">mv</span> cacert.pem cert.pem<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><p><strong>注意事项</strong></p><ul><li>可能存在系统差异，<code>openssl</code> 的目录会有所变化，以具体 <code>print(ssl.get_default_verify_paths())</code> 的执行结果输出为准。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h3&gt;&lt;p&gt;当使用 &lt;code&gt;urllib.urlopen&lt;/code&gt; 或 &lt;code&gt;socket&lt;/code&gt; 打开一个 HTT</summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="python" scheme="https://nestealin.com/tags/python/"/>
    
  </entry>
  
  <entry>
    <title>CentOS系统安装Python-3.7.11及OpenSSL-1.1.1</title>
    <link href="https://nestealin.com/6b5054e0/"/>
    <id>https://nestealin.com/6b5054e0/</id>
    <published>2024-01-14T15:06:30.000Z</published>
    <updated>2024-08-04T06:56:53.350Z</updated>
    
    <content type="html"><![CDATA[<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>本文将以两种方式安装 Python3、PiP3及虚拟环境(virtualenv)</p><hr><h2 id="手动安装"><a href="#手动安装" class="headerlink" title="手动安装"></a>手动安装</h2><h3 id="准备环境"><a href="#准备环境" class="headerlink" title="准备环境"></a>准备环境</h3><h4 id="安装依赖"><a href="#安装依赖" class="headerlink" title="安装依赖"></a>安装依赖</h4><p><code>libffi-devel</code> 一定要装，否则报错 <code>No module named &#39;_ctypes&#39;</code> .</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yum <span class="token function">install</span> gcc zlib-devel <span class="token function">make</span> libffi-devel -y<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h4 id="升级OpenSSL"><a href="#升级OpenSSL" class="headerlink" title="升级OpenSSL"></a>升级OpenSSL</h4><blockquote><p>如果仅安装 Python2 可以选择忽略该步骤。</p></blockquote><p>为 Python3 单独升级 openssl；为了避免与系统已有 openssl 冲突，因此安装到其他路径:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">wget</span> https://www.openssl.org/source/openssl-1.1.1k.tar.gz --no-check-certificate<span class="token function">tar</span> -zxvf openssl-1.1.1k.tar.gz<span class="token builtin class-name">cd</span> openssl-1.1.1k./config --prefix<span class="token operator">=</span>/usr/local/openssl-1.1.1 --openssldir<span class="token operator">=</span>/usr/local/openssl-1.1.1 <span class="token function">make</span> <span class="token operator">&amp;&amp;</span> <span class="token function">make</span> <span class="token function">install</span><span class="token comment"># 方法一，声明临时变量，怕影响线上服务推荐使用该方法</span><span class="token comment"># 包括后续引用库文件都要提前声明</span><span class="token builtin class-name">export</span> <span class="token assign-left variable">LD_LIBRARY_PATH</span><span class="token operator">=</span>/usr/local/openssl-1.1.1/lib:<span class="token variable">$LD_LIBRARY_PATH</span><span class="token comment"># 方法二，永久声明变量</span><span class="token builtin class-name">echo</span> <span class="token string">"/usr/local/openssl-1.1.1/lib"</span> <span class="token operator">>></span> /etc/ld.so.conf.d/openssl-1.1.1-x86_64.confldconfig<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="安装Python"><a href="#安装Python" class="headerlink" title="安装Python"></a>安装Python</h3><h4 id="Python2"><a href="#Python2" class="headerlink" title="Python2"></a>Python2</h4><p>以安装 Python-2.7.18 为例。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">wget</span> https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tar.xz<span class="token function">tar</span> xf Python-2.7.18.tar.xz<span class="token builtin class-name">cd</span> Python-2.7.18<span class="token function">sudo</span> ./configure --prefix<span class="token operator">=</span>/usr/local/python-2.7.18 --enable-optimizations<span class="token function">sudo</span> <span class="token function">make</span> <span class="token operator">&amp;&amp;</span> <span class="token function">sudo</span> <span class="token function">make</span> <span class="token function">install</span><span class="token function">sudo</span> <span class="token function">ln</span> -s /usr/local/python-2.7.18 /usr/local/python2.7<span class="token function">sudo</span> <span class="token function">ln</span> -s /usr/local/python-2.7.18/bin/python2.7 /usr/bin/python2.7<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h5 id="安装-pip2"><a href="#安装-pip2" class="headerlink" title="安装 pip2"></a>安装 pip2</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">curl</span> https://bootstrap.pypa.io/pip/2.7/get-pip.py -o get-pip.py<span class="token function">sudo</span> python2.7 get-pip.py<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h4 id="Python3"><a href="#Python3" class="headerlink" title="Python3"></a>Python3</h4><blockquote><p>以安装 Python-3.7.11 为例。</p></blockquote><h5 id="下载源码"><a href="#下载源码" class="headerlink" title="下载源码"></a>下载源码</h5><p>下载 Python 版本</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">wget</span> https://www.python.org/ftp/python/3.7.11/Python-3.7.11.tar.xz<span class="token function">tar</span> xvf Python-3.7.11.tar.xz<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h5 id="编译安装"><a href="#编译安装" class="headerlink" title="编译安装"></a>编译安装</h5><p>解压缩、编译和安装</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> Python-3.7.11<span class="token function">sudo</span> ./configure --prefix<span class="token operator">=</span>/usr/local/python-3.7.11 --enable-optimizations --with-openssl<span class="token operator">=</span>/usr/local/openssl-1.1.1<span class="token function">sudo</span> <span class="token function">make</span> <span class="token operator">&amp;&amp;</span> <span class="token function">sudo</span> <span class="token function">make</span> <span class="token function">install</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h5 id="更新环境"><a href="#更新环境" class="headerlink" title="更新环境"></a>更新环境</h5><p>做个软连接到当前用户的 bin 目录</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">ln</span> -s /usr/local/python-3.7.11 /usr/local/python3<span class="token function">ln</span> -s /usr/local/python-3.7.11/bin/python3.7 /usr/bin/python3<span class="token function">ln</span> -s /usr/local/python-3.7.11/bin/pip3 /usr/bin/pip3<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>升级安装好新版本 Python 以后，需要将工程文件 Python2.6 的文件头部 <code>#!/usr/bin/python</code> 修改为 Python3 的路径，例如:  <code>#!/opt/python3/bin/python3</code> 。</p><p><strong>扩展说明:</strong> 假设要安装3.8.5，可参考如下:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">PYTHON_VERSION</span><span class="token operator">=</span><span class="token string">"3.8.5"</span><span class="token builtin class-name">cd</span> /usr/local/src<span class="token function">wget</span> https://www.python.org/ftp/python/<span class="token variable">$PYTHON_VERSION</span>/Python-<span class="token variable">$PYTHON_VERSION</span>.tar.xz<span class="token function">tar</span> xf Python-<span class="token variable">$PYTHON_VERSION</span>.tar.xz<span class="token builtin class-name">cd</span> Python-<span class="token variable">$PYTHON_VERSION</span>/./configure --prefix<span class="token operator">=</span>/usr/local/python-<span class="token variable">$PYTHON_VERSION</span> --enable-optimizations --with-openssl<span class="token operator">=</span>/usr/local/openssl-1.1.1<span class="token function">make</span> -j <span class="token variable"><span class="token variable">`</span><span class="token function">cat</span> /proc/cpuinfo <span class="token operator">|</span> <span class="token function">grep</span> -i <span class="token string">"model name"</span> <span class="token operator">|</span> <span class="token function">wc</span> -l<span class="token variable">`</span></span> <span class="token operator">&amp;&amp;</span> <span class="token function">make</span> <span class="token function">install</span><span class="token function">ln</span> -s /usr/local/python-3.8.5/bin/python3.8 /usr/bin/python3.8<span class="token function">ln</span> -s /usr/local/python-3.8.5/bin/pip3 /usr/bin/pip3.8<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h5 id="安装-pip3-和-easy-install"><a href="#安装-pip3-和-easy-install" class="headerlink" title="安装 pip3 和 easy_install"></a>安装 pip3 和 easy_install</h5><p>安装完检查下服务器上面是否有了 pip3 命令和 easy_install-3.6 如果没有的话按以下步骤安装。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 下载setuptools,easy_install 的安装包</span><span class="token function">wget</span> https://bootstrap.pypa.io/ez_setup.py --no-check-certificate<span class="token comment"># 安装easy_install</span><span class="token comment"># 记得用python3安装</span>python3 ez_setup.py<span class="token comment">#安装完成后/usr/local/bin/目录下出现easy_install</span><span class="token comment">#安装pip3</span>easy_install-3.6 pip<span class="token comment">#安装完成后/usr/local/bin/目录下出现pip3.6</span><span class="token comment">#升级pip3.6版本</span>pip3 <span class="token function">install</span> --upgrade pip<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h5 id="检查openssl版本"><a href="#检查openssl版本" class="headerlink" title="检查openssl版本"></a>检查openssl版本</h5><p>通过终端检查</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 从终端进入python</span>python<span class="token operator">>></span><span class="token operator">></span> <span class="token function">import</span> ssl<span class="token operator">>></span><span class="token operator">></span> ssl.OPENSSL_VERSION<span class="token operator">>></span><span class="token operator">></span> <span class="token string">'OpenSSL 1.1.1k  25 Mar 2021'</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>通过脚本检查</p><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token comment">#!/usr/bin/python3</span><span class="token comment"># -*- coding: UTF-8 -*-</span><span class="token keyword">import</span> ssl<span class="token keyword">print</span><span class="token punctuation">(</span>ssl<span class="token punctuation">.</span>OPENSSL_VERSION<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h5 id=""><a href="#" class="headerlink" title=""></a></h5><hr><h2 id="一键脚本安装"><a href="#一键脚本安装" class="headerlink" title="一键脚本安装"></a>一键脚本安装</h2><h3 id="简要说明"><a href="#简要说明" class="headerlink" title="简要说明"></a>简要说明</h3><p>该脚本默认是基于 OpenSSL-1.1.1 来安装 3.7.11 版本的 Python 。</p><p>源码包目录，默认位于执行脚本当前目录的 packages 中。（ 如有自定义路径需求，请修改脚本中 <code>packages_dir</code> 变量。 ）</p><p>安装目录，默认分别位于 <code>/usr/local/openssl-1.1.1k</code> 及 <code>/usr/local/python-3.7.11</code> 中。 （ 脚本内写死 ）</p><p>虚拟环境目录，默认位于 <code>/data1/virtualpython</code> 目录下。 （ 脚本内写死 ）</p><ul><li>对于环境变量的改变:<ul><li>安装完 Python 后，默认会将新版 OpenSSL 加载至系统环境中，加载配置文件 <code>/etc/ld.so.conf.d/openssl-1.1.1k-x86_64.conf</code> 。</li><li>安装完 Python 后，默认会添加 <code>/usr/local/python3</code> 、 <code>/usr/bin/python3</code> 、 <code>/usr/bin/pip3</code> 三个软链。</li></ul></li></ul><h3 id="快速安装"><a href="#快速安装" class="headerlink" title="快速安装"></a>快速安装</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 安装Python3及PiP3</span><span class="token builtin class-name">source</span> <span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token function">curl</span> -sL https://github.com/nestealin/python3-installer/releases/download/v1.0.0/py3_auto_install.sh<span class="token punctuation">)</span> -d<span class="token comment"># 安装Python3，同时安装并配置虚拟环境</span><span class="token builtin class-name">source</span> <span class="token operator">&lt;</span><span class="token punctuation">(</span><span class="token function">curl</span> -sL https://github.com/nestealin/python3-installer/releases/download/v1.0.0/py3_auto_install.sh<span class="token punctuation">)</span> -v<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><hr><h3 id="脚本内容"><a href="#脚本内容" class="headerlink" title="脚本内容"></a>脚本内容</h3><p>如果脚本下载困难，可以通过如下脚本复制粘贴使用。</p><p>详见: <a href="https://nestealin.com/77134c2c/">Python3及虚拟环境(virtualenv)一键安装脚本(含升级OpenSSL-1.1.1)</a></p><hr><h2 id="可能遇到的问题"><a href="#可能遇到的问题" class="headerlink" title="可能遇到的问题"></a>可能遇到的问题</h2><h3 id="1-pip安装提示SSL报错"><a href="#1-pip安装提示SSL报错" class="headerlink" title="1.pip安装提示SSL报错"></a>1.pip安装提示SSL报错</h3><p>报错信息如下</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">WARNING: pip is configured with locations that require TLS/SSL, however the ssl module <span class="token keyword">in</span> Python is not availableCould not fetch URL https://pypi.org/simple/pip/: There was a problem confirming the ssl certificate: HTTPSConnectionPool<span class="token punctuation">(</span>host<span class="token operator">=</span><span class="token string">'pypi.org'</span>, <span class="token assign-left variable">port</span><span class="token operator">=</span><span class="token number">443</span><span class="token punctuation">)</span>: Max retries exceeded with url: /simple/pip/ <span class="token punctuation">(</span>Caused by SSLError<span class="token punctuation">(</span><span class="token string">"Can't connect to HTTPS URL because the SSL module is not available."</span><span class="token punctuation">))</span> - skipping<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>手动在 <code>Python</code> 中引入 <code>ssl</code> 模块也会有如下报错</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># /usr/local/python-3.7.11/bin/python3</span>Python <span class="token number">3.7</span>.11 <span class="token punctuation">(</span>default, Nov <span class="token number">20</span> <span class="token number">2022</span>, <span class="token number">21</span>:58:43<span class="token punctuation">)</span><span class="token punctuation">[</span>GCC <span class="token number">4.4</span>.7 <span class="token number">20120313</span> <span class="token punctuation">(</span>Red Hat <span class="token number">4.4</span>.7-23<span class="token punctuation">)</span><span class="token punctuation">]</span> on linuxType <span class="token string">"help"</span>, <span class="token string">"copyright"</span>, <span class="token string">"credits"</span> or <span class="token string">"license"</span> <span class="token keyword">for</span> <span class="token function">more</span> information.<span class="token operator">>></span><span class="token operator">></span> <span class="token function">import</span> sslTraceback <span class="token punctuation">(</span>most recent call last<span class="token punctuation">)</span>:  File <span class="token string">"&lt;stdin>"</span>, line <span class="token number">1</span>, <span class="token keyword">in</span> <span class="token operator">&lt;</span>module<span class="token operator">></span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/ssl.py"</span>, line <span class="token number">98</span>, <span class="token keyword">in</span> <span class="token operator">&lt;</span>module<span class="token operator">></span>    <span class="token function">import</span> _ssl             <span class="token comment"># if we can't import it, let the error propagate</span>ImportError: libssl.so.1.1: cannot <span class="token function">open</span> shared object file: No such <span class="token function">file</span> or directory<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>原因是安装时引入了非系统原生版本的openssl依赖库，需要手动声明环境变量，或写入系统中</p><p><strong>方法一</strong></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 方法一，声明临时变量，怕影响线上服务推荐使用该方法</span><span class="token comment"># 包括后续执行python、引用库文件前都要提前声明</span><span class="token builtin class-name">export</span> <span class="token assign-left variable">LD_LIBRARY_PATH</span><span class="token operator">=</span>/usr/local/openssl-1.1.1/lib:<span class="token variable">$LD_LIBRARY_PATH</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p><strong>方法二</strong></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 方法二，永久声明变量</span><span class="token builtin class-name">echo</span> <span class="token string">"/usr/local/openssl-1.1.1/lib"</span> <span class="token operator">>></span> /etc/ld.so.conf.d/openssl-1.1.1-x86_64.confldconfig<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><ul><li>配置后建议检查并修复:</li></ul><p>TODO</p><h3 id="2-编译-Python-3-8-X-时出现-Could-not-import-runpy-module-报错"><a href="#2-编译-Python-3-8-X-时出现-Could-not-import-runpy-module-报错" class="headerlink" title="2.编译 Python-3.8.X 时出现 Could not import runpy module 报错"></a>2.编译 Python-3.8.X 时出现 <code>Could not import runpy module</code> 报错</h3><p><strong>异常现象</strong></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">Could not <span class="token function">import</span> runpy moduleTraceback <span class="token punctuation">(</span>most recent call last<span class="token punctuation">)</span>:  File <span class="token string">"/root/0tmp/Python-3.8.16/Lib/runpy.py"</span>, line <span class="token number">15</span>, <span class="token keyword">in</span> <span class="token operator">&lt;</span>module<span class="token operator">></span>    <span class="token function">import</span> importlib.util  File <span class="token string">"/root/0tmp/Python-3.8.16/Lib/importlib/util.py"</span>, line <span class="token number">14</span>, <span class="token keyword">in</span> <span class="token operator">&lt;</span>module<span class="token operator">></span>    from contextlib <span class="token function">import</span> contextmanager  File <span class="token string">"/root/0tmp/Python-3.8.16/Lib/contextlib.py"</span>, line <span class="token number">4</span>, <span class="token keyword">in</span> <span class="token operator">&lt;</span>module<span class="token operator">></span>    <span class="token function">import</span> _collections_abcSystemError: <span class="token operator">&lt;</span>built-in <span class="token keyword">function</span> compile<span class="token operator">></span> returned NULL without setting an errorgenerate-posix-vars failedmake<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>: *** <span class="token punctuation">[</span>pybuilddir.txt<span class="token punctuation">]</span> Error <span class="token number">1</span>make<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>: Leaving directory `/root/0tmp/Python-3.8.16'make: *** <span class="token punctuation">[</span>profile-opt<span class="token punctuation">]</span> Error <span class="token number">2</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><strong>原因</strong></p><ul><li>在低版本的gcc版本中带有 <code>--enable-optimizations</code> 参数时会出现上面问题</li><li>在 gcc 8.1.0 版本后修复此问题</li></ul><p><strong>解决方式</strong></p><ol><li><p>升级gcc至8.1.0【不推荐】</p></li><li><p><code>./configure</code> 参数中去掉 <code>--enable-optimizations</code></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> <span class="token variable">$PYTHON_PACKAGE_PATH</span><span class="token function">make</span> clean./configure --prefix<span class="token operator">=</span>/usr/local/python-3.8.16 --with-openssl<span class="token operator">=</span>/usr/local/openssl-1.1.1<span class="token function">make</span> <span class="token operator">&amp;&amp;</span> <span class="token function">make</span> <span class="token function">install</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></li></ol><blockquote><p>参考文档: <a href="https://blog.csdn.net/whatday/article/details/103903955">python 3.8.0 编译报错 Could not import runpy module 解决方案_whatday的博客-CSDN博客</a></p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;简介&quot;&gt;&lt;a href=&quot;#简介&quot; class=&quot;headerlink&quot; title=&quot;简介&quot;&gt;&lt;/a&gt;简介&lt;/h2&gt;&lt;p&gt;本文将以两种方式安装 Python3、PiP3及虚拟环境(virtualenv)&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;手动安装&quot;&gt;&lt;a hre</summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="python" scheme="https://nestealin.com/tags/python/"/>
    
    <category term="openssl" scheme="https://nestealin.com/tags/openssl/"/>
    
    <category term="virtualenv" scheme="https://nestealin.com/tags/virtualenv/"/>
    
    <category term="虚拟环境" scheme="https://nestealin.com/tags/%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83/"/>
    
  </entry>
  
  <entry>
    <title>CentOS系统升级GCC-8.2.0及GLIBC-2.31</title>
    <link href="https://nestealin.com/28244582/"/>
    <id>https://nestealin.com/28244582/</id>
    <published>2024-01-14T14:35:44.000Z</published>
    <updated>2024-08-04T06:56:53.349Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>glibc 是 GNU 发布的 libc 库，即 c 运行库。glibc 是 linux 系统中最底层的 api，几乎其它任何运行库都会依赖于glibc。glibc除了封装 linux 操作系统所提供的系统服务外，它本身也提供了许多其它一些必要功能服务的实现。由于 glibc 囊括了几乎所有的 UNIX 通行的标准，可以想见其内容包罗万象。而就像其他的 UNIX 系统一样，其内含的档案群分散于系统的树状目录结构中，像一个支架一般撑起整个操作系统。在 GNU/Linux 系统中，其 C 函数库发展史点出了GNU/Linux 演进的几个重要里程碑，用 glibc 作为系统的 C 函式库，是 GNU/Linux 演进的一个重要里程碑。</p><p>而当前在面对 nodejs 18 时就出现了 glibc 版本过旧的问题导致不得不对其进行升级。</p><hr><h2 id="特别注意"><a href="#特别注意" class="headerlink" title="特别注意"></a>特别注意</h2><ul><li><p>错误地升级 glibc 会导致系统工具失效甚至系统崩溃，</p><p>请谨慎操作</p></li><li><p>以下全部操作都是用 root 账户进行的</p></li><li><p>推荐全程在 screen 中运行，防止意外断开造成不可意料的后果</p></li></ul><blockquote><p>glibc 不可用会导致：bash 无法使用、yum/rpm 无法使用、无法解析名称空间、无法切换用户等，基本相当于系统不可用。同样的，如果有其他工具服务依赖 glibc，也会因此造成不可用。</p></blockquote><hr><h2 id="升级流程"><a href="#升级流程" class="headerlink" title="升级流程"></a>升级流程</h2><h3 id="1-安装Python-3-7-11"><a href="#1-安装Python-3-7-11" class="headerlink" title="1.安装Python-3.7.11"></a>1.安装Python-3.7.11</h3><blockquote><p> 本次安装基于<a href="https://nestealin.com/77134c2c/">一键脚本</a>实现 Python-3.7.11 版本安装。</p></blockquote><p>创建脚本文件</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">vim</span> py3_auto_install.sh<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>脚本内容</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token shebang important">#!/bin/bash</span><span class="token comment"># Author: nestealin</span><span class="token comment"># Created: 2022-12-11</span><span class="token comment"># Update: 2023-05-13 change openssl version from 1.1.1a to 1.1.1k</span><span class="token comment"># Update: 2023-09-23 promt Python and Openssl version to variables</span><span class="token assign-left variable">command</span><span class="token operator">=</span><span class="token variable">$1</span><span class="token assign-left variable">install_script_dir</span><span class="token operator">=</span><span class="token string">"$( cd "<span class="token variable"><span class="token variable">$(</span> <span class="token function">dirname</span> <span class="token string">"<span class="token variable">$0</span>"</span>  <span class="token variable">)</span></span>"</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">pwd</span>  <span class="token punctuation">)</span><span class="token string">"packages_dir="</span><span class="token variable">$install_script_dir</span>/packages<span class="token string">"PYTHON_VERSION="</span><span class="token number">3.7</span>.11<span class="token string">"PYTHON_MAIN_VERSION=<span class="token variable"><span class="token variable">$(</span><span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$PYTHON_VERSION</span>"</span> <span class="token operator">|</span> <span class="token function">cut</span> -d. -f1-2<span class="token variable">)</span></span>OPENSSL_VERSION="</span><span class="token number">1.1</span>.1k<span class="token string">"# EnvPreparefunction Setup_Install_Env() &#123;    yum install gcc zlib-devel make libffi-devel -y    yum install -y ca-certificates    [ ! -d <span class="token variable">$packages_dir</span> ] &amp;&amp; mkdir <span class="token variable">$packages_dir</span>    echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>32mpackages directory: <span class="token variable">$packages_dir</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">"&#125;# Download Packagesfunction Download_Python_Package() &#123;    cd <span class="token variable">$packages_dir</span>    tarball="</span>Python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>.tar.xz<span class="token string">"    if [ ! -f <span class="token variable">$tarball</span> ]; then        echo "</span>Downloading <span class="token variable">$tarball</span><span class="token string">"        wget https://www.python.org/ftp/python/<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/<span class="token variable">$tarball</span>    [ ! -f <span class="token variable">$tarball</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to download <span class="token variable">$tarball</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Download_Openssl_Packages() &#123;    cd <span class="token variable">$packages_dir</span>    tarball="</span>openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>.tar.gz<span class="token string">"    if [ ! -f <span class="token variable">$tarball</span> ]; then        echo "</span>Downloading <span class="token variable">$tarball</span><span class="token string">"        wget https://www.openssl.org/source/<span class="token variable">$tarball</span>        echo "</span>Downloading cacert.pem<span class="token string">"        wget http://curl.haxx.se/ca/cacert.pem    [ ! -f <span class="token variable">$tarball</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to download <span class="token variable">$tarball</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Download_Pip3_Package() &#123;    cd <span class="token variable">$packages_dir</span>    tarball="</span>ez_setup.py<span class="token string">"    if [ ! -f <span class="token variable">$tarball</span> ]; then        echo "</span>Downloading <span class="token variable">$tarball</span><span class="token string">"        wget https://bootstrap.pypa.io/<span class="token variable">$tarball</span> --no-check-certificate    [ ! -f <span class="token variable">$tarball</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to download <span class="token variable">$tarball</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Install_Openssl() &#123;    install_dir="</span>/usr/local/openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span><span class="token string">"    cd <span class="token variable">$packages_dir</span>    tarball="</span>openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>.tar.gz<span class="token string">"    tar -zxvf <span class="token variable">$tarball</span>    cd openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>    ./config --prefix=<span class="token variable">$install_dir</span> --openssldir=<span class="token variable">$install_dir</span>    make -j <span class="token variable"><span class="token variable">`</span><span class="token function">cat</span> /proc/cpuinfo <span class="token operator">|</span> <span class="token function">grep</span> -i name <span class="token operator">|</span> <span class="token function">wc</span> -l<span class="token variable">`</span></span> &amp;&amp; make install    if [ -d <span class="token variable">$install_dir</span> ]; then        mv <span class="token variable">$packages_dir</span>/cacert.pem /usr/local/openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>/cert.pem        echo "</span>/usr/local/openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>/lib<span class="token string">" > /etc/ld.so.conf.d/openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span>-x86_64.conf        ldconfig    [ ! -d <span class="token variable">$install_dir</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to <span class="token function">install</span> <span class="token variable">$install_dir</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Install_Python3() &#123;    install_dir="</span>/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span><span class="token string">"    openssl_dir="</span>/usr/local/openssl-<span class="token variable">$&#123;OPENSSL_VERSION&#125;</span><span class="token string">"    cd <span class="token variable">$packages_dir</span>    tar xvf Python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>.tar.xz    cd Python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>    ./configure --prefix=/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span> --enable-optimizations --with-openssl=<span class="token variable">$openssl_dir</span>    make -j <span class="token variable"><span class="token variable">`</span><span class="token function">cat</span> /proc/cpuinfo <span class="token operator">|</span> <span class="token function">grep</span> -i name <span class="token operator">|</span> <span class="token function">wc</span> -l<span class="token variable">`</span></span> &amp;&amp; make install    if [ -d <span class="token variable">$install_dir</span> ]; then        ln -s /usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span> /usr/local/python3        ln -s /usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/python<span class="token variable">$&#123;PYTHON_MAIN_VERSION&#125;</span> /usr/bin/python3        ln -s /usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/pip3 /usr/bin/pip3    [ ! -d <span class="token variable">$install_dir</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to <span class="token function">install</span> <span class="token variable">$install_dir</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Install_Pip3() &#123;    install_dir="</span>/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin<span class="token string">"    cd <span class="token variable">$packages_dir</span>    if [ -d <span class="token variable">$install_dir</span> ]; then        <span class="token variable">$install_dir</span>/python3 ez_setup.py    [ ! -d <span class="token variable">$install_dir</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to <span class="token function">install</span> <span class="token variable">$install_dir</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;function Install_Virtualenv() &#123;    install_dir="</span>/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin<span class="token string">"    if [ -d <span class="token variable">$install_dir</span> ]; then        <span class="token variable">$install_dir</span>/pip3 install virtualenv virtualenvwrapper    [ ! -d <span class="token variable">$install_dir</span> ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to <span class="token function">install</span> <span class="token variable">$install_dir</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi    virtualenvwrapper_script="</span>virtualenvwrapper.sh<span class="token string">"    if [ -f <span class="token variable">$install_dir</span>/virtualenvwrapper.sh ]; then        mkdir -p /data1/virtualpython/virtualenvs &amp;&amp; mkdir /data1/virtualpython/PyEnv        mkdir -p /data1/virtualpython_others/virtualenvs &amp;&amp; mkdir /data1/virtualpython_others/PyEnv        env=<span class="token variable"><span class="token variable">$(</span><span class="token function">cat</span> <span class="token operator">&lt;&lt;</span><span class="token string">EOF<span class="token bash punctuation"> <span class="token operator">>></span>~/.bashrc</span># 为非root用户提供if [ <span class="token variable"><span class="token variable">`</span><span class="token function">id</span> -u<span class="token variable">`</span></span> != '0' ]; then    export WORKON_HOME=/data1/virtualpython_others/virtualenvs    export PROJECT_HOME=/data1/virtualpython_others/PyEnvs    source /usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/virtualenvwrapper.shfi# 如果root用户添加如下:export WORKON_HOME=/data1/virtualpython/virtualenvsexport PROJECT_HOME=/data1/virtualpython/PyEnvsexport VIRTUALENVWRAPPER_PYTHON=/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/python<span class="token variable">$&#123;PYTHON_MAIN_VERSION&#125;</span>export VIRTUALENVWRAPPER_VIRTUALENV=/usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/virtualenvsource /usr/local/python-<span class="token variable">$&#123;PYTHON_VERSION&#125;</span>/bin/virtualenvwrapper.shEOF</span><span class="token variable">)</span></span>        <span class="token variable">$env</span>        source ~/.bashrc    [ ! -f <span class="token variable">$install_dir</span>/virtualenvwrapper.sh ] &amp;&amp; echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mfail to <span class="token function">install</span> virtualenvwrapper.sh<span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">" &amp;&amp; exit 1    fi&#125;# HELP，-p|--python-only 仅安装python，默认项 , -v|--with-virtualEnv 虚拟环境function help()&#123;    echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31musage: <span class="token variable">$0</span> Options: <span class="token punctuation">[</span>-d<span class="token operator">|</span>-p<span class="token punctuation">]</span> <span class="token punctuation">[</span>-v<span class="token punctuation">]</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">"    echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31mOPTIONS:<span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">"    echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31m    -d<span class="token operator">|</span>-p<span class="token operator">|</span>--python-only    <span class="token function">install</span> python only, Default option<span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">"    echo -e "</span><span class="token punctuation">\</span>033<span class="token punctuation">[</span>31m    -v<span class="token operator">|</span>--with-virtualEnv   instal python with virtualEnv<span class="token punctuation">\</span>033<span class="token punctuation">[</span>0m<span class="token string">"&#125;case <span class="token variable">$command</span> in    (-d|-p|--python-only)        Setup_Install_Env        Download_Openssl_Packages        Install_Openssl        Download_Python_Package        Download_Pip3_Package        Install_Python3        Install_Pip3        ;;    (-v|--with-virtualEnv)        Setup_Install_Env        Download_Openssl_Packages        Install_Openssl        Download_Python_Package        Download_Pip3_Package        Install_Python3        Install_Pip3        Install_Virtualenv        ;;    (-h|--help|help)        help        ;;    (*)        echo "</span>Error command"        <span class="token builtin class-name">help</span>        <span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token keyword">esac</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>执行安装</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">chmod</span> +x py3_auto_install.sh./py3_auto_install.sh -d<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h3 id="2-升级make-4-3"><a href="#2-升级make-4-3" class="headerlink" title="2.升级make-4.3"></a>2.升级make-4.3</h3><p>在<a href="https://mirrors.aliyun.com/gnu/make/">阿里云镜像</a>上找到想要升级的 make 版本，这里以 <code>4.3</code> 为例</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">wget</span> https://mirrors.aliyun.com/gnu/make/make-4.3.tar.gz <span class="token function">tar</span> -zxf make-4.3.tar.gz  <span class="token builtin class-name">cd</span> make-4.3/  <span class="token function">mkdir</span> build<span class="token builtin class-name">cd</span> build<span class="token punctuation">..</span>/configure --prefix<span class="token operator">=</span>/usr <span class="token operator">&amp;&amp;</span> <span class="token function">make</span> <span class="token operator">&amp;&amp;</span> <span class="token function">make</span> <span class="token function">install</span><span class="token function">make</span> -v<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="3-升级gcc-8-2-0"><a href="#3-升级gcc-8-2-0" class="headerlink" title="3.升级gcc-8.2.0"></a>3.升级gcc-8.2.0</h3><h4 id="安装依赖"><a href="#安装依赖" class="headerlink" title="安装依赖"></a>安装依赖</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 未安装c编译器报错</span><span class="token comment"># no acceptable C compiler found in $PATH</span>yum -y <span class="token function">install</span> bison <span class="token function">wget</span> <span class="token function">bzip2</span> gcc gcc-c++ glibc-headers<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h4 id="下载源码"><a href="#下载源码" class="headerlink" title="下载源码"></a>下载源码</h4><blockquote><ul><li>清华镜像站: <a href="https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/">Index of /gnu/gcc/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror</a></li><li>阿里云镜像站: <a href="https://mirrors.aliyun.com/gnu/gcc/">gnu-gcc安装包下载_开源镜像站-阿里云</a></li></ul></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 下载并解压  </span><span class="token function">wget</span> https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-8.2.0/gcc-8.2.0.tar.gz --no-check-certificate<span class="token function">tar</span> xf gcc-8.2.0.tar.gz<span class="token builtin class-name">cd</span> gcc-8.2.0<span class="token comment"># 下载gmp mpfr mpc等供编译需求的依赖项  </span>./contrib/download_prerequisites<span class="token function">mkdir</span> build<span class="token builtin class-name">cd</span> build<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="编译安装"><a href="#编译安装" class="headerlink" title="编译安装"></a>编译安装</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">..</span>/configure --prefix<span class="token operator">=</span>/usr/local/gcc-8.2.0 --enable-bootstrap --enable-checking<span class="token operator">=</span>release --enable-languages<span class="token operator">=</span>c,c++ --disable-multilib<span class="token function">make</span> -j <span class="token variable"><span class="token variable">`</span><span class="token function">cat</span> /proc/cpuinfo <span class="token operator">|</span> <span class="token function">grep</span> <span class="token string">"model name"</span> <span class="token operator">|</span> <span class="token function">wc</span> -l<span class="token variable">`</span></span><span class="token function">make</span> <span class="token function">install</span><span class="token function">sudo</span> <span class="token function">ln</span> -sv /usr/local/gcc-8.2.0/include/ /usr/include/gcc<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>编译参数释义:</p><ul><li><code>../configure</code>: 跨上一级文件夹编译器配置；</li><li><code>--prefix=/usr/local/gcc-8.2.0</code>:  指定安装目录；</li><li><code>--enable-checking=release</code>: 在编译器中执行内部一致性检查；</li><li><code>--enable-languages=c,c++</code>: 指定支持的语言；</li><li><code>--disable-multilib</code>: 禁止编译适用于多重架构体系的库，就是 X86 X64 兼容之类的；</li></ul><h4 id="更新环境"><a href="#更新环境" class="headerlink" title="更新环境"></a>更新环境</h4><p>移除旧版本</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yum -y remove gcc g++<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>配置新版本全局可用</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">ln</span> -s /usr/local/gcc-8.2.0/bin/gcc /usr/bin/gcc<span class="token function">ln</span> -s /usr/local/gcc-8.2.0/bin/g++ /usr/bin/g++<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>更新动态库</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 查看当前的动态库</span>strings /usr/local/gcc-8.2.0/lib64/libstdc++.so.6 <span class="token operator">|</span> <span class="token function">grep</span> CXXABI<span class="token comment"># 更改动态库</span><span class="token function">cp</span> /usr/local/gcc-8.2.0/lib64/libstdc++.so.6.0.25 /usr/lib64/ldconfig<span class="token comment"># 查看更新后的默认动态库</span>strings /usr/lib64/libstdc++.so.6 <span class="token operator">|</span> <span class="token function">grep</span> CXXABI<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="版本检查"><a href="#版本检查" class="headerlink" title="版本检查"></a>版本检查</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 查看安装库</span><span class="token builtin class-name">cd</span> /usr/lib64 <span class="token operator">&amp;&amp;</span> ll libstdc++*<span class="token comment"># 或者gcc --version</span>gcc -v<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><h3 id="4-升级glibc-2-31"><a href="#4-升级glibc-2-31" class="headerlink" title="4.升级glibc-2.31"></a>4.升级glibc-2.31</h3><h4 id="下载源码-1"><a href="#下载源码-1" class="headerlink" title="下载源码"></a>下载源码</h4><blockquote><ul><li>官方下载地址: <a href="http://ftp.gnu.org/gnu/glibc/">http://ftp.gnu.org/gnu/glibc/</a></li><li>阿里云镜像站: <a href="https://mirrors.aliyun.com/gnu/glibc/">gnu-glibc安装包下载_开源镜像站-阿里云</a></li></ul></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">wget</span> https://mirrors.aliyun.com/gnu/glibc/glibc-2.31.tar.gz<span class="token function">tar</span> -zxf glibc-2.31.tar.gz<span class="token builtin class-name">cd</span> glibc-2.31/<span class="token comment"># 检查依赖的，没有更新的都yum -y install一下，之前装过的就不 用了</span><span class="token function">cat</span> INSTALL <span class="token operator">|</span> <span class="token function">grep</span> -E <span class="token string">"or newer|or later"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><img src="/28244582/3208427840.png" class=""><h4 id="编译安装-1"><a href="#编译安装-1" class="headerlink" title="编译安装"></a>编译安装</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 修改 scripts/test-installation.pl 避免引发安装问题</span><span class="token function">sed</span> -e <span class="token string">'128s/.*/         \&amp;\&amp; \$name ne "nss_test1" \&amp;\&amp; \$name ne "nss_test2" \&amp;\&amp; \$name ne "libgcc_s") &#123;/'</span> scripts/test-installation.pl <span class="token operator">></span> tmpfile <span class="token operator">&amp;&amp;</span> <span class="token function">mv</span> tmpfile scripts/test-installation.pl<span class="token function">mkdir</span> build<span class="token builtin class-name">cd</span> build<span class="token punctuation">..</span>/configure --prefix<span class="token operator">=</span>/usr --disable-profile --enable-add-ons --with-headers<span class="token operator">=</span>/usr/include --with-binutils<span class="token operator">=</span>/usr/bin --disable-sanity-checks --disable-werror --enable-obsolete-nsl<span class="token function">make</span> -j <span class="token variable"><span class="token variable">`</span><span class="token function">cat</span> /proc/cpuinfo <span class="token operator">|</span> <span class="token function">grep</span> <span class="token string">"model name"</span> <span class="token operator">|</span> <span class="token function">wc</span> -l<span class="token variable">`</span></span><span class="token function">make</span> <span class="token function">install</span><span class="token function">make</span> localedata/install-locales -j <span class="token variable"><span class="token variable">`</span><span class="token function">cat</span> /proc/cpuinfo <span class="token operator">|</span> <span class="token function">grep</span> <span class="token string">"model name"</span> <span class="token operator">|</span> <span class="token function">wc</span> -l<span class="token variable">`</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>编译参数释义:</p><ul><li><code>../configure</code>: 跨上一级文件夹编译器配置；</li><li><code>--prefix=/usr</code>: 指定安装目录，<strong>切勿修改</strong>；</li><li><code>--disable-profile</code>: 关掉 profiling 信息相关的库文件编译；</li><li><code>--enable-add-ons</code>: 指示 glibc 使用附加的 NPTL 包作为线程库；</li><li><code>--with-headers=/usr/include</code>: 指示 glibc 按照这个目录中的内核头文件编译自己，从而精确的知道内核的特性以根据这些特性对自己进行最佳化编译；</li><li><code>--with-binutils=/usr/bin</code>: 保证在编译 glibc 时不会用错 Binutils；</li></ul><p>如果出现如下报错，可以忽略:</p><img src="/28244582/3888679133.png" class=""><h4 id="版本检查-1"><a href="#版本检查-1" class="headerlink" title="版本检查"></a>版本检查</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 检查 </span>ldd --version strings /lib64/libc.so.6 <span class="token operator">|</span> <span class="token function">grep</span> GLIBC<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>至此，如果没有出现其他报错，则代表升级完成。</p><hr><h2 id="可能出现的问题"><a href="#可能出现的问题" class="headerlink" title="可能出现的问题"></a>可能出现的问题</h2><h3 id="1-glibc在make-install时出现”cannot-find-lnss-test2”报错"><a href="#1-glibc在make-install时出现”cannot-find-lnss-test2”报错" class="headerlink" title="1.glibc在make install时出现”cannot find -lnss_test2”报错"></a>1.glibc在make install时出现”cannot find -lnss_test2”报错</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/bin/ld: cannot <span class="token function">find</span> -lnss_test2collect2: error: ld returned <span class="token number">1</span> <span class="token builtin class-name">exit</span> statusExecution of gcc failed<span class="token operator">!</span>The script has found some problems with your installation<span class="token operator">!</span>Please <span class="token builtin class-name">read</span> the FAQ and the README <span class="token function">file</span> and check the following:- Did you change the gcc specs <span class="token function">file</span> <span class="token punctuation">(</span>necessary after upgrading from  Linux libc5<span class="token punctuation">)</span>?- Are there any symbolic links of the form libXXX.so to old libraries?  Links like libm.so -<span class="token operator">></span> libm.so.5 <span class="token punctuation">(</span>where libm.so.5 is an old library<span class="token punctuation">)</span> are wrong,  libm.so should point to the newly installed glibc <span class="token function">file</span> - and there should be  only one such <span class="token function">link</span> <span class="token punctuation">(</span>check e.g. /lib and /usr/lib<span class="token punctuation">)</span>You should restart this script from your build directory after you<span class="token string">'vefixed all problems!Btw. the script doesn'</span>t work <span class="token keyword">if</span> you<span class="token string">'re installing GNU libc not as yourprimary library!make[1]: *** [Makefile:120: install] Error 1make[1]: Leaving directory '</span>/tmp/glibc-2.31'make: *** <span class="token punctuation">[</span>Makefile:12: install<span class="token punctuation">]</span> Error <span class="token number">2</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这个报错网上说可以忽略，但实际上在机器作为 jenkins slave 时会因为环境问题导致无法被 master 接管，在条件允许的情况下应该考虑解决这个错误。</p><p>当然，也可以在编译时想办法消除该告警，可以参考如下操作。</p><p><strong>解决方式</strong></p><p>在 glibc 源码目录下修改 <code>scripts/test-installation.pl</code> 文件约 128 行内容:</p><img src="/28244582/2782029399.png" class=""><p>参考如下操作:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /tmp/glibc-2.31<span class="token function">sed</span> -i <span class="token string">'128s/.*/         \&amp;\&amp; \$name ne "nss_test1" \&amp;\&amp; \$name ne "nss_test2" \&amp;\&amp; \$name ne "libgcc_s") &#123;/'</span> scripts/test-installation.pl<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>然后清理编译数据重新执行编译即可</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /tmp/glibc-2.31<span class="token function">rm</span> -rf build<span class="token function">mkdir</span> build<span class="token builtin class-name">cd</span> build<span class="token punctuation">..</span>/configure --prefix<span class="token operator">=</span>/usr --disable-profile --enable-add-ons --with-headers<span class="token operator">=</span>/usr/include --with-binutils<span class="token operator">=</span>/usr/bin --disable-sanity-checks --disable-werror --enable-obsolete-nsl<span class="token function">make</span> -j <span class="token variable"><span class="token variable">`</span><span class="token function">cat</span> /proc/cpuinfo <span class="token operator">|</span> <span class="token function">grep</span> <span class="token string">"model name"</span> <span class="token operator">|</span> <span class="token function">wc</span> -l<span class="token variable">`</span></span><span class="token function">make</span> <span class="token function">install</span><span class="token function">make</span> localedata/install-locales<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="2-系统登陆后出现”cannot-change-locale”"><a href="#2-系统登陆后出现”cannot-change-locale”" class="headerlink" title="2.系统登陆后出现”cannot change locale”"></a>2.系统登陆后出现”cannot change locale”</h3><p>在忽略”cannot find -lnss_test2”报错，升级完 glibc 以后，每次在登录操作系统后都会出现一个提示:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">-bash: warning: setlocale: <span class="token environment constant">LC_TIME</span><span class="token builtin class-name">:</span> cannot change locale <span class="token punctuation">(</span>en_US.UTF-8<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>以上提示可以有三种解决方式，推荐使用”<strong>解决方式3</strong>“。</p><p><strong>解决方式</strong></p><ul><li>（临时）<strong>解决方式1:</strong> 在区域文件中添加 LC_TIME，具体为编辑文件 <code>/etc/locale.conf</code>，命令：</li></ul><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">vi</span> /etc/locale.conf<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>内容为：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token assign-left variable"><span class="token environment constant">LANG</span></span><span class="token operator">=</span><span class="token string">"en_US.UTF-8"</span><span class="token assign-left variable"><span class="token environment constant">LC_TIME</span></span><span class="token operator">=</span><span class="token string">"POSIX"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>重新登陆后告警消失。</p><ul><li>（临时）<strong>解决方式2:</strong> 但是如果你已经删除了编译 glibc 的 build 目录或者不知道 build 的目录在哪里，请按照以下步骤:</li></ul><p>查看 libc.so.6 软连接指向</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">ls</span> -la /lib64/libc.so.6<span class="token comment"># >>> 终端输出</span>/lib64/libc.so.6 -<span class="token operator">></span> libc-2.14.so<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>查看 locale-archive 归档文件目录</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">strings /lib64/libc.so.6 <span class="token operator">|</span> <span class="token function">grep</span> locale-archive<span class="token comment"># >>> 终端输出</span>/usr/local/glibc-2.14/lib/locale/locale-archive<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><p>这个目录是在升级 libc 的时候 build 的目录</p><p>添加软链接</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">ls</span> -la /usr/local/glibc-2.14/lib/locale/locale-archive<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>发现文件并不存在，那么</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">ln</span> -s /usr/lib/locale/locale-archive /usr/local/glibc-2.14/lib/locale/locale-archive<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>重新执行 <code>locale</code> 已经正常了 ！</p><ul><li>（永久，<strong>推荐</strong>）<strong>解决方式3:</strong> 如果你还没有删除 glibc 的编译目录，则进入 glibc 的编译目录，也就是 build 目录执行 <code>make localedata/install-locales</code> 即可解决。</li></ul><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /tmp/glibc-2.31/build<span class="token function">make</span> localedata/install-locales -j <span class="token variable"><span class="token variable">`</span><span class="token function">cat</span> /proc/cpuinfo <span class="token operator">|</span> <span class="token function">grep</span> <span class="token string">"model name"</span> <span class="token operator">|</span> <span class="token function">wc</span> -l<span class="token variable">`</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><blockquote><p>注: 在主机没有重 CPU 任务负载时，建议增加 <code>-j</code> 参数提高编译效率，该步骤非常耗时。</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 省略过程输出</span><span class="token punctuation">..</span>.zh_CN.GB18030<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_CN.GBK<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_CN.UTF-8<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_CN.GB2312<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_HK.UTF-8<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_HK.BIG5-HKSCS<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_SG.UTF-8<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_SG.GBK<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_SG.GB2312<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_TW.EUC-TW<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_TW.UTF-8<span class="token punctuation">..</span>. <span class="token keyword">done</span>zh_TW.BIG5<span class="token punctuation">..</span>. <span class="token keyword">done</span>zu_ZA.UTF-8<span class="token punctuation">..</span>. <span class="token keyword">done</span>zu_ZA.ISO-8859-1<span class="token punctuation">..</span>. <span class="token keyword">done</span> <span class="token keyword">done</span> <span class="token keyword">done</span> <span class="token keyword">done</span> <span class="token keyword">done</span> <span class="token keyword">done</span> <span class="token keyword">done</span> <span class="token keyword">done</span>make<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span>: Leaving directory <span class="token string">'/tmp/glibc-2.31/localedata'</span>make<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>: Leaving directory <span class="token string">'/tmp/glibc-2.31'</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>待编译完成后即可解决该问题。</p><h3 id="3-升级glibc后系统命令无法使用"><a href="#3-升级glibc后系统命令无法使用" class="headerlink" title="3.升级glibc后系统命令无法使用"></a>3.升级glibc后系统命令无法使用</h3><p>如果 glibc 挂了会导致系统很多命令不可用</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">ls</span> ls: error <span class="token keyword">while</span> loading shared libraries: /lib64/libc.so.6: invalid ELF header<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>可以使用一个正常的 libc 进行恢复，注意此时 ln 命令已经不可用，但 sln 还可以使用</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">sln /lib64/libc-2.17.so /lib64/libc.so.6<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="4-glibc安装时出现动态库报错undefined-reference-to-39-nsl-default-nss-GLIBC-PRIVATE-39"><a href="#4-glibc安装时出现动态库报错undefined-reference-to-39-nsl-default-nss-GLIBC-PRIVATE-39" class="headerlink" title="4.glibc安装时出现动态库报错undefined reference to &#39;_nsl_default_nss@GLIBC_PRIVATE&#39;"></a>4.glibc安装时出现动态库报错<code>undefined reference to &#39;_nsl_default_nss@GLIBC_PRIVATE&#39;</code></h3><img src="/28244582/2961754226.png" class=""><p>这个看下<code>nis/Makefile</code></p><pre class="line-numbers language-c" data-language="c"><code class="language-c"><span class="token number">71</span> <span class="token function">ifeq</span> <span class="token punctuation">(</span>$<span class="token punctuation">(</span>build<span class="token operator">-</span>obsolete<span class="token operator">-</span>nsl<span class="token punctuation">)</span><span class="token punctuation">,</span>yes<span class="token punctuation">)</span><span class="token number">72</span> libnsl<span class="token operator">-</span>routines <span class="token operator">+=</span> nss<span class="token operator">-</span><span class="token keyword">default</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>在编译阶段 <code>configure</code> 增加 <code>--enable-obsolete-nsl</code> 参数即可</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># configure --help</span>  --enable-obsolete-nsl   build and <span class="token function">install</span> the obsolete libnsl   library and depending NSS modules<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>按照下面格式重新调整一下，重新编译就可以了</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">..</span>/configure --prefix<span class="token operator">=</span>/usr --disable-profile --enable-add-ons --with-headers<span class="token operator">=</span>/usr/include --with-binutils<span class="token operator">=</span>/usr/bin --disable-sanity-checks --disable-werror --enable-obsolete-nsl<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="5-升级glibc后yum执行无任何反应"><a href="#5-升级glibc后yum执行无任何反应" class="headerlink" title="5.升级glibc后yum执行无任何反应"></a>5.升级glibc后yum执行无任何反应</h3><p><strong>原因</strong></p><ul><li>可能是因为 rpm 数据库有问题导致卡死。</li></ul><p><strong>解决方式</strong></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">rm</span> -f /var/lib/rpm/__db.00*<span class="token function">rpm</span> --rebuilddbyum clean all<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><ul><li><code>rm -f /var/lib/rpm/__db.00*</code>: 删除 rpm 数据库文件；</li><li><code>rpm --rebuilddb</code>: 重建 rpm 数据库；</li><li><code>yum clean all</code>: 清理可能的缓存；</li></ul><p>然后你的 yum 应该能用了。</p><h3 id="6-遇到-lib64-libstdc-so-6-undefined-symbol-libiconv"><a href="#6-遇到-lib64-libstdc-so-6-undefined-symbol-libiconv" class="headerlink" title="6.遇到 lib64/libstdc++.so.6: undefined symbol: libiconv"></a>6.遇到 lib64/libstdc++.so.6: undefined symbol: libiconv</h3><p><strong>原因</strong></p><ul><li>libstdc++ 版本不匹配。</li></ul><p><strong>解决方式</strong></p><p>将 libstdc++ 的软连接改回老版本</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /lib64<span class="token function">rm</span> -rf libstdc++.so.6<span class="token function">ln</span> -s libstdc++.so.6.0.19 libstdc++.so.6<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h3 id="7-遇到-Error-usr-lib64-libstdc-so-6-version-CXXABI-1-3-39-not-found"><a href="#7-遇到-Error-usr-lib64-libstdc-so-6-version-CXXABI-1-3-39-not-found" class="headerlink" title="7.遇到 Error: /usr/lib64/libstdc++.so.6: version CXXABI_1.3.*&#39; not found"></a>7.遇到 <code>Error: /usr/lib64/libstdc++.so.6: version CXXABI_1.3.*&#39; not found</code></h3><p><strong>原因</strong></p><ul><li>libstdc++ 版本不够新</li></ul><p><strong>解决方式</strong></p><p>首先找到你的 <code>gcc</code> 源码编译文件夹，比如我的在 <code>/tmp/gcc-8.2.0</code>，然后将最新的 libstdc++.so.6 复制到 <code>/usr/lib64/</code></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /tmp/gcc-8.2.0/build/x86_64-pc-linux-gnu/libstdc++-v3/src/.libs<span class="token function">cp</span> libstdc++.so.6.0.25 /usr/lib64/<span class="token builtin class-name">cd</span> /usr/lib64<span class="token function">rm</span> -rf libstdc++.so.6<span class="token function">ln</span> -s libstdc++.so.6.0.25 libstdc++.so.6<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li><code>rm -rf libstdc++.so.6</code>: 删除老的软连接；</li><li><code>ln -s libstdc++.so.6.0.25 libstdc++.so.6</code>: 将新版本的 libstdc++.so.6.0.25 软连接到 libstdc++.so.6；</li></ul><hr><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://www.zoleet.com/details/308.html">centos7安装glibc-2.29_卓力特</a></p><p><a href="http://foreversmart.cc/cloud-native/-glibc-version-not-found/">Glibc 版本 not found</a></p><p><a href="https://www.xiehai.zone/2023-05-24-centos-gcc-glibc-upgrade.html">CentOs7升级gcc、glibc | PasseRR’s Blog</a></p><p><a href="https://blog.csdn.net/nineya_com/article/details/129417738">GCC编译环境升级部署_-lnss_test2-CSDN博客</a></p><p><a href="https://www.zhang21.cn/glibc-update/">CentOS7升级Glibc到2.28 - 风继续吹</a></p><p><a href="https://www.cnblogs.com/jasondayee/p/13403245.html">CentOS 升级libc后导致中文乱码 locale: Cannot set LC_CTYPE to default locale: No such file or directory - jasondayee - 博客园</a></p><p><a href="https://blog.csdn.net/esdhhh/article/details/121196317?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-121196317-blog-107057646.235%5Ev36%5Epc_relevant_default_base&spm=1001.2101.3001.4242.1&utm_relevant_index=1">centos7 glibc2.17升级到glibc2.28_glibc 2.28-CSDN博客</a></p><p><a href="https://garlicspace.com/2020/07/18/centos7-%E5%8D%87%E7%BA%A7-glibc-gcc">centos7 升级 glibc &amp;&amp; gcc – GarlicSpace</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;glibc 是 GNU 发布的 libc 库，即 c 运行库。glibc 是 linux 系统中最底层的 api，几乎其它任何运行库都会依赖</summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="linux" scheme="https://nestealin.com/tags/linux/"/>
    
    <category term="gcc" scheme="https://nestealin.com/tags/gcc/"/>
    
    <category term="glibc" scheme="https://nestealin.com/tags/glibc/"/>
    
    <category term="nodejs" scheme="https://nestealin.com/tags/nodejs/"/>
    
  </entry>
  
  <entry>
    <title>DPVS下引发的TCP-ConnectionReset问题排查</title>
    <link href="https://nestealin.com/5187581/"/>
    <id>https://nestealin.com/5187581/</id>
    <published>2023-12-03T05:13:21.000Z</published>
    <updated>2024-06-29T07:26:38.691Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>线上某个中台服务在资源创建时如果执行过程超长，就会触发服务端响应 <code>(&#39;Connection aborted.&#39;, ConnectionResetError(104, &#39;Connection reset by peer&#39;))</code>，导致资源创建失败。</p><img src="/5187581/670478540.png" class=""><hr><h2 id="排查过程"><a href="#排查过程" class="headerlink" title="排查过程"></a>排查过程</h2><h3 id="1、抓包分析"><a href="#1、抓包分析" class="headerlink" title="1、抓包分析"></a>1、抓包分析</h3><p>在出现这个问题之初是因为近期更了新版本才出现了这个问题，回滚旧版本后问题消失，因此本次的排查是在部署新版本后进行抓包分析。</p><p>基本信息:</p><ul><li><p>服务网关(enovy): </p><ul><li>10.20.30.93</li><li>10.20.30.237</li></ul></li><li><p>服务端:</p><ul><li>10.20.30.52</li></ul></li><li><p>中台服务:</p><ul><li>10.20.30.73</li></ul></li><li><p>请求链路:</p><ul><li>客户端（页面） -&gt; DPVS(外网) -&gt; Nginx -&gt; 中台服务 -&gt;  DPVS(内网) -&gt; Nginx -&gt; 服务网关 -&gt; 服务端</li></ul><p>即”用户”在中台页面发起资源创建后，会先经过外网 DPVS 透传至 Nginx 并转发至”中台服务”，再由”中台服务”发起 HTTP 请求向内网 DPVS 透传至 Nginx 并转发至”服务网关”，最终由”服务网关”路由到目标”服务端”发起资源创建。</p></li></ul><p>抓包详情如下:</p><p>当请求服务端正常接口时表现如下:</p><img src="/5187581/72960092.png" class=""><img src="/5187581/842664044.png" class=""><p>从上面几个完整连接过程来看，基本都在 HTTP 响应后，如果超过60s没有继续请求就会触发 <code>FIN，ACK</code> （结束连接）。</p><p>当请求服务端耗时超长的接口时表现如下:</p><img src="/5187581/1841684825.png" class=""><img src="/5187581/3823347606.png" class=""><p>而从上面的请求过程来看，当请求超过 90s 没有响应后，就会触发网关 <code>FIN，ACK</code> （结束连接），但因为此时服务端没有回应 <code>FIN，ACK</code> 进而导致网关在 45s 后触发 <code>RST</code> （强制中断）。</p><p>已知信息:</p><ul><li>服务端与服务网关的 TCP Keep-alive 是每 15s 一次，由服务端主动发起</li><li>HTTP正常响应后 60s 的闲置连接就会触发主动中断，由服务端主动发起</li><li>HTTP未能立即响应（响应超时）后 90s 就会触发异常中断，由网关主动发起</li></ul><p>如果同时拿”客户端”与”服务端”的抓包结果对比观察:</p><img src="/5187581/3792788722.png" class=""><p>可以看出客户端和服务端都是在 90s 分别收到来自网关和 DPVS 的 RST 报文，此时有理由<strong>怀疑网关或 DPVS 存在超时相关设置问题</strong>。</p><h3 id="2、检查enovy信息"><a href="#2、检查enovy信息" class="headerlink" title="2、检查enovy信息"></a>2、检查enovy信息</h3><ul><li><p>当前配置</p><pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token key atrule">admin</span><span class="token punctuation">:</span>  <span class="token key atrule">access_log_path</span><span class="token punctuation">:</span> /log/admin_access.log  <span class="token key atrule">address</span><span class="token punctuation">:</span>    <span class="token key atrule">socket_address</span><span class="token punctuation">:</span> <span class="token punctuation">&#123;</span> <span class="token key atrule">address</span><span class="token punctuation">:</span> 0.0.0.0<span class="token punctuation">,</span> <span class="token key atrule">port_value</span><span class="token punctuation">:</span> <span class="token number">1023</span> <span class="token punctuation">&#125;</span><span class="token key atrule">static_resources</span><span class="token punctuation">:</span>  <span class="token key atrule">listeners</span><span class="token punctuation">:</span>  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> listener_0    <span class="token key atrule">address</span><span class="token punctuation">:</span>      <span class="token key atrule">socket_address</span><span class="token punctuation">:</span> <span class="token punctuation">&#123;</span> <span class="token key atrule">address</span><span class="token punctuation">:</span> 0.0.0.0<span class="token punctuation">,</span> <span class="token key atrule">port_value</span><span class="token punctuation">:</span> <span class="token number">1024</span> <span class="token punctuation">&#125;</span>    <span class="token key atrule">filter_chains</span><span class="token punctuation">:</span>    <span class="token punctuation">-</span> <span class="token key atrule">filters</span><span class="token punctuation">:</span>      <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> envoy.http_connection_manager        <span class="token key atrule">config</span><span class="token punctuation">:</span>          <span class="token key atrule">upgrade_configs</span><span class="token punctuation">:</span>          <span class="token punctuation">-</span> <span class="token key atrule">upgrade_type</span><span class="token punctuation">:</span> websocket          <span class="token key atrule">stat_prefix</span><span class="token punctuation">:</span> ingress_http          <span class="token key atrule">idle_timeout</span><span class="token punctuation">:</span> 600s          <span class="token key atrule">codec_type</span><span class="token punctuation">:</span> AUTO          <span class="token key atrule">access_log</span><span class="token punctuation">:</span>          <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> envoy.file_access_log            <span class="token key atrule">config</span><span class="token punctuation">:</span>              <span class="token key atrule">path</span><span class="token punctuation">:</span> <span class="token string">"/log/info.log"</span>          <span class="token key atrule">route_config</span><span class="token punctuation">:</span>            <span class="token key atrule">name</span><span class="token punctuation">:</span> local_route            <span class="token comment"># 已忽略其余配置</span>            <span class="token key atrule">virtual_hosts</span><span class="token punctuation">:</span>            <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> web_service              <span class="token key atrule">domains</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span>              <span class="token comment"># 已忽略其余配置</span>              <span class="token key atrule">routes</span><span class="token punctuation">:</span>              <span class="token punctuation">-</span> <span class="token key atrule">match</span><span class="token punctuation">:</span>                  <span class="token key atrule">prefix</span><span class="token punctuation">:</span> <span class="token string">"/upstream_server/"</span>                <span class="token key atrule">route</span><span class="token punctuation">:</span>                  <span class="token key atrule">cluster</span><span class="token punctuation">:</span> upstream_server_apiserver_service                  <span class="token key atrule">timeout</span><span class="token punctuation">:</span> 6000s          <span class="token key atrule">http_filters</span><span class="token punctuation">:</span>          <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> envoy.router  <span class="token key atrule">clusters</span><span class="token punctuation">:</span>  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> upstream_server_apiserver_service    <span class="token key atrule">connect_timeout</span><span class="token punctuation">:</span> 5s    <span class="token key atrule">type</span><span class="token punctuation">:</span> LOGICAL_DNS    <span class="token key atrule">lb_policy</span><span class="token punctuation">:</span> ROUND_ROBIN    <span class="token key atrule">hosts</span><span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">&#123;</span> <span class="token key atrule">socket_address</span><span class="token punctuation">:</span> <span class="token punctuation">&#123;</span> <span class="token key atrule">address</span><span class="token punctuation">:</span> upstream_server<span class="token punctuation">-</span>apiserver<span class="token punctuation">-</span>service<span class="token punctuation">,</span> <span class="token key atrule">port_value</span><span class="token punctuation">:</span> <span class="token number">9113</span> <span class="token punctuation">&#125;</span> <span class="token punctuation">&#125;</span> <span class="token punctuation">]</span>    <span class="token key atrule">common_http_protocol_options</span><span class="token punctuation">:</span>      <span class="token key atrule">idle_timeout</span><span class="token punctuation">:</span> 180s<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><blockquote><p><a href="https://www.bookstack.cn/read/envoyproxy-1.10/144d336a80f65388.md">https://www.bookstack.cn/read/envoyproxy-1.10/144d336a80f65388.md</a></p></blockquote><img src="/5187581/957140494.png" class="" title="img"><p>排查几项超时参数都是远大于 90s，与本次问题无关，<strong>初步排除网关问题</strong>。</p><h3 id="3、本地复现"><a href="#3、本地复现" class="headerlink" title="3、本地复现"></a>3、本地复现</h3><p>在初步排除服务网关后，于是尝试在本地通过模拟请求的方式复现并排查问题触发时机，本次分别使用 curl 与 Python requests 进行对比测试。（因为线上使用的是 Python requests）</p><p><strong>requests版本:</strong></p><ul><li>线上:<ul><li>2.22.0</li></ul></li><li>本地:<ul><li>2.23.0</li><li>2.31.0 （测试时最新版: <a href="https://pypi.org/project/requests/#history%EF%BC%89">https://pypi.org/project/requests/#history）</a></li></ul></li></ul><blockquote><p>省略测试过程。</p></blockquote><p><strong>测试结果:</strong></p><ul><li><p>在 curl 测试中，无论域名请求 DPVS VIP 还是直接请求 Nginx，都无法复现请求超过 90s 后因为 RST 原因导致连接异常断开的现象。测试结果均为 300s 服务端未响应而触发的客户端请求超时(408 Rquest Timeout)，但这种连接中断不是因为 Nginx 响应 RST 而触发异常断开，而是正常的 “TCP挥手” 流程。</p><img src="/5187581/171118219.png" class=""></li></ul><ul><li><p>在 Python requests 测试中，当客户端直接向 Nginx 请求时，不会出现 <code>Connection Reset</code> 的问题，与 curl 请求结果一致；但如果目标地址为 DPVS VIP 时就会在 90s 时复现 RST 问题。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">requests.exceptions.ConnectionError: <span class="token punctuation">(</span><span class="token string">'Connection aborted.'</span>, ConnectionResetError<span class="token punctuation">(</span><span class="token number">104</span>, <span class="token string">'Connection reset by peer'</span><span class="token punctuation">))</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li></ul><blockquote><p>问题得到复现，抓包过程与线上一致不再重复贴图。</p></blockquote><h3 id="4、尝试解决"><a href="#4、尝试解决" class="headerlink" title="4、尝试解决"></a>4、尝试解决</h3><p>通过查找相似问题的 <a href="https://github.com/psf/requests/issues/4937#issuecomment-788899804">issue</a> 可以看出，在代码前增加如下片段可以解决这类问题，因此对请求样例头部添加相关代码，然后再次进行请求验证:</p><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token comment">#!/usr/bin/python3</span><span class="token comment"># -*- coding: UTF-8 -*-</span><span class="token keyword">import</span> requests<span class="token keyword">import</span> json<span class="token keyword">import</span> time<span class="token keyword">import</span> socket<span class="token keyword">from</span> urllib3<span class="token punctuation">.</span>connection <span class="token keyword">import</span> HTTPConnectionHTTPConnection<span class="token punctuation">.</span>default_socket_options <span class="token operator">=</span> <span class="token punctuation">(</span>    HTTPConnection<span class="token punctuation">.</span>default_socket_options <span class="token operator">+</span> <span class="token punctuation">[</span>        <span class="token punctuation">(</span>socket<span class="token punctuation">.</span>SOL_SOCKET<span class="token punctuation">,</span> socket<span class="token punctuation">.</span>SO_KEEPALIVE<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span>        <span class="token punctuation">(</span>socket<span class="token punctuation">.</span>SOL_TCP<span class="token punctuation">,</span> socket<span class="token punctuation">.</span>TCP_KEEPIDLE<span class="token punctuation">,</span> <span class="token number">45</span><span class="token punctuation">)</span><span class="token punctuation">,</span>        <span class="token punctuation">(</span>socket<span class="token punctuation">.</span>SOL_TCP<span class="token punctuation">,</span> socket<span class="token punctuation">.</span>TCP_KEEPINTVL<span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">,</span>        <span class="token punctuation">(</span>socket<span class="token punctuation">.</span>SOL_TCP<span class="token punctuation">,</span> socket<span class="token punctuation">.</span>TCP_KEEPCNT<span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">)</span>    <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token comment"># 省略业务代码</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token keyword">print</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>strftime<span class="token punctuation">(</span><span class="token string">"%Y-%m-%d %H:%M:%S"</span><span class="token punctuation">,</span> time<span class="token punctuation">.</span>localtime<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>response <span class="token operator">=</span> requests<span class="token punctuation">.</span>request<span class="token punctuation">(</span><span class="token string">"POST"</span><span class="token punctuation">,</span> url<span class="token punctuation">,</span> headers<span class="token operator">=</span>headers<span class="token punctuation">,</span> data<span class="token operator">=</span>payload<span class="token punctuation">,</span> timeout<span class="token operator">=</span><span class="token number">360</span><span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>text<span class="token punctuation">)</span><span class="token keyword">print</span><span class="token punctuation">(</span>time<span class="token punctuation">.</span>strftime<span class="token punctuation">(</span><span class="token string">"%Y-%m-%d %H:%M:%S"</span><span class="token punctuation">,</span> time<span class="token punctuation">.</span>localtime<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>客户端输出:</p><pre class="line-numbers language-Bash" data-language="Bash"><code class="language-Bash">2023-10-20 10:37:56stream timeout2023-10-20 10:42:56<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>从结果可以看出，即便还是请求 DPVS VIP，但在添加了相关代码后不再出现 RST 问题，也能够像 curl 一样超过 90s 最终触发客户端请求超时(408 Rquest Timeout)。</p><p>至此，已经可以确认问题是由 DPVS 产生的，并且有了临时的解决方式，但仍不知根本原因。</p><hr><h2 id="模拟环境"><a href="#模拟环境" class="headerlink" title="模拟环境"></a>模拟环境</h2><p>为了进一步验证其根本原因，即为何添加了相关代码后能够不会复现问题，并且为什么只有请求 DPVS VIP 时才会出现这个问题，由此进行了模拟环境测试。</p><h3 id="0-基本信息"><a href="#0-基本信息" class="headerlink" title="0. 基本信息"></a>0. 基本信息</h3><ul><li>客户端: 192.168.7.91</li><li>Nginx: 192.168.7.27</li><li>服务端: 192.168.7.92</li><li>DPVS: 192.168.7.82</li><li>VIP: 192.168.7.182</li><li>LIP: 192.168.7.185</li></ul><blockquote><p>注:</p><ul><li>VIP: 作为DPVS的高可用IP，用于接收客户端请求的入口IP</li><li>LIP: 作为DPVS的转发IP，用于转发流量时向后端(RS)通信用的Local IP，而不是用DPVS IP向后端建连</li></ul></blockquote><img src="/5187581/4258036552.png" class=""><h3 id="1-客户端请求VIP-requests下表现"><a href="#1-客户端请求VIP-requests下表现" class="headerlink" title="1. 客户端请求VIP-requests下表现"></a>1. 客户端请求VIP-requests下表现</h3><p>客户端使用 Python requests 方式请求测试域名，分别在观察几个网络阶段的表现。</p><p><strong>客户端侧抓包</strong></p><ul><li><p>客户端 -&gt; DPVS</p><img src="/5187581/294694598.png" class=""></li><li><p>客户端输出</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">Traceback <span class="token punctuation">(</span>most recent call last<span class="token punctuation">)</span>:  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">803</span>, <span class="token keyword">in</span> urlopen    **response_kw,  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">537</span>, <span class="token keyword">in</span> _make_request    response <span class="token operator">=</span> conn.getresponse<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connection.py"</span>, line <span class="token number">461</span>, <span class="token keyword">in</span> getresponse    httplib_response <span class="token operator">=</span> super<span class="token punctuation">(</span><span class="token punctuation">)</span>.getresponse<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/http/client.py"</span>, line <span class="token number">1373</span>, <span class="token keyword">in</span> getresponse    response.begin<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/http/client.py"</span>, line <span class="token number">319</span>, <span class="token keyword">in</span> begin    version, status, reason <span class="token operator">=</span> self._read_status<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/http/client.py"</span>, line <span class="token number">280</span>, <span class="token keyword">in</span> _read_status    line <span class="token operator">=</span> str<span class="token punctuation">(</span>self.fp.readline<span class="token punctuation">(</span>_MAXLINE + <span class="token number">1</span><span class="token punctuation">)</span>, <span class="token string">"iso-8859-1"</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/socket.py"</span>, line <span class="token number">589</span>, <span class="token keyword">in</span> readinto    <span class="token builtin class-name">return</span> self._sock.recv_into<span class="token punctuation">(</span>b<span class="token punctuation">)</span>ConnectionResetError: <span class="token punctuation">[</span>Errno <span class="token number">104</span><span class="token punctuation">]</span> Connection reset by peerDuring handling of the above exception, another exception occurred:Traceback <span class="token punctuation">(</span>most recent call last<span class="token punctuation">)</span>:  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/requests/adapters.py"</span>, line <span class="token number">497</span>, <span class="token keyword">in</span> send    <span class="token assign-left variable">chunked</span><span class="token operator">=</span>chunked,  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">846</span>, <span class="token keyword">in</span> urlopen    method, url, <span class="token assign-left variable">error</span><span class="token operator">=</span>new_e, <span class="token assign-left variable">_pool</span><span class="token operator">=</span>self, <span class="token assign-left variable">_stacktrace</span><span class="token operator">=</span>sys.exc_info<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/util/retry.py"</span>, line <span class="token number">470</span>, <span class="token keyword">in</span> increment    raise reraise<span class="token punctuation">(</span>type<span class="token punctuation">(</span>error<span class="token punctuation">)</span>, error, _stacktrace<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/util/util.py"</span>, line <span class="token number">38</span>, <span class="token keyword">in</span> reraise    raise value.with_traceback<span class="token punctuation">(</span>tb<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">803</span>, <span class="token keyword">in</span> urlopen    **response_kw,  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">537</span>, <span class="token keyword">in</span> _make_request    response <span class="token operator">=</span> conn.getresponse<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connection.py"</span>, line <span class="token number">461</span>, <span class="token keyword">in</span> getresponse    httplib_response <span class="token operator">=</span> super<span class="token punctuation">(</span><span class="token punctuation">)</span>.getresponse<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/http/client.py"</span>, line <span class="token number">1373</span>, <span class="token keyword">in</span> getresponse    response.begin<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/http/client.py"</span>, line <span class="token number">319</span>, <span class="token keyword">in</span> begin    version, status, reason <span class="token operator">=</span> self._read_status<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/http/client.py"</span>, line <span class="token number">280</span>, <span class="token keyword">in</span> _read_status    line <span class="token operator">=</span> str<span class="token punctuation">(</span>self.fp.readline<span class="token punctuation">(</span>_MAXLINE + <span class="token number">1</span><span class="token punctuation">)</span>, <span class="token string">"iso-8859-1"</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/socket.py"</span>, line <span class="token number">589</span>, <span class="token keyword">in</span> readinto    <span class="token builtin class-name">return</span> self._sock.recv_into<span class="token punctuation">(</span>b<span class="token punctuation">)</span>urllib3.exceptions.ProtocolError: <span class="token punctuation">(</span><span class="token string">'Connection aborted.'</span>, ConnectionResetError<span class="token punctuation">(</span><span class="token number">104</span>, <span class="token string">'Connection reset by peer'</span><span class="token punctuation">))</span>During handling of the above exception, another exception occurred:Traceback <span class="token punctuation">(</span>most recent call last<span class="token punctuation">)</span>:  File <span class="token string">"clientTest.py"</span>, line <span class="token number">45</span>, <span class="token keyword">in</span> <span class="token operator">&lt;</span>module<span class="token operator">></span>    response <span class="token operator">=</span> requests.request<span class="token punctuation">(</span><span class="token string">"POST"</span>, url, <span class="token assign-left variable">headers</span><span class="token operator">=</span>headers, <span class="token assign-left variable">data</span><span class="token operator">=</span>payload, <span class="token assign-left variable">stream</span><span class="token operator">=</span>True, <span class="token assign-left variable">timeout</span><span class="token operator">=</span><span class="token number">360</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/requests/api.py"</span>, line <span class="token number">59</span>, <span class="token keyword">in</span> request    <span class="token builtin class-name">return</span> session.request<span class="token punctuation">(</span>method<span class="token operator">=</span>method, <span class="token assign-left variable">url</span><span class="token operator">=</span>url, **kwargs<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/requests/sessions.py"</span>, line <span class="token number">589</span>, <span class="token keyword">in</span> request    resp <span class="token operator">=</span> self.send<span class="token punctuation">(</span>prep, **send_kwargs<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/requests/sessions.py"</span>, line <span class="token number">703</span>, <span class="token keyword">in</span> send    r <span class="token operator">=</span> adapter.send<span class="token punctuation">(</span>request, **kwargs<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/requests/adapters.py"</span>, line <span class="token number">501</span>, <span class="token keyword">in</span> send    raise ConnectionError<span class="token punctuation">(</span>err, <span class="token assign-left variable">request</span><span class="token operator">=</span>request<span class="token punctuation">)</span>requests.exceptions.ConnectionError: <span class="token punctuation">(</span><span class="token string">'Connection aborted.'</span>, ConnectionResetError<span class="token punctuation">(</span><span class="token number">104</span>, <span class="token string">'Connection reset by peer'</span><span class="token punctuation">))</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><p><strong>DPVS侧抓包</strong></p><ul><li><p>客户端 -&gt; DPVS</p><img src="/5187581/1348001388.png" class=""></li><li><p>DPVS -&gt; Nginx</p><img src="/5187581/3409751771.png" class=""></li></ul><p><strong>Nginx侧抓包</strong></p><ul><li><p>DPVS -&gt; Nginx</p><img src="/5187581/107143447.png" class=""></li><li><p>请求日志:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token number">192.168</span>.7.185:1026 <span class="token number">80</span> - <span class="token punctuation">[</span><span class="token number">21</span>/Oct/2023:15:20:40 +0800<span class="token punctuation">]</span> <span class="token string">"POST /test HTTP/1.1"</span> <span class="token number">499</span> <span class="token number">0</span> <span class="token number">434</span> <span class="token string">"-"</span> <span class="token string">"python-requests/2.27.1"</span> - <span class="token number">192.168</span>.7.92:51020 - <span class="token number">90.817</span> <span class="token number">90.818</span> opstest.nestealin.com <span class="token string">"- - -"</span> <span class="token string">"192.168.7.185"</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li></ul><p>从上述抓包表现可以看出，在客户端请求后 90s 左右，DPVS分别向客户端、服务端发送了 RST 致使连接中断。</p><h3 id="2-客户端请求VIP-curl下表现"><a href="#2-客户端请求VIP-curl下表现" class="headerlink" title="2. 客户端请求VIP-curl下表现"></a>2. 客户端请求VIP-curl下表现</h3><p><strong>客户端侧抓包</strong></p><img src="/5187581/90426750.png" class=""><p><strong>DPVS侧抓包</strong></p><ul><li><p>客户端 -&gt; DPVS</p><img src="/5187581/1388293459.png" class=""></li><li><p>DPVS -&gt; Nginx</p><img src="/5187581/3950568121.png" class=""></li></ul><p><strong>Nginx侧抓包</strong></p><img src="/5187581/1095386410.png" class=""><p>将本次测试请求的抓包过程与前一次使用 requests 方法对比可以发现，<strong>客户端在使用 curl 请求的第 60s 时会发送一次 TCP Keep-Alive 请求，而客户端使用 Python requests 方法请求时全程没有发起 TCP Keep-Alive 请求</strong>；而这种”请求保活”的方式也是客户端在使用 curl 时连接过程得以延续的关键。</p><h3 id="3-客户端直接请求Nginx"><a href="#3-客户端直接请求Nginx" class="headerlink" title="3. 客户端直接请求Nginx"></a>3. 客户端直接请求Nginx</h3><p>在客户端下继续使用 requests 向 Nginx 直接发起请求。</p><p><strong>客户端侧抓包</strong></p><img src="/5187581/440144560.png" class=""><p><strong>Nginx侧抓包</strong></p><img src="/5187581/2051935576.png" class=""><p>当客户端直接向 Nginx 请求时，请求过程仍旧没有发送，但不会触发 <code>Connection Reset</code> 能够完成 HTTP 请求。</p><p>此时可以确认本次”异常断开”的行为是与 DPVS 有直接关系。</p><h3 id="4-客户端增加Keep-Alive"><a href="#4-客户端增加Keep-Alive" class="headerlink" title="4. 客户端增加Keep-Alive"></a>4. 客户端增加Keep-Alive</h3><p>在客户端下继续使用 requests 向 DPVS VIP 发起请求，但本次在代码中添加”临时方法”，实现定期发送 Keep-Alive 请求，并抓取请求过程。</p><p><strong>客户端侧抓包</strong></p><img src="/5187581/1454181997.png" class=""><p><strong>DPVS侧抓包</strong></p><ul><li><p>客户端 -&gt; DPVS</p><img src="/5187581/1200095701.png" class=""></li><li><p>DPVS -&gt; Nginx</p><img src="/5187581/2067439639.png" class=""></li></ul><p><strong>Nginx侧抓包</strong></p><img src="/5187581/2686416114.png" class=""><p>可见，在客户端开启 Keep-Alive 后，DPVS 也不会主动终止 TCP 连接，进而确认本次异常与 DPVS 的连接管理有关。（缩小问题范围）</p><h3 id="5-源码分析"><a href="#5-源码分析" class="headerlink" title="5. 源码分析"></a>5. 源码分析</h3><p>通过<a href="https://www.jianshu.com/p/f38cd8c99f70">源码分析</a>可以大致看出在 DPVS 的 TCP 连接管理中是有一个定时器来实现超时处理的，再结合 <a href="https://github.com/iqiyi/dpvs/blob/master/src/ipvs/ip_vs_proto_tcp.c#L60">dpvs/src/ipvs/ip_vs_proto_tcp.c at master · iqiyi/dpvs</a> 初始化方法可以看出”监听状态”的超时参数是由 <code>/etc/dpvs.conf</code> 中的 <code>ipvs_defs.tcp.timeout.established</code> 定义的。</p><p>接下来为了进一步验证配置有效性，通过修改相关文件增加日志输出:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 以下均为编辑tcp_send_rst方法</span><span class="token function">vi</span> src/ipvs/ip_vs_proto_tcp.c +999    <span class="token keyword">if</span> <span class="token punctuation">(</span>conn-<span class="token operator">></span>state <span class="token operator">!=</span> DPVS_TCP_S_ESTABLISHED<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>        RTE_LOG<span class="token punctuation">(</span>WARNING, IPVS, <span class="token string">"%s: only RST in ESTABLISHED.<span class="token entity" title="\n">\n</span>"</span>, __func__<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token builtin class-name">return</span> EDPVS_OK<span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    // 方法末行增加    RTE_LOG<span class="token punctuation">(</span>WARNING, IPVS, <span class="token string">"%s: IDLE ESTABLISHED RST Sended.<span class="token entity" title="\n">\n</span>"</span>, __func__<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token builtin class-name">return</span> EDPVS_OK<span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>重新编译并重启DPVS</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /usr/local/dpvs-1.9.0<span class="token builtin class-name">export</span> <span class="token assign-left variable">DPVS_PATH</span><span class="token operator">=</span>/usr/local/dpvs-1.9.0<span class="token builtin class-name">export</span> <span class="token assign-left variable">PKG_CONFIG_PATH</span><span class="token operator">=</span><span class="token variable">$DPVS_PATH</span>/dpdk/dpdklib/lib64/pkgconfig:/usr/lib64/pkgconfig<span class="token builtin class-name">export</span> <span class="token assign-left variable">LIBDPDKPC_PATH</span><span class="token operator">=</span><span class="token variable">$DPVS_PATH</span>/dpdk/dpdklib/lib64/pkgconfig/libdpdk.pc<span class="token function">make</span> -j <span class="token number">20</span><span class="token function">make</span> <span class="token function">install</span> -j <span class="token number">20</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>待编译通过后重启 DPVS 及 Keepalived 。</p><h3 id="6-效果验证"><a href="#6-效果验证" class="headerlink" title="6. 效果验证"></a>6. 效果验证</h3><p>客户端直接请求VIP</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">curl</span> <span class="token number">192.168</span>.7.182 -v<span class="token comment"># 因为没有携带域名请求不会命中测试配置，会立刻得到Nginx响应，连接终止</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><ul><li><p>DPVS日志</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 待请求完成后约7s出现如下日志</span>tailf /data/logs/dpvs/dpvs.logIPVS: tcp_send_rst: only RST <span class="token keyword">in</span> ESTABLISHED.IPVS: tcp_send_rst: only RST <span class="token keyword">in</span> ESTABLISHED.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></li></ul><blockquote><p>7s后进行连接回收是受限于 <code>ipvs_defs.tcp.timeout.time_wait</code> 参数，默认值为7</p></blockquote><p>此处验证日志输出有效。</p><p>接下来开始请求测试域名</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">python3 clientTest.py<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><ul><li><p>DPVS日志</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 待请求发起后90s出现如下日志</span>tailf /data/logs/dpvs/dpvs.logIPVS: tcp_send_rst: IDLE ESTABLISHED RST Sended.IPVS: tcp_send_rst: IDLE ESTABLISHED RST Sended.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><ul><li>代表没能正常断开连接，而是让 DPVS 双向删除连接状态</li></ul></li><li><p>Nginx日志</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token number">192.168</span>.7.185:1046 <span class="token number">80</span> - <span class="token punctuation">[</span><span class="token number">23</span>/Oct/2023:14:08:13 +0800<span class="token punctuation">]</span> <span class="token string">"POST /test HTTP/1.1"</span> <span class="token number">499</span> <span class="token number">0</span> <span class="token number">434</span> <span class="token string">"-"</span> <span class="token string">"python-requests/2.31.0"</span> - <span class="token number">192.168</span>.7.92:51020 - <span class="token number">90.640</span> <span class="token number">90.641</span> opstest.nestealin.com <span class="token string">"- - -"</span> <span class="token string">"192.168.7.185"</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><ul><li>此时客户端触发 <code>Connection Reset</code> 异常复现问题，中断的时长为 90s</li></ul></li></ul><p>进而修改 DPVS 配置，延长 TCP 超时时间</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">vim</span> /etc/dpvs.conf<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>修改内容如下:</p><blockquote><p>仅展示关键配置</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token operator">!</span> ipvs configipvs_defs <span class="token punctuation">&#123;</span>    <span class="token punctuation">..</span>.    tcp <span class="token punctuation">&#123;</span>        <span class="token operator">!</span> defence_tcp_drop        <span class="token function">timeout</span> <span class="token punctuation">&#123;</span>            <span class="token punctuation">..</span>.            established <span class="token number">90</span>            established <span class="token number">100</span>            <span class="token punctuation">..</span>.        <span class="token punctuation">&#125;</span>    <span class="token punctuation">&#125;</span>    <span class="token punctuation">..</span>.<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>对 IPVS 中 TCP established 状态的空闲连接超时设置从 90s 调高至 100s</p><p>并对 DPVS 执行配置重加载</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">kill</span> -SIGHUP <span class="token variable">$&#123;DPVS_PID&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>客户端重新发起测试请求</p><ul><li><p>DPVS日志</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">tailf /data/logs/dpvs/dpvs.log<span class="token comment"># Reload日志简要输出，能够确认配置加载生效</span>CFG_FILE: load dpvs configuation <span class="token function">file</span> at <span class="token number">2023</span>/10/23 <span class="token number">14</span>:40:11 MondayIPVS: tcp_timeout_established <span class="token operator">=</span> <span class="token number">100</span><span class="token comment"># 新的测试请求过程中，依旧因为"空闲"连接导致DPVS主动断开</span>IPVS: tcp_send_rst: IDLE ESTABLISHED RST Sended.IPVS: tcp_send_rst: IDLE ESTABLISHED RST Sended.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre></li><li><p>Nginx日志</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token number">192.168</span>.7.185:1048 <span class="token number">80</span> - <span class="token punctuation">[</span><span class="token number">23</span>/Oct/2023:14:28:24 +0800<span class="token punctuation">]</span> <span class="token string">"POST /test HTTP/1.1"</span> <span class="token number">499</span> <span class="token number">0</span> <span class="token number">434</span> <span class="token string">"-"</span> <span class="token string">"python-requests/2.31.0"</span> - <span class="token number">192.168</span>.7.92:51020 - <span class="token number">101.077</span> <span class="token number">101.076</span> opstest.nestealin.com <span class="token string">"- - -"</span> <span class="token string">"192.168.7.185"</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre></li></ul><p>虽然本次客户端仍会触发 <code>Connection Reset</code> 异常，但中断的时长已经变为 101s，基本与 DPVS 配置调整的预期一致，证明配置有效。</p><h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><ul><li>curl 请求比 Python 的 requests 方法在客户端请求第 60s 时多发送了一次 TCP Keep-Alive 请求，让 TCP 连接保活、请求过程得以继续</li><li>DPVS 对 TCP 连接有设置定时器，对各种阶段的连接进行单独处理，最终由 <code>/etc/dpvs.conf</code> 配置中的 <code>ipvs_defs.tcp.timeout</code> 相关参数独立控制</li></ul><hr><h2 id="关于408问题"><a href="#关于408问题" class="headerlink" title="关于408问题"></a>关于408问题</h2><p>在解决客户端 <code>Connection Reset</code> 问题之后，继续出现了下方的 <code>Read timed out</code> 问题:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token number">2023</span>-10-24 <span class="token number">13</span>:02:49Traceback <span class="token punctuation">(</span>most recent call last<span class="token punctuation">)</span>:  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">426</span>, <span class="token keyword">in</span> _make_request    six.raise_from<span class="token punctuation">(</span>e, None<span class="token punctuation">)</span>  File <span class="token string">"&lt;string>"</span>, line <span class="token number">3</span>, <span class="token keyword">in</span> raise_from  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">421</span>, <span class="token keyword">in</span> _make_request    httplib_response <span class="token operator">=</span> conn.getresponse<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/http/client.py"</span>, line <span class="token number">1373</span>, <span class="token keyword">in</span> getresponse    response.begin<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/http/client.py"</span>, line <span class="token number">319</span>, <span class="token keyword">in</span> begin    version, status, reason <span class="token operator">=</span> self._read_status<span class="token punctuation">(</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/http/client.py"</span>, line <span class="token number">280</span>, <span class="token keyword">in</span> _read_status    line <span class="token operator">=</span> str<span class="token punctuation">(</span>self.fp.readline<span class="token punctuation">(</span>_MAXLINE + <span class="token number">1</span><span class="token punctuation">)</span>, <span class="token string">"iso-8859-1"</span><span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/socket.py"</span>, line <span class="token number">589</span>, <span class="token keyword">in</span> readinto    <span class="token builtin class-name">return</span> self._sock.recv_into<span class="token punctuation">(</span>b<span class="token punctuation">)</span>TimeoutError: <span class="token punctuation">[</span>Errno <span class="token number">110</span><span class="token punctuation">]</span> Connection timed outDuring handling of the above exception, another exception occurred:Traceback <span class="token punctuation">(</span>most recent call last<span class="token punctuation">)</span>:  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/requests/adapters.py"</span>, line <span class="token number">449</span>, <span class="token keyword">in</span> send    <span class="token assign-left variable">timeout</span><span class="token operator">=</span>timeout  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">727</span>, <span class="token keyword">in</span> urlopen    method, url, <span class="token assign-left variable">error</span><span class="token operator">=</span>e, <span class="token assign-left variable">_pool</span><span class="token operator">=</span>self, <span class="token assign-left variable">_stacktrace</span><span class="token operator">=</span>sys.exc_info<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/util/retry.py"</span>, line <span class="token number">410</span>, <span class="token keyword">in</span> increment    raise six.reraise<span class="token punctuation">(</span>type<span class="token punctuation">(</span>error<span class="token punctuation">)</span>, error, _stacktrace<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/packages/six.py"</span>, line <span class="token number">735</span>, <span class="token keyword">in</span> reraise    raise value  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">677</span>, <span class="token keyword">in</span> urlopen    <span class="token assign-left variable">chunked</span><span class="token operator">=</span>chunked,  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">428</span>, <span class="token keyword">in</span> _make_request    self._raise_timeout<span class="token punctuation">(</span>err<span class="token operator">=</span>e, <span class="token assign-left variable">url</span><span class="token operator">=</span>url, <span class="token assign-left variable">timeout_value</span><span class="token operator">=</span>read_timeout<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/urllib3/connectionpool.py"</span>, line <span class="token number">353</span>, <span class="token keyword">in</span> _raise_timeout    self, url, <span class="token string">"Read timed out. (read timeout=%s)"</span> % timeout_valueurllib3.exceptions.ReadTimeoutError: HTTPConnectionPool<span class="token punctuation">(</span>host<span class="token operator">=</span><span class="token string">'192.168.7.182'</span>, <span class="token assign-left variable">port</span><span class="token operator">=</span><span class="token number">80</span><span class="token punctuation">)</span>: Read timed out. <span class="token punctuation">(</span>read <span class="token assign-left variable">timeout</span><span class="token operator">=</span>None<span class="token punctuation">)</span>During handling of the above exception, another exception occurred:Traceback <span class="token punctuation">(</span>most recent call last<span class="token punctuation">)</span>:  File <span class="token string">"clientTest.py"</span>, line <span class="token number">46</span>, <span class="token keyword">in</span> <span class="token operator">&lt;</span>module<span class="token operator">></span>    response <span class="token operator">=</span> requests.request<span class="token punctuation">(</span><span class="token string">"POST"</span>, url, <span class="token assign-left variable">headers</span><span class="token operator">=</span>headers, <span class="token assign-left variable">data</span><span class="token operator">=</span>payload<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/requests/api.py"</span>, line <span class="token number">60</span>, <span class="token keyword">in</span> request    <span class="token builtin class-name">return</span> session.request<span class="token punctuation">(</span>method<span class="token operator">=</span>method, <span class="token assign-left variable">url</span><span class="token operator">=</span>url, **kwargs<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/requests/sessions.py"</span>, line <span class="token number">533</span>, <span class="token keyword">in</span> request    resp <span class="token operator">=</span> self.send<span class="token punctuation">(</span>prep, **send_kwargs<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/requests/sessions.py"</span>, line <span class="token number">646</span>, <span class="token keyword">in</span> send    r <span class="token operator">=</span> adapter.send<span class="token punctuation">(</span>request, **kwargs<span class="token punctuation">)</span>  File <span class="token string">"/usr/local/python-3.7.11/lib/python3.7/site-packages/requests/adapters.py"</span>, line <span class="token number">529</span>, <span class="token keyword">in</span> send    raise ReadTimeout<span class="token punctuation">(</span>e, <span class="token assign-left variable">request</span><span class="token operator">=</span>request<span class="token punctuation">)</span>requests.exceptions.ReadTimeout: HTTPConnectionPool<span class="token punctuation">(</span>host<span class="token operator">=</span><span class="token string">'192.168.7.182'</span>, <span class="token assign-left variable">port</span><span class="token operator">=</span><span class="token number">80</span><span class="token punctuation">)</span>: Read timed out. <span class="token punctuation">(</span>read <span class="token assign-left variable">timeout</span><span class="token operator">=</span>None<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>这是由于客户端在请求时设置了超时时间，去掉 <code>timeout</code> 参数后即可解决问题。</p><pre class="line-numbers language-python" data-language="python"><code class="language-python"><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token comment"># 原代码</span>response <span class="token operator">=</span> requests<span class="token punctuation">.</span>request<span class="token punctuation">(</span><span class="token string">"POST"</span><span class="token punctuation">,</span> url<span class="token punctuation">,</span> headers<span class="token operator">=</span>headers<span class="token punctuation">,</span> data<span class="token operator">=</span>payload<span class="token punctuation">,</span> timeout<span class="token operator">=</span><span class="token number">360</span><span class="token punctuation">)</span><span class="token comment"># 更改后代码，去除timeout参数即可</span>response <span class="token operator">=</span> requests<span class="token punctuation">.</span>request<span class="token punctuation">(</span><span class="token string">"POST"</span><span class="token punctuation">,</span> url<span class="token punctuation">,</span> headers<span class="token operator">=</span>headers<span class="token punctuation">,</span> data<span class="token operator">=</span>payload<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><h3 id="1-出现RST的原因"><a href="#1-出现RST的原因" class="headerlink" title="1. 出现RST的原因"></a>1. 出现RST的原因</h3><h4 id="客观原因"><a href="#客观原因" class="headerlink" title="客观原因"></a>客观原因</h4><ul><li>在 DPVS 中存在管理 TCP 连接的定时器，而对”监听状态” ( Established ) 的 TCP 连接默认设置为 90s 超时，即如果在此期间没有任何 TCP 报文传输，DPVS 就会分别向客户端与 RS 发送 RST 报文中断连接 （ 出现 RST 问题的<strong>原因1</strong> ）</li><li>在 Python requests 方法中默认不会实现 TCP Keep-Alive 机制，需要额外增加 <code>HTTPConnection.default_socket_options</code> 实现”连接保活” （ 出现 RST 问题的<strong>原因2</strong> ）</li><li>因为 DPVS 存在 TCP 空流超时设置（ <strong>原因1</strong> ），并且 Python requests 默认没有发送 TCP 心跳（ <strong>原因2</strong> ），导致如有请求连接超过 90s 未主动断开的，就会触达 DPVS 默认超时时间，随后 DPVS 会主动发送 RST 报文中断连接</li><li>Python requests 是依赖 urllib3 实现的 TCP 建连，但并没有向上暴露相关修改参数，使得用户无法在使用 requests 时直接管理 TCP 连接</li></ul><h4 id="主观原因"><a href="#主观原因" class="headerlink" title="主观原因"></a>主观原因</h4><ul><li>“中台服务”创建资源是串行执行，只有等到”服务端”资源完成创建后这个请求才算完成</li><li>“服务端”的资源创建流程通常需要 5、6 分钟甚至更多，导致一般的超时阈值无法覆盖整个执行过程</li><li>综上，再结合”客观原因”而触发了创建中的 RST 问题</li></ul><h3 id="2-为什么只在本次版本发布后出现该问题"><a href="#2-为什么只在本次版本发布后出现该问题" class="headerlink" title="2. 为什么只在本次版本发布后出现该问题"></a>2. 为什么只在本次版本发布后出现该问题</h3><ul><li>原来”中台服务”有对 RST 异常进行捕获并重试（ “服务端”接口已做幂等校验 ），而在本次发版后因为框架升级忽略了相关处理，未能”捕获并重试”进而引发相关问题</li></ul><h3 id="3-出现客户端请求超时-408-Rquest-Timeout-的原因"><a href="#3-出现客户端请求超时-408-Rquest-Timeout-的原因" class="headerlink" title="3. 出现客户端请求超时(408 Rquest Timeout)的原因"></a>3. 出现客户端请求超时(408 Rquest Timeout)的原因</h3><ul><li>客户端有设置 <code>timeout</code> 主动超时参数，导致到了超时阈值后主动断开连接</li></ul><hr><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://www.bookstack.cn/read/envoyproxy-1.10/144d336a80f65388.md">HTTP route management - HTTP route - 《Envoy Proxy 1.10 Documentation》</a></p><p><a href="https://requests.readthedocs.io/en/stable/user/advanced/#keep-alive">https://requests.readthedocs.io/en/stable/user/advanced/#keep-alive</a></p><p><a href="https://github.com/psf/requests/issues/4937">Connection reset by peer when sending POST · Issue #4937 · psf/requests · GitHub</a></p><p><a href="https://github.com/edeng23/binance-trade-bot/issues/212">Connection reset by peer · Issue #212 · edeng23/binance-trade-bot · GitHub</a></p><p><a href="https://github.com/urllib3/urllib3/issues/944">detection of dropped persistent connection fails if server resets connection · Issue #944 · urllib3/urllib3 · GitHub</a></p><p><a href="https://urllib3.readthedocs.io/en/latest/user-guide.html#retrying-requests">https://urllib3.readthedocs.io/en/latest/user-guide.html#retrying-requests</a></p><p><a href="https://cloud.tencent.com/developer/ask/sof/106994102">连接中止: RemoteDisconnected (“没有响应的远程结束关闭连接”)在发送邮件时大约5分钟不活动之后-腾讯云开发者社区-腾讯云</a></p><p><a href="https://www.xinmeow.com/2022/04/25/python-%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE-requests-%E6%A8%A1%E5%9D%97%E4%BD%BF%E7%94%A8%EF%BC%8C%E6%89%93%E5%BC%80tcp-keepalive%E8%A7%A3%E5%86%B3%E8%AF%B7%E6%B1%82%E9%95%BF%E6%97%B6%E9%97%B4/">python 环境配置 requests 模块使用，打开tcp keepalive解决请求长时间返回时tcp连接断开问题</a></p><p><a href="https://docs.python.org/3/library/http.client.html">http.client — HTTP protocol client — Python 3.12.0 documentation</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;线上某个中台服务在资源创建时如果执行过程超长，就会触发服务端响应 &lt;code&gt;(&amp;#39;Connection aborted.&amp;#39;,</summary>
      
    
    
    
    <category term="network" scheme="https://nestealin.com/categories/network/"/>
    
    
    <category term="dpvs" scheme="https://nestealin.com/tags/dpvs/"/>
    
    <category term="ipvs" scheme="https://nestealin.com/tags/ipvs/"/>
    
    <category term="tcp" scheme="https://nestealin.com/tags/tcp/"/>
    
    <category term="Connection reset by peer" scheme="https://nestealin.com/tags/Connection-reset-by-peer/"/>
    
    <category term="Connection reset" scheme="https://nestealin.com/tags/Connection-reset/"/>
    
    <category term="RST" scheme="https://nestealin.com/tags/RST/"/>
    
  </entry>
  
  <entry>
    <title>KVM安装黑群晖DSM7.X</title>
    <link href="https://nestealin.com/ec84f387/"/>
    <id>https://nestealin.com/ec84f387/</id>
    <published>2023-04-15T16:18:18.000Z</published>
    <updated>2024-06-29T07:26:38.768Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>原有 DSM 6.23 无法直接升级至 7.2 （引导变动、过程繁琐，同时存在一定风险）。</p><hr><h2 id="警告"><a href="#警告" class="headerlink" title="警告"></a>警告</h2><img src="/ec84f387/nesVaultImage-20230410004606.png" class=""><p>本篇教程仅做学习使用，<strong>不对任何数据及可用性负责</strong>。</p><hr><h2 id="安装步骤"><a href="#安装步骤" class="headerlink" title="安装步骤"></a>安装步骤</h2><h3 id="事前准备"><a href="#事前准备" class="headerlink" title="事前准备"></a>事前准备</h3><blockquote><p>此处跳过KVM环境安装，如需安装管理工具，可参考: <a href="https://nestealin.com/25f60e5a/">WebVirtCloud–KVM管理工具的部署及使用详细文档</a></p></blockquote><h4 id="引导文件及系统安装包"><a href="#引导文件及系统安装包" class="headerlink" title="引导文件及系统安装包"></a>引导文件及系统安装包</h4><p>访问链接: <a href="https://pan.gxnas.com:1443/GXNAS%E7%BD%91%E7%9B%98-OneDrive/%E9%BB%91%E7%BE%A4%E6%99%96/%E9%BB%91%E7%BE%A4%E6%99%96DSM6.24%E5%92%8CDSM7.x%E6%B5%8B%E8%AF%95%E7%89%88">黑群晖DSM6.24和DSM7.x测试版 | GXNAS网盘（远程）</a></p><p>下载红框中的文件</p><blockquote><p>本篇以安装 DS3622 机器型号的黑群晖为例。</p></blockquote><img src="/ec84f387/nesVaultImage-20230409133434.png" class=""><blockquote><p>注意:</p><ul><li>DS3622xs_7.X引导文件（支持7.0.1-42218到7.1.1-42962up4）.img<ul><li>需要将文件上传至服务器 <code>/data2/kvm/images/ds3622_7.2/</code> 目录，并重命名为 <code>synoboot.img</code> ； </li><li><strong>完整绝对路径:</strong> <code>/data2/kvm/images/ds3622_7.2/synoboot.img</code></li></ul></li><li>DS3622xs_7.2-64216（系统安装包）.pat<ul><li>放在电脑本地即可</li></ul></li></ul></blockquote><h4 id="Synology-Assistant-（非必须）"><a href="#Synology-Assistant-（非必须）" class="headerlink" title="Synology Assistant （非必须）"></a>Synology Assistant （非必须）</h4><p><a href="https://www.synology.com/zh-tw/support/download/DS3622xs+?version=7.1#utilities">下載中心 - DS3622xs+ | 群暉科技 Synology Inc.</a></p><p>根据红框选项并下载</p><img src="/ec84f387/nesVaultImage-20230409134004.png" class=""><img src="/ec84f387/nesVaultImage-20230409134049.png" class=""><p>根据系统选择合适的文件，下载后在本地安装即可。</p><h3 id="KVM启动"><a href="#KVM启动" class="headerlink" title="KVM启动"></a>KVM启动</h3><h4 id="镜像准备"><a href="#镜像准备" class="headerlink" title="镜像准备"></a>镜像准备</h4><p>主要镜像:</p><ul><li>引导文件: <code>/data2/kvm/images/ds3622_7.2/synoboot.img</code> （即上面下载的 <code>DS3622xs_7.X引导文件（支持7.0.1-42218到7.1.1-42962up4）.img</code>）</li><li>数据盘: <code>/data2/kvm/images/synology_72_data.img</code> （需要手动创建）</li></ul><blockquote><p>引导文件下载”事前准备”中有提到，不再重复。</p></blockquote><p>创建数据盘</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /data2/kvm/images<span class="token comment"># 根据实际情况，决定创建大小</span>qemu-img create -f qcow2 synology_72_data.img 3000G<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h4 id="KVM配置文件"><a href="#KVM配置文件" class="headerlink" title="KVM配置文件"></a>KVM配置文件</h4><p><code>vim synology-72.xml</code></p><p>填入如下内容:  ( 以下内容仅供参考，需要根据实际情况进行调整 )</p><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>domain</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>kvm<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>name</span><span class="token punctuation">></span></span>synology-72<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>name</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>memory</span> <span class="token attr-name">unit</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>KiB<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>4194304<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>memory</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>currentMemory</span> <span class="token attr-name">unit</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>KiB<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>2097152<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>currentMemory</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>vcpu</span> <span class="token attr-name">placement</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>static<span class="token punctuation">'</span></span> <span class="token attr-name">current</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>4<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>4<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>vcpu</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>os</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>type</span> <span class="token attr-name">arch</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>x86_64<span class="token punctuation">'</span></span> <span class="token attr-name">machine</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pc-i440fx-rhel7.0.0<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>hvm<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>type</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bootmenu</span> <span class="token attr-name">enable</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>yes<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>os</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>features</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>acpi</span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>apic</span><span class="token punctuation">/></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>features</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>cpu</span> <span class="token attr-name">mode</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>custom<span class="token punctuation">'</span></span> <span class="token attr-name">match</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>exact<span class="token punctuation">'</span></span> <span class="token attr-name">check</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>partial<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>model</span> <span class="token attr-name">fallback</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>allow<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>Westmere<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>model</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>vendor</span><span class="token punctuation">></span></span>Intel<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>vendor</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>vme<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ds<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>acpi<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ss<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ht<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>tm<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pbe<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pclmuldq<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>dtes64<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ds_cpl<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>vmx<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>est<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>tm2<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>xtpr<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pdcm<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>movbe<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>tsc-deadline<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>rdrand<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>arat<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>tsc_adjust<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>smep<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>erms<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>feature</span> <span class="token attr-name">policy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>require<span class="token punctuation">'</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>rdtscp<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>cpu</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>clock</span> <span class="token attr-name">offset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>utc<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>timer</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>rtc<span class="token punctuation">'</span></span> <span class="token attr-name">tickpolicy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>catchup<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>timer</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pit<span class="token punctuation">'</span></span> <span class="token attr-name">tickpolicy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>delay<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>timer</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>hpet<span class="token punctuation">'</span></span> <span class="token attr-name">present</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>no<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>clock</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>on_poweroff</span><span class="token punctuation">></span></span>destroy<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>on_poweroff</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>on_reboot</span><span class="token punctuation">></span></span>restart<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>on_reboot</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>on_crash</span><span class="token punctuation">></span></span>restart<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>on_crash</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>pm</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>suspend-to-mem</span> <span class="token attr-name">enabled</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>no<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>suspend-to-disk</span> <span class="token attr-name">enabled</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>no<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>pm</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>devices</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>emulator</span><span class="token punctuation">></span></span>/usr/libexec/qemu-kvm<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>emulator</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>disk</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>file<span class="token punctuation">'</span></span> <span class="token attr-name">device</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>disk<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>driver</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>qemu<span class="token punctuation">'</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>raw<span class="token punctuation">'</span></span> <span class="token attr-name">cache</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>writeback<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>source</span> <span class="token attr-name">file</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>/data2/kvm/images/ds3622_7.2/synoboot.img<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>target</span> <span class="token attr-name">dev</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>hdc<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>usb<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>boot</span> <span class="token attr-name">order</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>1<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>usb<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span> <span class="token attr-name">port</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>2<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>disk</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>disk</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>file<span class="token punctuation">'</span></span> <span class="token attr-name">device</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>disk<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>driver</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>qemu<span class="token punctuation">'</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>qcow2<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>source</span> <span class="token attr-name">file</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>/data2/kvm/images/synology_72_data.img<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>target</span> <span class="token attr-name">dev</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>sda<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>sata<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>boot</span> <span class="token attr-name">order</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>2<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>drive<span class="token punctuation">'</span></span> <span class="token attr-name">controller</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>1<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span> <span class="token attr-name">unit</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>disk</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>controller</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>usb<span class="token punctuation">'</span></span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span> <span class="token attr-name">model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ich9-ehci1<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x04<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x7<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>controller</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>controller</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>usb<span class="token punctuation">'</span></span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span> <span class="token attr-name">model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ich9-uhci1<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>master</span> <span class="token attr-name">startport</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x04<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0<span class="token punctuation">'</span></span> <span class="token attr-name">multifunction</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>on<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>controller</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>controller</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>usb<span class="token punctuation">'</span></span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span> <span class="token attr-name">model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ich9-uhci2<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>master</span> <span class="token attr-name">startport</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>2<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x04<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x1<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>controller</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>controller</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>usb<span class="token punctuation">'</span></span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span> <span class="token attr-name">model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ich9-uhci3<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>master</span> <span class="token attr-name">startport</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>4<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x04<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x2<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>controller</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>controller</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>sata<span class="token punctuation">'</span></span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x07<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>controller</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>controller</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>sata<span class="token punctuation">'</span></span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>1<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x09<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>controller</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>controller</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span> <span class="token attr-name">model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci-root<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>controller</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>scsi<span class="token punctuation">'</span></span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span> <span class="token attr-name">model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>virtio-scsi<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x03<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>controller</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>controller</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ide<span class="token punctuation">'</span></span> <span class="token attr-name">index</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x01<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x1<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>controller</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>interface</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>bridge<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>mac</span> <span class="token attr-name">address</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>52:72:13:65:c4:2b<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>source</span> <span class="token attr-name">bridge</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>br0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>model</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>e1000<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x13<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>interface</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>serial</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pty<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>target</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>isa-serial<span class="token punctuation">'</span></span> <span class="token attr-name">port</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>model</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>isa-serial<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>target</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>serial</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>console</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pty<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>target</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>serial<span class="token punctuation">'</span></span> <span class="token attr-name">port</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>console</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>mouse<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ps2<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>keyboard<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>ps2<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>graphics</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>vnc<span class="token punctuation">'</span></span> <span class="token attr-name">port</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>15999<span class="token punctuation">'</span></span> <span class="token attr-name">autoport</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>no<span class="token punctuation">'</span></span> <span class="token attr-name">listen</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0.0.0.0<span class="token punctuation">'</span></span> <span class="token attr-name">passwd</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>000000<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>listen</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>address<span class="token punctuation">'</span></span> <span class="token attr-name">address</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0.0.0.0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>graphics</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>video</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>model</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>cirrus<span class="token punctuation">'</span></span> <span class="token attr-name">vram</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>16384<span class="token punctuation">'</span></span> <span class="token attr-name">heads</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>1<span class="token punctuation">'</span></span> <span class="token attr-name">primary</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>yes<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x02<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>video</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>memballoon</span> <span class="token attr-name">model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>virtio<span class="token punctuation">'</span></span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>address</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>pci<span class="token punctuation">'</span></span> <span class="token attr-name">domain</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0000<span class="token punctuation">'</span></span> <span class="token attr-name">bus</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x00<span class="token punctuation">'</span></span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x05<span class="token punctuation">'</span></span> <span class="token attr-name">function</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>0x0<span class="token punctuation">'</span></span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>memballoon</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>devices</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>domain</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="加载配置并运行"><a href="#加载配置并运行" class="headerlink" title="加载配置并运行"></a>加载配置并运行</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">virsh</span> define synology-72.xml<span class="token function">virsh</span> list --all <span class="token operator">|</span> <span class="token function">grep</span> synology<span class="token function">virsh</span> start synology-72<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>在本地以 VNC Viewer 进行连接</p><img src="/ec84f387/nesVaultImage-20230409182119.png" class=""><p>首次启动时会自动制作”引导程序”</p><img src="/ec84f387/nesVaultImage-20230409182023.png" class=""><img src="/ec84f387/nesVaultImage-20230409135732.png" class=""><p>看到如上提示时代表引导成功，可以继续本地配置</p><h3 id="安装DSM"><a href="#安装DSM" class="headerlink" title="安装DSM"></a>安装DSM</h3><h4 id="安装系统"><a href="#安装系统" class="headerlink" title="安装系统"></a>安装系统</h4><p>打开 Synology Assistant 同意”许可协议”并开始搜索内网服务。</p><img src="/ec84f387/nesVaultImage-20230409182249.png" class=""><p>有如下提示则代表引导正常</p><img src="/ec84f387/nesVaultImage-20230409182336.png" class=""><p>在电脑浏览器新开一个标签，输入（<a href="http://find.synology.com/">http://find.synology.com/</a>）这个地址回车，开始搜索局域网内的群晖设备；</p><p>如果局域网内有多台群晖设备的，右边会有一个三角形显示，可以翻页找到我们需要安装的设备（状态会显示：未安装），点”连接”；</p><img src="/ec84f387/nesVaultImage-20230409182629.png" class=""><p>左下角”我已阅读并同意 EULA 的条款”打勾，下一步；</p><img src="/ec84f387/nesVaultImage-20230409182718.png" class=""><p>继续；</p><img src="/ec84f387/nesVaultImage-20230409182735.png" class=""><p>点击”安装”；</p><img src="/ec84f387/nesVaultImage-20230409182917.png" class=""><p>浏览；</p><img src="/ec84f387/nesVaultImage-20230409182944.png" class=""><p>找到之前下载的 <code>DS3622xs_7.2-64216（系统安装包）.pat</code>  这个安装包文件，打开；</p><img src="/ec84f387/nesVaultImage-20230409183050.png" class=""><p>确认一下安装包的版本号（用什么版本的引导，就要选对应版本的安装包，不可以搞错），无误后点下一步；</p><img src="/ec84f387/nesVaultImage-20230409183113.png" class=""><p>安装过程中，群晖系统会自动把存储硬盘重新分区并格式化为群晖格式的硬盘，在”我了解这些硬盘上的所有数据都将被删除”打勾，继续；</p><img src="/ec84f387/nesVaultImage-20230409183148.png" class=""><p>输入型号”DS3622xs+”，继续；</p><img src="/ec84f387/nesVaultImage-20230409183221.png" class=""><p>开始安装 DSM 系统；</p><img src="/ec84f387/nesVaultImage-20230409183248.png" class=""><p>耐心等待安装，安装完成系统会自动重启，此时会显示一个10分钟的倒计时，重启等待的时间由硬件性能决定（正常等待1-10分钟）；</p><img src="/ec84f387/nesVaultImage-20230409183553.png" class=""><p>重启后回到 Synology Assistant 可以看到系统已经就绪。</p><img src="/ec84f387/nesVaultImage-20230409135838.png" class=""><h4 id="配置系统"><a href="#配置系统" class="headerlink" title="配置系统"></a>配置系统</h4><p>等待套件加载完毕；</p><img src="/ec84f387/nesVaultImage-20230409183810.png" class=""><img src="/ec84f387/nesVaultImage-20230409183827.png" class=""><p>开始设置系统，”开始”；</p><img src="/ec84f387/957e03d76dd5b4e5e4af04159e77fc18.png" class=""><p>给设备起个名字（不可以用中文），设置一个用户名（不可以用admin），设置密码（密码要求：大写字母+小写字母+数字的组合，长度至少8位），下一步。</p><img src="/ec84f387/nesVaultImage-20230410010204.png" class=""><p>选”当有可用的DSM或者套件更新时通知我，我会手动安装”，下一步。</p><img src="/ec84f387/nesVaultImage-20230409184008.png" class=""><p>“跳过” Synology 账户登录；</p><img src="/ec84f387/nesVaultImage-20230409184028.png" class=""><p>不勾选（不开启）”设备分析”，**直接点击”提交”**；</p><img src="/ec84f387/nesVaultImage-20230409184047.png" class=""><p>进入系统桌面，2FA提示可根据需要按需开启；</p><img src="/ec84f387/nesVaultImage-20230409184138.png" class=""><p>接下来提示创建存储池和存储空间，点”立即创建”；</p><img src="/ec84f387/nesVaultImage-20230409184215.png" class=""><p>开始；</p><img src="/ec84f387/nesVaultImage-20230409184243.png" class=""><p>RAID类型根据实际选择（如果有多个硬盘需要组阵列的选SHR，如果需要把多个硬盘组成一个大容量的选JBOD），本教程使用单硬盘，选”Basic”即可，下一步；</p><img src="/ec84f387/nesVaultImage-20230409184326.png" class=""><p>选中需要建立存储的硬盘，下一步；</p><img src="/ec84f387/nesVaultImage-20230409184419.png" class=""><p>跳过硬盘检查（如果你组的是RAID，强烈建议勾选”执行硬盘检查”，以免硬盘出问题引起RAID损毁），下一步；</p><img src="/ec84f387/nesVaultImage-20230409184455.png" class=""><p>在”修改分配的大小”这里，点”最大化”，下一步；</p><img src="/ec84f387/nesVaultImage-20230409184533.png" class=""><p>“选择文件系统”这里有两个选择，根据实际情况选择，如果想要使用群晖系统所有功能不受限制的，选”Btrfs”，下一步；</p><img src="/ec84f387/nesVaultImage-20230409184557.png" class=""><p>无磁盘加密需求，下一步；</p><img src="/ec84f387/nesVaultImage-20230409184636.png" class=""><p>核对配置，应用；</p><img src="/ec84f387/nesVaultImage-20230409184704.png" class=""><p>格式化硬盘，确定；</p><img src="/ec84f387/nesVaultImage-20230409184736.png" class=""><h4 id="确认版本"><a href="#确认版本" class="headerlink" title="确认版本"></a>确认版本</h4><p>进入桌面</p><img src="/ec84f387/nesVaultImage-20230409140906.png" class=""><p>进入 “控制面板” – “信息中心” 确认系统版本</p><img src="/ec84f387/nesVaultImage-20230409140943.png" class=""><p>系统安装至此结束。</p><hr><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ol><li><a href="https://wp.gxnas.com/11213.html">Proxmox VE（PVE）安装黑群晖DSM7.X教程（PVE虚拟机安装群晖DS918-7.01保姆级教程） - GXNAS博客</a></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;原有 DSM 6.23 无法直接升级至 7.2 （引导变动、过程繁琐，同时存在一定风险）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;警告&quot;&gt;&lt;a </summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="kvm" scheme="https://nestealin.com/tags/kvm/"/>
    
    <category term="dsm" scheme="https://nestealin.com/tags/dsm/"/>
    
    <category term="黑群晖" scheme="https://nestealin.com/tags/%E9%BB%91%E7%BE%A4%E6%99%96/"/>
    
  </entry>
  
  <entry>
    <title>MacOS下利用launchd实现守护进程与开机自启</title>
    <link href="https://nestealin.com/3fd008f1/"/>
    <id>https://nestealin.com/3fd008f1/</id>
    <published>2023-04-09T07:14:47.000Z</published>
    <updated>2024-06-29T07:26:38.829Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>最近在 Mac 上安装了一些软件。重启后发现这些软件会随开机启动。我不喜欢这样，所以想禁止这些启动项。</p><p>在中文网络搜索，大多数内容都是在系统偏好设置中，在账户和群组里管理「登录项」。但是目标软件没有出现在登录项的列表中。为此，我不得不在英文网络上搜索，找到了 Apple 关于开发者的一些文档，最终解决了问题。</p><p>这篇记录一下如何管理 macOS 系统上的启动项与守护进程。</p><hr><h2 id="守护进程与用户代理"><a href="#守护进程与用户代理" class="headerlink" title="守护进程与用户代理"></a>守护进程与用户代理</h2><p>启动项的专业称呼是守护进程（Daemon）。守护进程是计算机系统中，运行在后台的程序。在 <em>nix</em> 系统中，守护进程通常没有父进程。一般来说，守护进程完成监听而后作出响应的任务。举例来说，杀毒软件的守护进程监听到有新下载的文件，就给出响应——启动杀毒软件对新下载的文件进行安全扫描。</p><p>通常来说，守护进程是系统启动及内核运行后在系统初始化阶段启动的进程。对于 macOS 来说，还有名为用户代理（User Agent）的守护进程类似物。与守护进程相同，用户代理也能实现上述监听而后作出响应的功能。不过，与守护进程不同的是，用户代理是在用户登录系统时启动的，而不是在系统初始化阶段启动的。不过，就本文而言，守护进程与用户代理是一回事，因此除有特殊注明外，一律以守护进程指代，不做区分。</p><hr><h2 id="launchd介绍"><a href="#launchd介绍" class="headerlink" title="launchd介绍"></a>launchd介绍</h2><p>在 macOS 上，Apple 推荐用 <code>launchd</code> 来启动守护进程与用户代理。</p><p>具体来说，<code>launchd</code> 在系统启动及内和运行后，在系统初始化阶段启动守护进程，而在用户登录是启动用户代理。流程大致如下：</p><ol><li>读入属性列表文件（property list files）</li><li>注册守护进程所需的套接字（sockets）和文件描述符（file descriptors）</li><li>启动要求在任何情况下持续运行的守护进程</li><li>对于按需启动的守护进程，在 <code>launchd</code> 收到相应请求时，启动对应的守护进程</li><li>当关机（对于守护进程）或用户登出（对于用户代理）时，<code>launchd</code> 对这些守护进程发出 <code>SIGTERM</code> 信号</li></ol><h3 id="launchctl定义"><a href="#launchctl定义" class="headerlink" title="launchctl定义"></a>launchctl定义</h3><p><code>launchctl </code>经常用来做定时任务，英文解释如下：</p><blockquote><p>In computing, launchd, a unified operating system service management framework, starts, stops and manages daemons, applications, processes, and scripts in macOS. It was introduced with Mac OS X Tiger and is licensed under the Apache License. – Wikipedia</p></blockquote><p><a href="https://link.juejin.cn/?target=https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html">英文官网地址</a></p><p>核心是定义一系列的自启动应用配置文件</p><table><thead><tr><th align="left">Type</th><th align="left">Lacation</th><th align="left">Run on behalf of</th></tr></thead><tbody><tr><td align="left">User Agents</td><td align="left">~/Library/LaunchAgents</td><td align="left">Current logged in user</td></tr><tr><td align="left">Global Agents</td><td align="left">/Library/LaunchAgents</td><td align="left">Current logged in user</td></tr><tr><td align="left">Global Daemons</td><td align="left">/Library/LaunchDaemons</td><td align="left">root or the user sepcified with the key UserName</td></tr><tr><td align="left">System Agents</td><td align="left">/System/Library/LaunchAgents</td><td align="left">Current logged in user</td></tr><tr><td align="left">System Daemons</td><td align="left">/System/Library/LaunchDaemons</td><td align="left">root or the user sepcified with the key UserName</td></tr></tbody></table><h3 id="启动顺序"><a href="#启动顺序" class="headerlink" title="启动顺序"></a>启动顺序</h3><ol><li>电脑启动，在用户未登录时，系统会扫描 <code>/System/Library/LaunchDaemons/</code> 和 <code>/Library/LaunchDaemons/</code> 里面的配置</li><li>用户登录进来时，系统会扫描 <code>/System/Library/LaunchAgents, /Library/LaunchAgents</code> ，以及用户的目录：<code>~/Library/LaunchAgents directory</code> 里面的配置</li></ol><h3 id="属性列表文件-property-list-files"><a href="#属性列表文件-property-list-files" class="headerlink" title="属性列表文件 ( property list files )"></a>属性列表文件 ( property list files )</h3><p>上一节提到，<code>launchd</code> 会去相应目录读取属性列表文件，然后根据属性列表文件中的参数，注册套接字和文件描述符等资源，以及控制守护进程的运行策略。因此，接下来的关键就是这类属性列表文件。</p><p>属性列表文件的英文是 Property List files，对应的文件名后缀是 <code>.plist</code> 。说是属性列表文件，其实本质上就是 XML 文件。以下是一个示例文件。</p><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token prolog">&lt;?xml version="1.0" encoding="UTF-8"?></span><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">plist</span> <span class="token name">PUBLIC</span> <span class="token string">"-//Apple//DTD PLIST 1.0//EN"</span> <span class="token string">"http://www.apple.com/DTDs/PropertyList-1.0.dtd"</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>plist</span> <span class="token attr-name">version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dict</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Label<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>com.example.hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>ProgramArguments<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>array</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>world<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>array</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>KeepAlive<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>true</span><span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dict</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>plist</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>Apple 在<a href="https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html#//apple_ref/doc/uid/10000172i-SW7-104142-BCICCCFI">文档里</a>给出了守护进程属性列表文件必选和推荐的字段，这里翻译如下。</p><table><thead><tr><th align="left">关键字</th><th align="left">说明</th></tr></thead><tbody><tr><td align="left"><code>Label &lt;string&gt;</code></td><td align="left">必填；包含用于 <code>launchd</code> 识别守护进程的唯一字符串标识符。</td></tr><tr><td align="left"><code>ProgramArguments &lt;array of strings&gt;</code></td><td align="left">必填；包含用于 <code>launchd</code> 启动守护进程时使用的参数。</td></tr><tr><td align="left"><code>inetdCompatibility</code></td><td align="left">表示该守护进程对于每个传入的连接启用相互独立的实例。该关键字会让 <code>launchd</code> 像 <code>inetd</code> 那样运作；具体来说，<code>launchd</code> 会将与每个传入连接的客户端建立好的套接字传给相互独立的守护进程实例。</td></tr><tr><td align="left"><code>KeepAlive &lt;boolean or dictionary of stuff&gt;</code></td><td align="left">该关键字用于指定相应的守护进程是按需启动还是要一直启动着。Apple 推荐实现按需启动的守护进程。</td></tr></tbody></table><p>另外的一些可选字段可参考如下表格:</p><table><thead><tr><th align="left">键值</th><th align="left">描述(作用)</th></tr></thead><tbody><tr><td align="left"><code>Program &lt;string&gt;</code></td><td align="left">可选, 要运行的程序， 如果省略这个选项，会把 <code>ProgramArguments</code> 的第一个元素作为要运行的程序, 任务执行绝对路径</td></tr><tr><td align="left"><code>WatchPaths &lt;array of strings&gt;</code></td><td align="left">可选, 作用: 监听路径. 当任何一个被监听的路径 ( array 中指定的 string ) 被修改时, 都会重启任务</td></tr><tr><td align="left"><code>QueueDirectories &lt;array of strings&gt;</code></td><td align="left">可选, 与 WatchPaths 的作用很像, 作用是监听路径的修改. 不同之处是, 只有这个路径是一个目录并且这个目录不为空时 , 任务才会被重启.</td></tr><tr><td align="left"><code>StartOnMount &lt;boolean&gt;</code></td><td align="left">This optional key causes the job to be started every time a filesystem is mounted. 具体作用未明</td></tr><tr><td align="left"><code>StartInterval &lt;integer&gt;</code></td><td align="left">可选, 每间隔 N 秒 重启任务. 当系统是睡眠状态时,任务会在下次系统被唤醒时重启, 睡眠时的多个任务重启事件会被合并成一个事件 ( 系统睡眠时,无论多少个N秒, 系统被唤醒时只会执行一次 )</td></tr><tr><td align="left"><code>StartCalendarInterval &lt;dictionary of integers or array of dictionary of integers&gt;</code></td><td align="left">可选, 在指定的日历格式的时间点 重启任务, 缺少的参数会被当做通配符(对应参数时间段内任意时间点), 这个命令和 <code>crontab</code> 命令很像(在系统休眠是也会执行任务), 和 <code>corn</code> ( 系统休眠时不执行任务,系统被唤醒时, 多次执行命令合并成一次.同 <code>StartInterval &lt;integer&gt;</code> ) 不一样. 参数格式详见下<strong>附表1</strong></td></tr><tr><td align="left"><code>StandardInPath &lt;string&gt;</code></td><td align="left">可选, 执行任务的标准数据输入的文件路径</td></tr><tr><td align="left"><code>StandardOutPath &lt;string&gt;</code></td><td align="left">可选, 任务执行时保存标准输出的文件路径</td></tr><tr><td align="left"><code>StandardErrorPath &lt;string&gt;</code></td><td align="left">可选, 任务执行时, 保存错误日志的文件路径</td></tr><tr><td align="left"><code>Debug &lt;boolean&gt;</code></td><td align="left">可选, 当任务执行, <code>launchd</code> 将临时的调整它的日志 <code>mask</code> 到LOG_DEBUG</td></tr></tbody></table><h6 id="附表1"><a href="#附表1" class="headerlink" title="附表1"></a>附表1</h6><table><thead><tr><th align="left">键值</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>Minute &lt;integer&gt;</code></td><td align="left">第几分钟时执行任务</td></tr><tr><td align="left"><code>Hour &lt;integer&gt;</code></td><td align="left">第几个小时执行任务(采用24时制)</td></tr><tr><td align="left"><code>Day &lt;integer&gt;</code></td><td align="left">每个月的第几天执行任务</td></tr><tr><td align="left"><code>Weekday &lt;integer&gt;</code></td><td align="left">周几执行任务, ( 0 ~ 7 )</td></tr><tr><td align="left"><code>Month &lt;integer&gt;</code></td><td align="left">第几个月执行任务</td></tr></tbody></table><p>此外，Apple 在<a href="https://developer.apple.com/library/archive/technotes/tn2083/_index.html">技术笔记</a>中还提及了其他两个关键字，这两个关键字也可能影响守护进程的运行策略（当然还有其他一些关键字可能影响，但主要还有这两个）：</p><ul><li><strong>RunAtLoad:</strong> 在属性列表文件加载时启动守护进程；</li><li><strong>SuccessfulExit:</strong> 与 <code>KeepAlive</code> 联合使用。当 <code>SuccessfulExit = true</code> 时表示若进程正常退出 ( <code>Exit at 0</code> )，则 <code>launchd</code> 应当尝试将其重启；当 <code>SuccessfulExit = false</code> 时表示若进程异常退出，则 <code>launchd</code> 应当尝试将其重启。</li></ul><p>因此我们可以构建一些场景：</p><table><thead><tr><th align="left">预期的行为</th><th align="left">相应的属性配置</th></tr></thead><tbody><tr><td align="left">完全地按需启动</td><td align="left"><code>KeepAlive = false; RunAtLoad = false</code></td></tr><tr><td align="left">在属性列表文件加载时启动，而后按需启动</td><td align="left"><code>KeepAlive = false; RunAtLoad = true</code></td></tr><tr><td align="left">在守护进程异常退出之前，按需启动</td><td align="left"><code>KeepAlive = &#123; SuccessfulExit = false &#125;; RunAtLoad = false</code></td></tr><tr><td align="left">在守护进程正常退出之前，按需启动</td><td align="left"><code>KeepAlive = &#123; SuccessfulExit = true &#125;; RunAtLoad = false</code></td></tr></tbody></table><h3 id="管理启动项"><a href="#管理启动项" class="headerlink" title="管理启动项"></a>管理启动项</h3><p>有了这些知识，管理 macOS 上的启动项就很容易了。你需要做的就是在上述 5 个目录下，找到相应程序的属性列表文件，而后按你的意图修改即可。当然，有些属性列表文件需要使用 <code>root</code> 权限来修改。有必要的话，你需要在终端（Terminal.app）当中使用 <code>sudo vim /path/to/your.plist</code> 来修改目标文件。</p><h4 id="查看进程清单"><a href="#查看进程清单" class="headerlink" title="查看进程清单"></a>查看进程清单</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 罗列系统当前运行的进程清单</span>launchctl list<span class="token comment"># 查看特定服务的配置信息</span>launchctl list com.adobe.AdobeCreativeCloud<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="加载守护进程"><a href="#加载守护进程" class="headerlink" title="加载守护进程"></a>加载守护进程</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 加载特定的服务配置</span>launchctl load <span class="token operator">&lt;</span>file_path<span class="token operator">></span><span class="token comment"># 例如:</span>launchctl load /Library/LaunchAgents/com.adobe.AdobeCreativeCloud.plist<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="移除守护进程"><a href="#移除守护进程" class="headerlink" title="移除守护进程"></a>移除守护进程</h4><p>如果要移除的话，可以通过如下命令执行:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 移除 xyz.hanks.spider</span>launchctl unload /Library/LaunchAgents/your.plist<span class="token comment"># 卸载特定的服务配置</span>launchctl unload -w /Library/LaunchAgents/com.adobe.AdobeCreativeCloud.plist<span class="token comment"># 特此说明，-w 参数的作用是，如果自动执行了 load 命令尝试去恢复服务注册，则让其无效</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>唯有一点需要注意，在做任何修改之前<strong>做好备份</strong>。</p><hr><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><h3 id="开机自启"><a href="#开机自启" class="headerlink" title="开机自启"></a>开机自启</h3><p>接下来我们自己自制一个自启动应用，用来每次启动电脑打印一次 <code>ls -al /Users/nestealin/Downloads </code>。</p><blockquote><p><strong>注意:</strong> 在开机启动或守护进程配置中，应尽量保持使用<strong>绝对路径</strong>，如果使用<strong>相对路径</strong>可能会提示路径不存在。</p></blockquote><p>去 <code>~/Library/LaunchAgents</code> 新建一个配置文件，名字叫做 <code>com.startup.test.plist</code> ，配置如下：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token operator">&lt;</span>?xml <span class="token assign-left variable">version</span><span class="token operator">=</span><span class="token string">"1.0"</span> <span class="token assign-left variable">encoding</span><span class="token operator">=</span><span class="token string">"UTF-8"</span>?<span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">!</span>DOCTYPE plist PUBLIC <span class="token string">"-//Apple//DTD PLIST 1.0//EN"</span> <span class="token string">"http://www.apple.com/DTDs/PropertyList-1.0.dtd"</span><span class="token operator">></span><span class="token operator">&lt;</span>plist <span class="token assign-left variable">version</span><span class="token operator">=</span><span class="token string">"1.0"</span><span class="token operator">></span>  <span class="token operator">&lt;</span>dict<span class="token operator">></span>      <span class="token operator">&lt;</span>key<span class="token operator">></span>Label<span class="token operator">&lt;</span>/key<span class="token operator">></span>      <span class="token operator">&lt;</span>string<span class="token operator">></span>com.startup.test<span class="token operator">&lt;</span>/string<span class="token operator">></span>      <span class="token operator">&lt;</span>key<span class="token operator">></span>UserName<span class="token operator">&lt;</span>/key<span class="token operator">></span>      <span class="token operator">&lt;</span>string<span class="token operator">></span>nestealin<span class="token operator">&lt;</span>/string<span class="token operator">></span>    <span class="token operator">&lt;</span>key<span class="token operator">></span>KeepAlive<span class="token operator">&lt;</span>/key<span class="token operator">></span>    <span class="token operator">&lt;</span>true/<span class="token operator">></span>      <span class="token operator">&lt;</span>key<span class="token operator">></span>ProgramArguments<span class="token operator">&lt;</span>/key<span class="token operator">></span>      <span class="token operator">&lt;</span>array<span class="token operator">></span>          <span class="token operator">&lt;</span>string<span class="token operator">></span>/bin/sh<span class="token operator">&lt;</span>/string<span class="token operator">></span>          <span class="token operator">&lt;</span>string<span class="token operator">></span>ls -al /Users/nestealin/Downloads<span class="token operator">&lt;</span>/string<span class="token operator">></span>      <span class="token operator">&lt;</span>/array<span class="token operator">></span>      <span class="token operator">&lt;</span>key<span class="token operator">></span>RunAtLoad<span class="token operator">&lt;</span>/key<span class="token operator">></span>      <span class="token operator">&lt;</span>true/<span class="token operator">></span>      <span class="token operator">&lt;</span>key<span class="token operator">></span>OnDemand<span class="token operator">&lt;</span>/key<span class="token operator">></span>      <span class="token operator">&lt;</span>false/<span class="token operator">></span>      <span class="token operator">&lt;</span>key<span class="token operator">></span>LaunchOnlyOnce<span class="token operator">&lt;</span>/key<span class="token operator">></span>      <span class="token operator">&lt;</span>true/<span class="token operator">></span>      <span class="token operator">&lt;</span>key<span class="token operator">></span>StandardErrorPath<span class="token operator">&lt;</span>/key<span class="token operator">></span>      <span class="token operator">&lt;</span>string<span class="token operator">></span>/Users/nestealin/com.startup.test.err<span class="token operator">&lt;</span>/string<span class="token operator">></span>      <span class="token operator">&lt;</span>key<span class="token operator">></span>StandardOutPath<span class="token operator">&lt;</span>/key<span class="token operator">></span>      <span class="token operator">&lt;</span>string<span class="token operator">></span>/Users/nestealin/com.startup.test.out<span class="token operator">&lt;</span>/string<span class="token operator">></span>  <span class="token operator">&lt;</span>/dict<span class="token operator">></span><span class="token operator">&lt;</span>/plist<span class="token operator">></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>接着输入命令</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">launchctl load /Users/nestealin/Library/LaunchAgents/com.startup.test.plist<span class="token function">sudo</span> <span class="token function">chown</span> root:wheel /Users/nestealin/Library/LaunchAgents/com.startup.test.plist<span class="token function">sudo</span> <span class="token function">chmod</span> <span class="token number">600</span> /Users/nestealin/Library/LaunchAgents/com.startup.test.plist<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><blockquote><p><strong>注意:</strong></p><p>设置在 <code>/Library/LaunchAgents</code> 的 plist 文件</p><ul><li>用户属组权限需要是：<code>root:wheel</code></li><li>文件权限应该是：<code>600</code></li></ul><p>不然的话设置不会生效。</p></blockquote><p>接着，查看已装载的列表：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">launchctl list<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>最后，重启电脑然后去查看 <code>/Users/nestealin/com.startup.test.out</code> 有没有正确的输出。</p><h3 id="守护进程"><a href="#守护进程" class="headerlink" title="守护进程"></a>守护进程</h3><p>以守护 <a href="https://github.com/Caldis/Mos">Mos</a> 应用进程为例，实现应用进程在<strong>手动退出</strong>或<strong>崩溃退出</strong>后3秒自动重新拉起。</p><blockquote><p>关联issue: <a href="https://github.com/Caldis/Mos/issues/574">https://github.com/Caldis/Mos/issues/574</a></p></blockquote><h4 id="编写配置文件"><a href="#编写配置文件" class="headerlink" title="编写配置文件"></a>编写配置文件</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> ~/Downloads<span class="token function">vim</span> application.com.caldis.Mos.plist<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>内容如下:</p><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token prolog">&lt;?xml version="1.0" encoding="UTF-8"?></span><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">plist</span> <span class="token name">PUBLIC</span> <span class="token string">"-//Apple//DTD PLIST 1.0//EN"</span> <span class="token string">"http://www.apple.com/DTDs/PropertyList-1.0.dtd"</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>plist</span> <span class="token attr-name">version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dict</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Label<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>application.com.caldis.Mos<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>OnDemand<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>true</span><span class="token punctuation">/></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>ProgramArguments<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>array</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>/Applications/Mos.app/Contents/MacOS/Mos<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>array</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>StartInterval<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>integer</span><span class="token punctuation">></span></span>3<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>integer</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dict</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>plist</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="加载守护进程-1"><a href="#加载守护进程-1" class="headerlink" title="加载守护进程"></a>加载守护进程</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /Library/LaunchAgents<span class="token function">sudo</span> <span class="token function">mv</span> ~/Download/application.com.caldis.Mos.plist ./<span class="token function">sudo</span> <span class="token function">chmod</span> +x application.com.caldis.Mos.plistlaunchctl load application.com.caldis.Mos.plist<span class="token comment"># 检查加载项</span>launchctl list <span class="token operator">|</span> <span class="token function">grep</span> -i mos<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="定时任务1"><a href="#定时任务1" class="headerlink" title="定时任务1"></a>定时任务1</h3><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token prolog">&lt;?xml version="1.0" encoding="UTF-8"?></span><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">plist</span> <span class="token name">PUBLIC</span> <span class="token string">"-//Apple//DTD PLIST 1.0//EN"</span> <span class="token string">"http://www.apple.com/DTDs/PropertyList-1.0.dtd"</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>plist</span> <span class="token attr-name">version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dict</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Label<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>xyz.hanks.spider<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>    <span class="token comment">&lt;!-- 要运行的程序， 如果省略这个选项，会把ProgramArguments的第一个    元素作为要运行的程序 --></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Program<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>/Users/zhanks/work/Bookshelf/run.sh<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>    <span class="token comment">&lt;!-- 每天18：30 --></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>StartCalendarInterval<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dict</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Minute<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>integer</span><span class="token punctuation">></span></span>30<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>integer</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Hour<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>integer</span><span class="token punctuation">></span></span>18<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>integer</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dict</span><span class="token punctuation">></span></span>    <span class="token comment">&lt;!-- 运行间隔，与StartCalenderInterval使用其一，单位为>秒 --></span>    <span class="token comment">&lt;!-- &lt;key>StartInterval&lt;/key>--></span>    <span class="token comment">&lt;!-- integer>5&lt;/integer>--></span>    <span class="token comment">&lt;!-- 标准错误输出文件，错误日志 --></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>StandardErrorPath<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>/Users/zhanks/run-err.log<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dict</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>plist</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="定时任务2"><a href="#定时任务2" class="headerlink" title="定时任务2"></a>定时任务2</h3><pre class="line-numbers language-xml" data-language="xml"><code class="language-xml"><span class="token prolog">&lt;?xml version="1.0" encoding="UTF-8"?></span>  <span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">plist</span> <span class="token name">PUBLIC</span> <span class="token string">"-//Apple//DTD PLIST 1.0//EN"</span> <span class="token string">"http://www.apple.com/DTDs/PropertyList-1.0.dtd"</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>plist</span> <span class="token attr-name">version</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>1.0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dict</span><span class="token punctuation">></span></span>        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Label<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token comment">&lt;!-- 名称，要全局唯一 --></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>xyz.hanks.spider<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>     <span class="token comment">&lt;!-- 要运行的程序， 如果省略这个选项，会把ProgramArguments的第一个    元素作为要运行的程序 --></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Program<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>/Users/hanks/run.sh<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>    <span class="token comment">&lt;!-- 命令， 第一个为命令，其它为参数--></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>ProgramArguments<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>array</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>/Users/hanks/run.sh<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>array</span><span class="token punctuation">></span></span>    <span class="token comment">&lt;!-- 运行时间 --></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>StartCalendarInterval<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dict</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Minute<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>integer</span><span class="token punctuation">></span></span>30<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>integer</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Hour<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>integer</span><span class="token punctuation">></span></span>9<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>integer</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Day<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>integer</span><span class="token punctuation">></span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>integer</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Month<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>integer</span><span class="token punctuation">></span></span>5<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>integer</span><span class="token punctuation">></span></span>      <span class="token comment">&lt;!-- 0和7都指星期天 --></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>Weekday<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>integer</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>integer</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dict</span><span class="token punctuation">></span></span>    <span class="token comment">&lt;!-- 运行间隔，与StartCalenderInterval使用其一，单位为秒 --></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>StartInterval<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>integer</span><span class="token punctuation">></span></span>30<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>integer</span><span class="token punctuation">></span></span>    <span class="token comment">&lt;!-- 标准输入文件 --></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>StandardInPath<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>/Users/hanks/run-in.log<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>    <span class="token comment">&lt;!-- 标准输出文件 --></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>StandardOutPath<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>/Users/hanks/run-out.log<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>    <span class="token comment">&lt;!-- 标准错误输出文件 --></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>key</span><span class="token punctuation">></span></span>StandardErrorPath<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>key</span><span class="token punctuation">></span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span><span class="token punctuation">></span></span>/Users/hanks/run-err.log<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dict</span><span class="token punctuation">></span></span>  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>plist</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>– EOF –</p><hr><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://juejin.cn/post/6910952244712538125#heading-3">mac launchctl 守护进程</a></p><p><a href="https://www.jianshu.com/p/df4070f39556">mac守护进程</a></p><p><a href="https://liam.page/2019/01/16/manage-daemons-and-agents-on-macOS/">管理 macOS 系统上的启动项</a></p><p><a href="https://sexywp.com/use-launchd-to-manage-system-services.htm">[Mac]使用 launchd 管理系统后台服务</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;最近在 Mac 上安装了一些软件。重启后发现这些软件会随开机启动。我不喜欢这样，所以想禁止这些启动项。&lt;/p&gt;
&lt;p&gt;在中文网络搜索，大多数</summary>
      
    
    
    
    <category term="others" scheme="https://nestealin.com/categories/others/"/>
    
    
    <category term="osx" scheme="https://nestealin.com/tags/osx/"/>
    
    <category term="macos" scheme="https://nestealin.com/tags/macos/"/>
    
    <category term="launchd" scheme="https://nestealin.com/tags/launchd/"/>
    
    <category term="launchctl" scheme="https://nestealin.com/tags/launchctl/"/>
    
    <category term="守护进程" scheme="https://nestealin.com/tags/%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8B/"/>
    
    <category term="开机自启" scheme="https://nestealin.com/tags/%E5%BC%80%E6%9C%BA%E8%87%AA%E5%90%AF/"/>
    
    <category term="定时任务" scheme="https://nestealin.com/tags/%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/"/>
    
  </entry>
  
  <entry>
    <title>速搭服务端调用OpenAI-API及Nginx反向代理ServerEvents</title>
    <link href="https://nestealin.com/b6f83bbc/"/>
    <id>https://nestealin.com/b6f83bbc/</id>
    <published>2023-04-02T13:14:09.000Z</published>
    <updated>2024-06-29T07:26:39.017Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>有时候通过 chatGPT 前端访问的时候会出现一些拥塞或响应很慢，但 API 仍响应迅速，为了降低交互门槛，本篇将介绍如何速搭一个自己的前端页面，以 API 形式直接交互。</p><p>同时，在本次 Nginx 的反向代理中，引入了对于服务端推送事件(ServerEvents)的流式响应代理方法，实现响应文字的逐字输出。</p><blockquote><p>注意:</p><p>API调用需要消耗 <a href="https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them">tokens</a>，并非免费交互，请在使用前三思。</p></blockquote><h2 id="获取API-Keys"><a href="#获取API-Keys" class="headerlink" title="获取API Keys"></a>获取API Keys</h2><blockquote><p>此处省略账号 OpenAI 账号创建，请自行准备。</p></blockquote><p>首先，登陆后台页面: <a href="https://platform.openai.com/account/usage">OpenAI API</a></p><p>然后，在 API keys 中点击创建 secret key</p><img src="/b6f83bbc/4005002777.png" class=""><p>点击 Create 后会有弹窗返回对应 key 内容</p><img src="/b6f83bbc/4116993835.png" class=""><blockquote><p>请妥善保管好你的 secret key。</p></blockquote><h2 id="部署服务"><a href="#部署服务" class="headerlink" title="部署服务"></a>部署服务</h2><blockquote><p>本次服务采用 <a href="https://github.com/ddiu8081/chatgpt-demo">GitHub - ddiu8081/chatgpt-demo</a> 实现”开箱即用”。</p></blockquote><p>环境依赖:</p><ul><li>nodejs: ≥ 18.15.0</li><li>nginx</li></ul><h3 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /usr/local<span class="token function">wget</span> https://nodejs.org/dist/v18.15.0/node-v18.15.0-linux-x64.tar.xz<span class="token function">tar</span> xf node-v18.15.0-linux-x64.tar.xz<span class="token function">mv</span> node-v18.15.0-linux-x64 node-v18.15.0<span class="token function">ln</span> -s node-v18.15.0 node<span class="token builtin class-name">export</span> <span class="token assign-left variable">NODEPATH</span><span class="token operator">=</span>/usr/local/node/bin<span class="token builtin class-name">export</span> <span class="token assign-left variable"><span class="token environment constant">PATH</span></span><span class="token operator">=</span><span class="token environment constant">$PATH</span><span class="token builtin class-name">:</span><span class="token variable">$NODEPATH</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="拉取仓库"><a href="#拉取仓库" class="headerlink" title="拉取仓库"></a>拉取仓库</h3><p>在服务端执行如下命令</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /opt<span class="token function">git</span> clone https://github.com/ddiu8081/chatgpt-demo.git<span class="token builtin class-name">cd</span> chatgpt-demo<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h3 id="安装依赖"><a href="#安装依赖" class="headerlink" title="安装依赖"></a>安装依赖</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">npm</span> i -g <span class="token function">pnpm</span><span class="token function">pnpm</span> <span class="token function">install</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h3 id="启动运行"><a href="#启动运行" class="headerlink" title="启动运行"></a>启动运行</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 请在 OPENAI_API_KEY 填入 OpenAI 上生成的 API Key</span><span class="token builtin class-name">export</span> <span class="token assign-left variable">OPENAI_API_KEY</span><span class="token operator">=</span>sk-xxxx<span class="token function">pnpm</span> run dev --host <span class="token number">0.0</span>.0.0<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>浏览器验证访问: <a href="http://192.168.7.28:3000/">http://192.168.7.28:3000</a></p><img src="/b6f83bbc/729375573.png" class=""><p>访问正常，接下来开始配置域名的反向代理。</p><h3 id="配置Nginx"><a href="#配置Nginx" class="headerlink" title="配置Nginx"></a>配置Nginx</h3><blockquote><p>此处省略 Nginx 安装。</p></blockquote><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">upstream</span> chatgpt_demo</span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">server</span> 192.168.7.28:3000</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span>  <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">listen</span>    <span class="token number">443</span> ssl</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span>  chatgpt-demo.nestealin.com</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">charset</span> utf-8</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">access_log</span>  logs/<span class="token variable">$http_host.access.main.log</span>  main</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">error_log</span>  logs/chatgpt-demo.nestealin.com.error.log error</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">ssl_certificate</span>      keys/server.cer</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">ssl_certificate_key</span>  keys/server.key</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">ssl_session_timeout</span>  <span class="token number">5m</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">ssl_prefer_server_ciphers</span> <span class="token boolean">on</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">ssl_protocols</span> TLSv1.2 TLSv1.3</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">&#123;</span>         <span class="token directive"><span class="token keyword">chunked_transfer_encoding</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">proxy_cache</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">proxy_buffering</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">proxy_redirect</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">proxy_http_version</span> 1.1</span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">proxy_set_header</span> Host <span class="token variable">$host</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Real-IP <span class="token variable">$remote_addr</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Forwarded-For <span class="token variable">$proxy_add_x_forwarded_for</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">proxy_set_header</span> X-Real-Port <span class="token variable">$remote_port</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">proxy_set_header</span> Connection <span class="token string">''</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">proxy_pass</span> http://chatgpt_demo</span><span class="token punctuation">;</span>            <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>由于 OpenAI 是以 <a href="https://zh.javascript.info/server-sent-events">Server Sent Events</a> 形式进行交互，客户端以 <code>text/event-stream</code> 格式发送事件，而服务端也会以 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/EventSource">EventSource</a> 的事件类型进行流式响应，这也就是为什么能在前端看到响应文字是逐字输出的。</p><p>以下几项是实现<strong>逐字输出的关键</strong>。</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">proxy_cache</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">proxy_buffering</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">proxy_http_version</span> 1.1</span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">proxy_set_header</span> Connection <span class="token string">''</span></span><span class="token punctuation">;</span><span class="token directive"><span class="token keyword">chunked_transfer_encoding</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>如果没有上述配置，那么返回结果将会等 Nginx 在完整收到结果后，再一股脑整段成篇地返回给用户，而不会像在 chatGPT 页面那样逐字流畅返回。</p></blockquote><h2 id="访问测试"><a href="#访问测试" class="headerlink" title="访问测试"></a>访问测试</h2><p>浏览器访问: <a href="https://chatgpt-demo.nestealin.com/">https://chatgpt-demo.nestealin.com/</a></p><img src="/b6f83bbc/chatGPT-demo.gif" class=""><p>如上图所示，后续即可通过自己的服务端页面直接调用 API 交互。</p><hr><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://juejin.cn/post/7074962899260669988">Server-Sent Events服务器信息推送</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;有时候通过 chatGPT 前端访问的时候会出现一些拥塞或响应很慢，但 API 仍响应迅速，为了降低交互门槛，本篇将介绍如何速搭一个自己的前</summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="nginx" scheme="https://nestealin.com/tags/nginx/"/>
    
    <category term="openai" scheme="https://nestealin.com/tags/openai/"/>
    
    <category term="chatgpt" scheme="https://nestealin.com/tags/chatgpt/"/>
    
    <category term="ServerEvents" scheme="https://nestealin.com/tags/ServerEvents/"/>
    
  </entry>
  
  <entry>
    <title>在DPVS中实现流量控制</title>
    <link href="https://nestealin.com/48078d3f/"/>
    <id>https://nestealin.com/48078d3f/</id>
    <published>2023-04-02T12:01:39.000Z</published>
    <updated>2024-06-29T07:26:38.964Z</updated>
    
    <content type="html"><![CDATA[<h2 id="基本信息"><a href="#基本信息" class="headerlink" title="基本信息"></a>基本信息</h2><h3 id="版本支持"><a href="#版本支持" class="headerlink" title="版本支持"></a>版本支持</h3><p>已实测版本:</p><ul><li>DPVS-1.8.2-with-DPDK-17.11.2</li><li>DPVS-1.9.0-with-DPDK-20.11.1</li><li>DPVS-1.9.2-with-DPDK-20.11.1</li></ul><blockquote><p>上述三个版本对 tc 的配置命令并无差异，文中的配置命令均可受用。</p></blockquote><h3 id="能力支持"><a href="#能力支持" class="headerlink" title="能力支持"></a>能力支持</h3><ul><li><strong>网卡级别流量限速</strong>: <a href="https://github.com/iqiyi/dpvs/blob/master/doc/tc.md#example1">Example 1. Device traffic shaping (Egress)</a></li><li><strong>细分流量控制</strong>: <a href="https://github.com/iqiyi/dpvs/blob/master/doc/tc.md#example2">Example 2. Traffic classification and flow control (Egress)</a></li><li><strong>访问控制</strong>: <a href="https://github.com/iqiyi/dpvs/blob/master/doc/tc.md#example3">Example 3. Access control with TC (Ingress)</a></li><li><strong>流量控制及访问控制</strong>: <a href="https://github.com/iqiyi/dpvs/blob/master/doc/tc.md#example4">Example 4. Traffic policing for services (Ingress)</a></li><li><strong>动态访问控制</strong>: <a href="https://github.com/iqiyi/dpvs/blob/master/doc/tc.md#example5">Example 5. Dynamic allow/deny access list using TC ipset classifier</a></li></ul><blockquote><p>以上策略不局限于仅在 Ingress 或 Egress 单向流量配置，也可在同一个流量策略中实现双向组合控制。</p></blockquote><h3 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h3><h4 id="实现方式"><a href="#实现方式" class="headerlink" title="实现方式"></a>实现方式</h4><p>DPVS的限速是通过 <a href="https://tldp.org/HOWTO/Traffic-Control-HOWTO/index.html">TC（Traffic Control）</a> 的机制实现的，Traffic Control是一组在网络接口上排队传输/接收数据包的机制和操作。其中包括排队(enqueuing)、流控策略(policing)、分类(classifying)、调度(scheduling)、塑形(shaping)和丢包(dropping)等操作。</p><p>主要用途介绍:</p><ul><li>  Policing：流量控制机制，常用于网络边界，以确保对等方不会消耗超过其分配带宽的流量。</li><li>  Classifying：分组机制，将数据包分离到不同的处理方式，可能是不同的输出队列中。</li><li>  Scheduling：排程机制，将数据包在特定队列的输入和输出之间排列（或重新排列）。</li><li>  Shaping：塑形机制，将数据包在输出队列中延迟传输，以满足所需的输出速率。</li><li>  Dropping：丢弃机制，将数据包完全丢弃。</li></ul><h4 id="在DPVS上的实现机制"><a href="#在DPVS上的实现机制" class="headerlink" title="在DPVS上的实现机制"></a>在DPVS上的实现机制</h4><p>DPVS通过两种TC对象（<strong>QSch</strong> 和 <strong>Cls</strong>）实现上述流量控制机制。DPVS 的 TC 框架是基于每个逻辑核(lcore)实现的，以避免多线程竞争条件造成的性能损失。每个 Qsch 必须是根 Qsch 或现有 Qsch 的一个子 Qsch ，并且根 Qsch 必须连接到 DPVS 设备。DPVS TC支持以下设备类型：</p><ul><li>  物理设备</li><li>  绑定(bonding)设备</li><li>  VLAN设备</li></ul><p>目前不支持隧道设备。支持出站(egress)和入站(ingress)流量，但需要注意的是，<strong>入站流量很难受限</strong>，因为它主要由网络通信的对等端决定。</p><blockquote><p>扩展说明:</p><p>此处的出站和入站都是相对于 DPVS 而言的，而在实际场景中，如果站在 RS 的视角来看这里的出站和入站，那么应该是:</p><ul><li><strong>出站</strong>: 即 RS 的流入/下载</li><li><strong>入站</strong>: 即 RS 的流出/上传</li></ul></blockquote><p>基本上，<strong>Qsch</strong>由一个或多个队列、一组用于队列的操作以及一些流量统计成员组成。Qsch可以作为 根Qsch 安装到 DPVS 接口设备中，也可以作为 子Qsch 集成到现有的 Qsch 中。根Qsch接收其连接设备的所有传入/传出流量，而 非根Qsch 只能从其 父Qsch 接收流量。Qsch可以分为两种不同的类型——出站Qsch和入站Qsch，以执行传输到或从 DPVS 设备接收的数据包的流量控制策略。</p><p><strong>Cls</strong>是一种分类器，由一组用于将流量分类到不同 Qsch （队列调度器/规则）的操作组成。Cls必须附加到现有的 Qsch 规则上，并在 Cls 匹配到的数据包后，会由 Qsch 规则来决定后续操作。DPVS支持两种分类的目标操作：丢弃(drop)或加入 子Qsch (queue)。不允许将流量分类到非子Qsch（例如孙子Qsch）中。基于性能考虑，数据包仅会排入最后匹配的 Qsch 中，而不是对前序 Qsch 规则逐个匹配。这意味着，如果 Qsch 被层次化配置，并且网络数据包从 根Qsch 到 叶Qsch 匹配所有 Cls，那么数据包将直接被加入到 叶Qsch 中，而不必一个接一个地经过。</p><p>每个 Cls 只能处理一种指定的数据包类型。DPVS Cls支持三种数据包类型–IPv4、IPv6和Vlan。Cls支持优先级。如果有两个或多个 Cls 附加到一个 Qsch 上，并且它们都匹配 Qsch 中的数据包，则采用具有最高优先级的 Cls 的分类结果。</p><h4 id="Qsch-对象"><a href="#Qsch-对象" class="headerlink" title="Qsch 对象"></a>Qsch 对象</h4><p>DPVS TC 实现了四个 Qsch 对象 – <code>pfifo</code>、<code>bfifo</code>、<code>pfifo_fast</code> 和 <code>tbf</code>。原则上，它们与 Linux TC 的对应项几乎相同。</p><h5 id="pfifo，bfifo"><a href="#pfifo，bfifo" class="headerlink" title="pfifo，bfifo"></a>pfifo，bfifo</h5><p><code>FIFO</code> 意味着“先进先出” ( First-In, First-Out ) ，它只是在收到数据包后尽快传输数据包，并按照数据包接收的顺序排队。</p><img src="/48078d3f/b9ac21553385d9ad3fdf32fae79a6395.png" class=""><p>然而，一个真正的 FIFO Qsch 必须有一个大小限制（缓冲区大小），以防止队列溢出。DPVS实现了两个基本的 FIFO Qsch : 一个基于字节(bytes)，另一个基于数据包(packets)。无论使用哪种类型的 FIFO，其队列大小都由参数 <code>limit</code> 来定义。</p><p>对于 <code>pfifo</code>，单位被理解为数据包(packets)，对于 <code>bfifo</code>，单位被理解为字节(bytes)。</p><h5 id="pfifo-fast"><a href="#pfifo-fast" class="headerlink" title="pfifo_fast"></a>pfifo_fast</h5><p>基于传统的 FIFO Qsch，pfifo_fast Qsch 也提供了一些优先级设置。它提供了三个不同的频段（单独的FIFO）来分离流量。</p><p>最高优先级的流量（交互式流量）被放置在<strong>频段0</strong> (FIFO 0) 中，并优先得到服务。同样地，如有<strong>频段2</strong> (FIFO 2) 的数据包需要出队（流出），则需要等待<strong>频段1</strong> (FIFO 1) 处理完其所有排队中的现有数据包。</p><p>因此，通常建议将 <code>pfifo_fast</code> 作为根 Qsch。（支持优先级和分离流量的设计，有助于提高网络性能和用户体验，对于多数应用场景已经足够。）</p><img src="/48078d3f/2852a182718629dd7906918e288711a8.png" class=""><p>而对于 <code>pfifo_fast</code> 队列，用户没有任何可配置项。关于 <code>priomap</code> 和使用 ToS 比特位的详细信息，请参见文档中的 <a href="https://lartc.org/howto/lartc.qdisc.classless.html">pfifo-fast</a> 部分。</p><h5 id="tbf"><a href="#tbf" class="headerlink" title="tbf"></a>tbf</h5><p><code>TBF</code> 是“令牌桶过滤器”(Token Bucket Filter)的缩写，因为它是建立在 token 和 buckets 之上。它简单地塑造了一个接口上传输的流量。为了限制数据包从一个特定接口的脱队速度，TBF Qsch是一个完美的解决方案。它只是将传输的流量减慢到指定的速率。只有当有足够的令牌可用时，数据包才会被传输。否则，数据包将被推迟。以这种方式延迟数据包将在数据包的往返时间中引入一个人工延迟。</p><img src="/48078d3f/072a2717f849cf86fac8bc5c8cd70a58.png" class=""><p>TBF QSch可以有以下参数:</p><ul><li><strong>rate</strong>: 速率参数，单位是 bps，可能会加上 k、m、g 等的 SI 单位后缀（1000进制），最大值为 4 Gbps。</li><li><strong>burst</strong>: 桶大小参数，单位是 bytes。这是可用令牌的最大字节数，通常需要根据速率设置较大的 burst 值。</li><li><strong>limit/latency</strong>: <strong>limit</strong> 表示可以等待令牌变得可用的队列中的最大字节数，<strong>latency</strong> 表示在 TBF 中一个数据包最大可以等待的时间，单位分别为 bytes 和 ms 。</li><li><strong>peakrate</strong>: <em>可选参数</em>，表示桶的最大耗尽速率，单位是 bps，可能会加上 k、m、g 等的 SI 单位后缀。</li><li>mtu: <em>可选参数</em>，表示 peakrate 桶的大小，单位是 bytes 。</li></ul><h4 id="Cls对象"><a href="#Cls对象" class="headerlink" title="Cls对象"></a>Cls对象</h4><h5 id="match"><a href="#match" class="headerlink" title="match"></a>match</h5><p>Cls <code>match</code> 规则由两部分组成：模式（pattern）和目标（target）。生产环境中，每个来自 Qsch 的数据包都会与模式进行比较，如果匹配，它们的处理方式将由目标的策略决定。  </p><p>在配置 <code>模式（pattern）</code> 中，需要考虑一个数据流中的以下五个属性：  </p><ul><li><strong>Protocol</strong>: 协议，包括: TCP, UDP, ICMP.  </li><li><strong>Source ip-port range</strong>: 源IP的端口范围，数据包的源IP地址和端口的可接受范围。  </li><li><strong>Dest ip-port range</strong>: 目的IP的端口范围，数据包的目标IP地址和端口的可接受范围。  </li><li><strong>Ingress device</strong>: 入站设备，接收数据包的设备，仅用于入口流量。  </li><li><strong>Egress device</strong>: 出站设备，数据包被发送的设备，仅适用于出口流量。  </li></ul><p>在实际配置中，可以省略上述 pattern 中的一个或多个属性，省略的属性在匹配时会被忽略。</p><p>例如: <code>pattern &#39;tcp，from-192.168.0.1:1-1024，oif-dpdk0&#39;</code> 表示匹配源IP地址为 <code>192.168.0.1</code>，源端口在<strong>1</strong>到<strong>1024</strong>之间，从 DPVS <code>dpdk0</code> 接口发出的 <code>TCP</code> 数据包。</p><p>而对于 <code>Cls target</code> 配置有两种策略：Qsch或Drop，具体如下:</p><ul><li>前者（Qsch）: 将匹配的数据包分类到指定 Qsch 的队列中，且目标 Qsch 必须是 Cls 所附加到的 Qsch 的子级。</li><li>后者（Drop）: 仅丢弃匹配的数据包。</li></ul><hr><h2 id="功能介绍"><a href="#功能介绍" class="headerlink" title="功能介绍"></a>功能介绍</h2><h3 id="基本命令"><a href="#基本命令" class="headerlink" title="基本命令"></a>基本命令</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable"><span class="token environment constant">PATH</span></span><span class="token operator">=</span>/usr/local/dpvs-1.9.2/bin:<span class="token environment constant">$PATH</span><span class="token comment"># 开启 egress 限速</span>dpip <span class="token function">link</span> <span class="token builtin class-name">set</span> dpdk0 tc-egress on<span class="token comment"># 添加 200Mbps 带宽限制，突发可达240Mpbs的限速规则</span>dpip qsch <span class="token function">add</span> dev dpdk0 root tbf rate 200m burst <span class="token number">2400000</span> latency 1ms<span class="token comment"># 查看 dpdk0 流量调度器（qdisc）信息</span>dpip qsch show dev dpdk0<span class="token comment"># 查看 dpdk0 根流量调度器下的分类器（cls）信息</span>dpip cls show dev dpdk0 qsch root<span class="token comment"># 查看 dpdk0 分类器 ID 为 1 的分类器信息</span>dpip cls show dev dpdk0 qsch <span class="token number">1</span>:<span class="token comment"># 修改限速20Mbps，突发30Mbps</span>dpip qsch change dev dpdk0 root tbf rate 20m burst <span class="token number">240000</span> latency 1ms<span class="token comment"># 删除限速规则</span><span class="token comment">## 注意: 如有多层规则，那么需要对每层规则手动删除</span>dpip qsch del dev dpdk0 root tbfdpip qsch del dev dpdk0 root pfifo_fastdpip qsch del dev dpdk0 handle <span class="token number">1</span>:0 parent rootdpip qsch del dev dpdk0 handle <span class="token number">10</span>:0 parent <span class="token number">1</span>:0<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>关键语法说明:</p><ul><li><code>rate</code> : 带宽限制，单位(bits/s), 支持 SI 制式(1000进)单位 (k, m, g)，例如: 10k, 20m, 1g</li><li><code>burst</code> : 突发速率，单位(Bps|Bytes/s)，例如可以理解为最大突发可达: xxMB/s</li><li>上述两者相互制约:<ul><li>最大 <code>burst</code> 决定最大带宽，假设 <code>rate</code> 设置为 <code>200m</code> ，<code>burst</code> 设置为 <code>2000000</code> (约1.9MB)，此时最大带宽约为 <code>67Mbps</code> .</li><li>最大 <code>rate</code> 制约 <code>burst</code> ，假设 <code>rate</code> 设置为 <code>100m</code> ，<code>burst</code> 设置为 <code>20000000</code> (约19MB)，此时最大带宽约为 <code>200Mbps</code> .</li></ul></li><li><code>qsch</code> : 表示网口的排队调度器设置，包括 <strong>根排队调度器</strong> 和 <strong>子排队调度器</strong> 。<ul><li><strong>根排队调度器</strong>是整个调度器层次结构的最上层，它控制整个端口的调度和限速。</li><li><strong>子排队调度器</strong>是根排队调度器的下一级，它控制端口接收到的特定流量的调度和限速。</li><li>例如，如果要为特定 IP 地址或端口号配置不同的服务质量（QoS），可以为其创建子排队调度器。</li></ul></li><li><code>qsch root</code> : 表示网口根排队调度器的分类规则，即指定哪些流量将被发送到子排队调度器进行进一步处理。</li><li><code>qsch 1:</code> : 表示网口 <code>qsch 1</code> 的子排队调度器的分类规则，即指定哪些流量将被发送到 <code>qsch 1</code> 进行进一步处理。需要注意的是，这里的 <code>qsch 1:</code> 中的冒号（:）表示所有 <code>qsch 1</code> 的子排队调度器，而不是 <code>qsch 1</code> 本身。</li></ul><blockquote><p>限速配置中，可能实际速率会低于限速值，此时可适时调整。</p></blockquote><p>以下，将基于打流实验进行简单的限速配置介绍。</p><h3 id="基准速度"><a href="#基准速度" class="headerlink" title="基准速度"></a>基准速度</h3><blockquote><p>基于iperf3打流进行带宽测试。</p></blockquote><h4 id="Keepalived配置"><a href="#Keepalived配置" class="headerlink" title="Keepalived配置"></a>Keepalived配置</h4><blockquote><p>仅展示关键配置。</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">local_address_group laddr_g1 <span class="token punctuation">&#123;</span>        <span class="token number">192.168</span>.7.185 dpdk0<span class="token punctuation">&#125;</span>local_address_group laddr_g2 <span class="token punctuation">&#123;</span>        <span class="token number">192.168</span>.7.186 dpdk0<span class="token punctuation">&#125;</span>virtual_server <span class="token number">192.168</span>.7.182 <span class="token number">12334</span> <span class="token punctuation">&#123;</span>        delay_loop <span class="token number">3</span>   <span class="token comment"># 执行RS健康检测间隔，单位: 秒</span>        lb_algo rr        lb_kind FNAT        protocol TCP        syn_proxy        laddr_group_name laddr_g1    <span class="token comment"># 从这个转发组ID与RS建连</span>        <span class="token comment"># 如果所有RS检测失败，则运行脚本</span>        quorum_down /etc/keepalived/check_rs.sh        real_server <span class="token number">192.168</span>.7.27 <span class="token number">12334</span> <span class="token punctuation">&#123;</span>                weight <span class="token number">100</span>                TCP_CHECK <span class="token punctuation">&#123;</span>                        connect_timeout <span class="token number">3</span>                        nb_sock_retry <span class="token number">2</span>                        delay_before_retry <span class="token number">3</span>                        connect_port <span class="token number">80</span>                <span class="token punctuation">&#125;</span>        <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span>virtual_server <span class="token number">192.168</span>.7.182 <span class="token number">12335</span> <span class="token punctuation">&#123;</span>        delay_loop <span class="token number">3</span>        lb_algo rr        lb_kind FNAT        protocol TCP        syn_proxy        laddr_group_name laddr_g1        quorum_down /etc/keepalived/check_rs.sh        real_server <span class="token number">192.168</span>.7.27 <span class="token number">12335</span> <span class="token punctuation">&#123;</span>                weight <span class="token number">100</span>                TCP_CHECK <span class="token punctuation">&#123;</span>                        connect_timeout <span class="token number">3</span>                        nb_sock_retry <span class="token number">2</span>                        delay_before_retry <span class="token number">3</span>                        connect_port <span class="token number">80</span>                <span class="token punctuation">&#125;</span>        <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span>virtual_server <span class="token number">192.168</span>.7.183 <span class="token number">12335</span> <span class="token punctuation">&#123;</span>        delay_loop <span class="token number">3</span>        lb_algo rr        lb_kind FNAT        protocol TCP        syn_proxy        laddr_group_name laddr_g2        quorum_down /etc/keepalived/check_rs.sh        real_server <span class="token number">192.168</span>.7.95 <span class="token number">12335</span> <span class="token punctuation">&#123;</span>                weight <span class="token number">100</span>                TCP_CHECK <span class="token punctuation">&#123;</span>                        connect_timeout <span class="token number">3</span>                        nb_sock_retry <span class="token number">2</span>                        delay_before_retry <span class="token number">3</span>                        connect_port <span class="token number">80</span>                <span class="token punctuation">&#125;</span>        <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>IPVS关系</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">Prot LocalAddress:Port Scheduler Flags  -<span class="token operator">></span> RemoteAddress:Port           Forward Weight ActiveConn InActConnTCP  <span class="token number">192.168</span>.7.182:12334 rr  -<span class="token operator">></span> <span class="token number">192.168</span>.7.27:12334           FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span>TCP  <span class="token number">192.168</span>.7.182:12335 rr  -<span class="token operator">></span> <span class="token number">192.168</span>.7.27:12335           FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span>TCP  <span class="token number">192.168</span>.7.183:12335 rr  -<span class="token operator">></span> <span class="token number">192.168</span>.7.95:12335           FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="iPerf3命令"><a href="#iPerf3命令" class="headerlink" title="iPerf3命令"></a>iPerf3命令</h4><h5 id="服务端"><a href="#服务端" class="headerlink" title="服务端"></a>服务端</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">iperf3 -s -p <span class="token number">12334</span> -i <span class="token number">1</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h5 id="客户端"><a href="#客户端" class="headerlink" title="客户端"></a>客户端</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 测试客户端上传，DPVS端下载，RS端下载</span>iperf3 -c <span class="token number">192.168</span>.7.182 -p <span class="token number">12334</span> -t <span class="token number">10</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h4 id="结果输出"><a href="#结果输出" class="headerlink" title="结果输出"></a>结果输出</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 客户端上传</span><span class="token comment"># iperf3 -c 192.168.7.182 -p 12334 -t 10</span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12334</span><span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">59896</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12334</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">93.6</span> MBytes   <span class="token number">785</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">98.2</span> MBytes   <span class="token number">824</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">92.6</span> MBytes   <span class="token number">777</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">95.5</span> MBytes   <span class="token number">801</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">96.3</span> MBytes   <span class="token number">808</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">97.5</span> MBytes   <span class="token number">818</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">97.9</span> MBytes   <span class="token number">821</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">96.1</span> MBytes   <span class="token number">807</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">94.6</span> MBytes   <span class="token number">793</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">91.7</span> MBytes   <span class="token number">769</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">954</span> MBytes   <span class="token number">800</span> Mbits/sec                  sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">954</span> MBytes   <span class="token number">800</span> Mbits/sec                  receiver<span class="token comment"># ---</span><span class="token comment"># 客户端下载</span><span class="token comment"># iperf3 -c 192.168.7.182 -p 12334 -t 10 -R</span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12334</span>Reverse mode, remote <span class="token function">host</span> <span class="token number">192.168</span>.7.182 is sending<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">59944</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12334</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">89.6</span> MBytes   <span class="token number">751</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">90.4</span> MBytes   <span class="token number">758</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">87.8</span> MBytes   <span class="token number">736</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">88.2</span> MBytes   <span class="token number">739</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">90.8</span> MBytes   <span class="token number">761</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">87.1</span> MBytes   <span class="token number">731</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">90.9</span> MBytes   <span class="token number">763</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">87.6</span> MBytes   <span class="token number">735</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">92.5</span> MBytes   <span class="token number">776</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">90.5</span> MBytes   <span class="token number">759</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth       Retr<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">896</span> MBytes   <span class="token number">751</span> Mbits/sec    <span class="token number">0</span>             sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">896</span> MBytes   <span class="token number">751</span> Mbits/sec                  receiveriperf Done.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>可得 <strong>RS</strong> 的基准带宽:</p><ul><li>下行约为 <code>800Mbps</code> 。</li><li>上行约为 <code>751Mbps</code> 。</li></ul><h3 id="出站限速-Egress"><a href="#出站限速-Egress" class="headerlink" title="出站限速-Egress"></a>出站限速-Egress</h3><h4 id="整体限速"><a href="#整体限速" class="headerlink" title="整体限速"></a>整体限速</h4><p>该限速方法是针对整个 <strong>dpdk</strong> 网卡进行限速，如果有需要针对多个 VIP、RS 限速需求，应该采取”分类限速”。</p><h5 id="设置限速"><a href="#设置限速" class="headerlink" title="设置限速"></a>设置限速</h5><p><strong>双向限速</strong></p><h6 id="开启限速"><a href="#开启限速" class="headerlink" title="开启限速"></a>开启限速</h6><ul><li>将限速设置为 <code>200Mbps</code> .</li></ul><p>针对 <code>dpdk0</code> 网卡开启限速</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /usr/local/dpvs-1.9.2/bin./dpip <span class="token function">link</span> <span class="token builtin class-name">set</span> dpdk0 tc-egress on./dpip qsch <span class="token function">add</span> dev dpdk0 root tbf rate 200m burst <span class="token number">20000000</span> latency 1ms<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h6 id="查看当前限速策略"><a href="#查看当前限速策略" class="headerlink" title="查看当前限速策略"></a>查看当前限速策略</h6><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">./dpip qsch show dev dpdk0<span class="token comment"># >>></span>qsch tbf root dev dpdk0 parent <span class="token number">0</span>: flags 0x0 cls <span class="token number">0</span> rate <span class="token number">200</span>.00Mbps burst 20000000B limit 25000B<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><h6 id="结果输出-1"><a href="#结果输出-1" class="headerlink" title="结果输出"></a>结果输出</h6><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 客户端上传速率</span>iperf3 -c <span class="token number">192.168</span>.7.182 -p <span class="token number">12334</span> -t <span class="token number">10</span><span class="token comment"># >>></span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12334</span><span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">53672</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12334</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">37.4</span> MBytes   <span class="token number">314</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">19.6</span> MBytes   <span class="token number">164</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">28.1</span> MBytes   <span class="token number">236</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">18.9</span> MBytes   <span class="token number">158</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">22.5</span> MBytes   <span class="token number">189</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">27.0</span> MBytes   <span class="token number">227</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">20.3</span> MBytes   <span class="token number">170</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">20.6</span> MBytes   <span class="token number">173</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">26.3</span> MBytes   <span class="token number">220</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">19.1</span> MBytes   <span class="token number">160</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">240</span> MBytes   <span class="token number">201</span> Mbits/sec                  sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">240</span> MBytes   <span class="token number">201</span> Mbits/sec                  receiveriperf Done.<span class="token comment"># ---</span><span class="token comment"># 客户端下载速率</span>iperf3 -c <span class="token number">192.168</span>.7.182 -p <span class="token number">12335</span> -t <span class="token number">10</span> -R<span class="token comment"># >>></span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12335</span>Reverse mode, remote <span class="token function">host</span> <span class="token number">192.168</span>.7.182 is sending<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">56984</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12335</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.01   sec  <span class="token number">37.5</span> MBytes   <span class="token number">313</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.01</span>-2.00   sec  <span class="token number">26.1</span> MBytes   <span class="token number">220</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">19.5</span> MBytes   <span class="token number">163</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">26.0</span> MBytes   <span class="token number">219</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">22.7</span> MBytes   <span class="token number">190</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">21.5</span> MBytes   <span class="token number">180</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">23.9</span> MBytes   <span class="token number">201</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">20.3</span> MBytes   <span class="token number">170</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">25.2</span> MBytes   <span class="token number">212</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">19.0</span> MBytes   <span class="token number">159</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth       Retr<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">242</span> MBytes   <span class="token number">203</span> Mbits/sec  <span class="token number">708</span>             sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">242</span> MBytes   <span class="token number">203</span> Mbits/sec                  receiveriperf Done.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>平均带宽均在 <code>200Mbps</code> 左右，验证生效。</p><h5 id="调整限速"><a href="#调整限速" class="headerlink" title="调整限速"></a>调整限速</h5><ul><li>将限速设置为 <code>30Mbps</code> .<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">./dpip qsch change dev dpdk0 root tbf rate 30m burst <span class="token number">3000000</span> latency 1ms./dpip qsch show dev dpdk0<span class="token comment"># >>></span>qsch tbf root dev dpdk0 parent <span class="token number">0</span>: flags 0x0 cls <span class="token number">0</span> rate <span class="token number">30</span>.00Mbps burst 3000000B limit 3750B<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre></li></ul><h6 id="结果输出-2"><a href="#结果输出-2" class="headerlink" title="结果输出"></a>结果输出</h6><p>客户端发起打流，验证限速结果</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 客户端上传速率</span>iperf3 -c <span class="token number">192.168</span>.7.182 -p <span class="token number">12334</span> -t <span class="token number">10</span><span class="token comment"># >>></span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12334</span><span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">53837</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12334</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">5.24</span> MBytes  <span class="token number">43.8</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">4.37</span> MBytes  <span class="token number">36.8</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">3.35</span> MBytes  <span class="token number">28.1</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">3.36</span> MBytes  <span class="token number">28.2</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">3.39</span> MBytes  <span class="token number">28.4</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">3.43</span> MBytes  <span class="token number">28.7</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">3.41</span> MBytes  <span class="token number">28.7</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">3.42</span> MBytes  <span class="token number">28.5</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">3.38</span> MBytes  <span class="token number">28.4</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">3.41</span> MBytes  <span class="token number">28.6</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec  <span class="token number">36.8</span> MBytes  <span class="token number">30.8</span> Mbits/sec                  sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec  <span class="token number">36.6</span> MBytes  <span class="token number">30.7</span> Mbits/sec                  receiveriperf Done.<span class="token comment"># ---</span><span class="token comment"># 客户端下载速率</span>iperf3 -c <span class="token number">192.168</span>.7.182 -p <span class="token number">12335</span> -t <span class="token number">10</span> -R<span class="token comment"># >>></span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12335</span>Reverse mode, remote <span class="token function">host</span> <span class="token number">192.168</span>.7.182 is sending<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">57333</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12335</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">5.90</span> MBytes  <span class="token number">49.3</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">2.98</span> MBytes  <span class="token number">25.0</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">3.79</span> MBytes  <span class="token number">31.8</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">3.05</span> MBytes  <span class="token number">25.6</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.01   sec  <span class="token number">3.76</span> MBytes  <span class="token number">31.6</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.01</span>-6.00   sec  <span class="token number">3.02</span> MBytes  <span class="token number">25.4</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">3.80</span> MBytes  <span class="token number">32.0</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">3.02</span> MBytes  <span class="token number">25.3</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">3.13</span> MBytes  <span class="token number">26.4</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">3.69</span> MBytes  <span class="token number">30.9</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth       Retr<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec  <span class="token number">36.6</span> MBytes  <span class="token number">30.7</span> Mbits/sec  <span class="token number">1940</span>             sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec  <span class="token number">36.2</span> MBytes  <span class="token number">30.3</span> Mbits/sec                  receiveriperf Done.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h5 id="持续流量过程中调整限速"><a href="#持续流量过程中调整限速" class="headerlink" title="持续流量过程中调整限速"></a>持续流量过程中调整限速</h5><ul><li>在持续的流量中，将限速从 <code>200Mbps</code> 调整为 <code>50Mbps</code> 再调整回 <code>200Mbps</code>，验证过程是否有影响。</li></ul><h6 id="结果输出-3"><a href="#结果输出-3" class="headerlink" title="结果输出"></a>结果输出</h6><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">iperf3 -c <span class="token number">192.168</span>.7.182 -p <span class="token number">12334</span> -t <span class="token number">15</span><span class="token comment"># >>></span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12334</span><span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">54238</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12334</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">35.0</span> MBytes   <span class="token number">294</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">28.6</span> MBytes   <span class="token number">240</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">18.6</span> MBytes   <span class="token number">156</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">20.2</span> MBytes   <span class="token number">170</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">28.1</span> MBytes   <span class="token number">235</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">8.72</span> MBytes  <span class="token number">73.3</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">5.73</span> MBytes  <span class="token number">48.1</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">5.83</span> MBytes  <span class="token number">48.9</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">3.97</span> MBytes  <span class="token number">33.2</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">5.83</span> MBytes  <span class="token number">49.0</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>  <span class="token number">10.00</span>-11.00  sec  <span class="token number">5.77</span> MBytes  <span class="token number">48.3</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>  <span class="token number">11.00</span>-12.00  sec  <span class="token number">37.3</span> MBytes   <span class="token number">313</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>  <span class="token number">12.00</span>-13.00  sec  <span class="token number">19.3</span> MBytes   <span class="token number">162</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>  <span class="token number">13.00</span>-14.00  sec  <span class="token number">28.6</span> MBytes   <span class="token number">241</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>  <span class="token number">14.00</span>-15.00  sec  <span class="token number">19.0</span> MBytes   <span class="token number">159</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-15.00  sec   <span class="token number">271</span> MBytes   <span class="token number">151</span> Mbits/sec                  sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-15.00  sec   <span class="token number">271</span> MBytes   <span class="token number">151</span> Mbits/sec                  receiver<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>验证有效。</p><h5 id="删除限速"><a href="#删除限速" class="headerlink" title="删除限速"></a>删除限速</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">./dpip qsch del dev dpdk0 root tbf<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><hr><h4 id="分类限速"><a href="#分类限速" class="headerlink" title="分类限速"></a>分类限速</h4><p>该限速方法可以根据应用场景进行分类限速，支持对多个 RS 配置不同限速规则。</p><h5 id="场景说明"><a href="#场景说明" class="headerlink" title="场景说明"></a>场景说明</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">Prot LocalAddress:Port Scheduler Flags  -<span class="token operator">></span> RemoteAddress:Port           Forward Weight ActiveConn InActConnTCP  <span class="token number">192.168</span>.7.182:12334 rr synproxy  -<span class="token operator">></span> <span class="token number">192.168</span>.7.27:12334           FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span>TCP  <span class="token number">192.168</span>.7.182:12335 rr synproxy  -<span class="token operator">></span> <span class="token number">192.168</span>.7.27:12335           FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span>TCP  <span class="token number">192.168</span>.7.183:12335 rr synproxy  -<span class="token operator">></span> <span class="token number">192.168</span>.7.95:12335           FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>接下来，将针对上述的 RS 设置不同的限速策略:</p><ul><li>双向不限速<ul><li>所有 <strong>RS</strong> 的 <strong>12334</strong> 端口: 双向不限速</li></ul></li><li>针对<strong>RS</strong>限制出站<ul><li>192.168.7.<strong>27</strong>:12335: 限制出站 <code>200Mbps</code> （即 RS 下载带宽）</li><li>192.168.7.<strong>95</strong>:12335: 限制出站 <code>250Mbps</code> （即 RS 下载带宽）</li></ul></li></ul><h5 id="配置方式"><a href="#配置方式" class="headerlink" title="配置方式"></a>配置方式</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 开启egress限速</span>./dpip <span class="token function">link</span> <span class="token builtin class-name">set</span> dpdk0 tc-egress on<span class="token comment"># 编写分级限速策略</span>./dpip qsch <span class="token function">add</span> dev dpdk0 root pfifo_fast./dpip qsch <span class="token function">add</span> dev dpdk0 handle <span class="token number">1</span>:0 parent root bfifo limit <span class="token number">10000000</span>./dpip qsch <span class="token function">add</span> dev dpdk0 handle <span class="token number">10</span>:0 parent <span class="token number">1</span>:0 pfifo limit <span class="token number">100000</span>./dpip qsch <span class="token function">add</span> dev dpdk0 handle <span class="token number">20</span>:0 parent <span class="token number">1</span>:0 tbf rate 80m burst <span class="token number">8000000</span> latency 2ms./dpip qsch <span class="token function">add</span> dev dpdk0 handle <span class="token number">30</span>:0 parent <span class="token number">1</span>:0 tbf rate 150m burst <span class="token number">15000000</span> latency 2ms<span class="token comment"># 分级策略</span>./dpip cls <span class="token function">add</span> dev dpdk0 qsch root handle <span class="token number">0</span>:1 match pattern <span class="token string">'tcp,oif=dpdk0'</span> target <span class="token number">1</span>:<span class="token comment"># 针对RS地址分类</span>./dpip cls <span class="token function">add</span> dev dpdk0 qsch <span class="token number">1</span>: handle <span class="token number">1</span>:1 match pattern <span class="token string">'tcp,to=:12334,oif=dpdk0'</span> target <span class="token number">10</span>:./dpip cls <span class="token function">add</span> dev dpdk0 qsch <span class="token number">1</span>: handle <span class="token number">1</span>:2 match pattern <span class="token string">'tcp,to=192.168.7.27:12335,oif=dpdk0'</span> target <span class="token number">20</span>:./dpip cls <span class="token function">add</span> dev dpdk0 qsch <span class="token number">1</span>: handle <span class="token number">1</span>:3 match pattern <span class="token string">'tcp,to=192.168.7.95:12335,oif=dpdk0'</span> target <span class="token number">30</span>:<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h5 id="查看限速策略"><a href="#查看限速策略" class="headerlink" title="查看限速策略"></a>查看限速策略</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 整体限速</span>./dpip qsch show dev dpdk0<span class="token comment"># >>></span>qsch pfifo_fast root dev dpdk0 parent <span class="token number">0</span>: flags 0x0 cls <span class="token number">1</span> bands <span class="token number">3</span> priomap <span class="token number">1</span> <span class="token number">2</span> <span class="token number">2</span> <span class="token number">2</span> <span class="token number">1</span> <span class="token number">2</span> <span class="token number">0</span> <span class="token number">0</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">1</span> <span class="token number">1</span>qsch tbf <span class="token number">30</span>: dev dpdk0 parent <span class="token number">1</span>: flags 0x0 cls <span class="token number">0</span> rate <span class="token number">150</span>.00Mbps burst 15000000B limit 37500Bqsch tbf <span class="token number">20</span>: dev dpdk0 parent <span class="token number">1</span>: flags 0x0 cls <span class="token number">0</span> rate <span class="token number">80</span>.00Mbps burst 8000000B limit 20000Bqsch pfifo <span class="token number">10</span>: dev dpdk0 parent <span class="token number">1</span>: flags 0x0 cls <span class="token number">0</span> limit <span class="token number">100000</span>qsch bfifo <span class="token number">1</span>: dev dpdk0 parent root flags 0x0 cls <span class="token number">3</span> limit <span class="token number">10000000</span><span class="token comment"># ---</span><span class="token comment"># 分级策略</span>./dpip cls show dev dpdk0 qsch <span class="token number">1</span>:<span class="token comment"># >>></span>cls match <span class="token number">1</span>:1 dev dpdk0 qsch <span class="token number">1</span>: pkttype 0x0800 prio <span class="token number">0</span> TCP,to<span class="token operator">=</span><span class="token number">0.0</span>.0.0-0.0.0.0:12334-12334,oif<span class="token operator">=</span>dpdk0 target <span class="token number">10</span>:cls match <span class="token number">1</span>:2 dev dpdk0 qsch <span class="token number">1</span>: pkttype 0x0800 prio <span class="token number">0</span> TCP,to<span class="token operator">=</span><span class="token number">192.168</span>.7.27-192.168.7.27:12335-12335,oif<span class="token operator">=</span>dpdk0 target <span class="token number">20</span>:cls match <span class="token number">1</span>:3 dev dpdk0 qsch <span class="token number">1</span>: pkttype 0x0800 prio <span class="token number">0</span> TCP,to<span class="token operator">=</span><span class="token number">192.168</span>.7.95-192.168.7.95:12335-12335,oif<span class="token operator">=</span>dpdk0 target <span class="token number">30</span>:<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h5 id="结果输出-4"><a href="#结果输出-4" class="headerlink" title="结果输出"></a>结果输出</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 192.168.7.182:12334不限速</span>iperf3 -c <span class="token number">192.168</span>.7.182 -p <span class="token number">12334</span> -t <span class="token number">10</span><span class="token comment"># >>></span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12334</span><span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">65415</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12334</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.01   sec  <span class="token number">87.9</span> MBytes   <span class="token number">727</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.01</span>-2.00   sec  <span class="token number">84.8</span> MBytes   <span class="token number">722</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">92.4</span> MBytes   <span class="token number">775</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">84.7</span> MBytes   <span class="token number">710</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">96.8</span> MBytes   <span class="token number">812</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">90.5</span> MBytes   <span class="token number">759</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">95.5</span> MBytes   <span class="token number">801</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">90.2</span> MBytes   <span class="token number">756</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">88.1</span> MBytes   <span class="token number">739</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">96.7</span> MBytes   <span class="token number">811</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">908</span> MBytes   <span class="token number">761</span> Mbits/sec                  sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">908</span> MBytes   <span class="token number">761</span> Mbits/sec                  receiveriperf Done.<span class="token comment"># ---</span><span class="token comment"># 192.168.7.182:12335限速80Mbps</span>iperf3 -c <span class="token number">192.168</span>.7.182 -p <span class="token number">12335</span> -t <span class="token number">10</span><span class="token comment"># >>></span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12335</span><span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">65441</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12335</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">14.7</span> MBytes   <span class="token number">123</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">9.42</span> MBytes  <span class="token number">78.9</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">9.37</span> MBytes  <span class="token number">78.5</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">9.80</span> MBytes  <span class="token number">82.3</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">7.62</span> MBytes  <span class="token number">64.1</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">9.23</span> MBytes  <span class="token number">77.1</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">10.1</span> MBytes  <span class="token number">85.3</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">9.39</span> MBytes  <span class="token number">78.9</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">9.40</span> MBytes  <span class="token number">78.6</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">9.31</span> MBytes  <span class="token number">78.4</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec  <span class="token number">98.4</span> MBytes  <span class="token number">82.5</span> Mbits/sec                  sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec  <span class="token number">98.3</span> MBytes  <span class="token number">82.4</span> Mbits/sec                  receiveriperf Done.<span class="token comment"># ---</span><span class="token comment"># 192.168.7.183:12335限速150Mbps</span>iperf3 -c <span class="token number">192.168</span>.7.183 -p <span class="token number">12335</span> -t <span class="token number">10</span><span class="token comment"># >>></span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.183, port <span class="token number">12335</span><span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">65473</span> connected to <span class="token number">192.168</span>.7.183 port <span class="token number">12335</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">30.8</span> MBytes   <span class="token number">258</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">17.3</span> MBytes   <span class="token number">145</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">17.1</span> MBytes   <span class="token number">144</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">17.1</span> MBytes   <span class="token number">144</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">17.0</span> MBytes   <span class="token number">142</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">17.3</span> MBytes   <span class="token number">145</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">17.2</span> MBytes   <span class="token number">144</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">17.1</span> MBytes   <span class="token number">144</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">17.2</span> MBytes   <span class="token number">145</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">17.2</span> MBytes   <span class="token number">144</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">185</span> MBytes   <span class="token number">155</span> Mbits/sec                  sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">185</span> MBytes   <span class="token number">155</span> Mbits/sec                  receiver<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>策略生效。</p><h5 id="删除限速策略"><a href="#删除限速策略" class="headerlink" title="删除限速策略"></a>删除限速策略</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">./dpip qsch del dev dpdk0 root pfifo_fast./dpip qsch del dev dpdk0 handle <span class="token number">1</span>:0 parent root bfifo limit <span class="token number">10000000</span>./dpip qsch del dev dpdk0 handle <span class="token number">10</span>:0 parent <span class="token number">1</span>:0 pfifo limit <span class="token number">100000</span>./dpip qsch del dev dpdk0 handle <span class="token number">20</span>:0 parent <span class="token number">1</span>:0 tbf rate 80m burst <span class="token number">8000000</span> latency 2ms./dpip qsch del dev dpdk0 handle <span class="token number">30</span>:0 parent <span class="token number">1</span>:0 tbf rate 150m burst <span class="token number">15000000</span> latency 2ms<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><p>除了限速，还可以实现 Ingress 方向控制、针对源IP或目标IP的访问控制与 UDP 协议分流转发相关配置等，详见: <a href="https://github.com/iqiyi/dpvs/blob/master/doc/tc.md">DPVS Traffic Control (TC)</a></p></blockquote><hr><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><h3 id="基于Egress实现出入站分类限速"><a href="#基于Egress实现出入站分类限速" class="headerlink" title="基于Egress实现出入站分类限速"></a>基于Egress实现出入站分类限速</h3><h4 id="分类限速-1"><a href="#分类限速-1" class="headerlink" title="分类限速"></a>分类限速</h4><h5 id="场景说明-1"><a href="#场景说明-1" class="headerlink" title="场景说明"></a>场景说明</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">Prot LocalAddress:Port Scheduler Flags  -<span class="token operator">></span> RemoteAddress:Port           Forward Weight ActiveConn InActConnTCP  <span class="token number">192.168</span>.7.182:12334 rr synproxy  -<span class="token operator">></span> <span class="token number">192.168</span>.7.27:12334           FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span>TCP  <span class="token number">192.168</span>.7.182:12335 rr synproxy  -<span class="token operator">></span> <span class="token number">192.168</span>.7.27:12335           FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span>TCP  <span class="token number">192.168</span>.7.183:12335 rr synproxy  -<span class="token operator">></span> <span class="token number">192.168</span>.7.95:12335           FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>针对上述的 VIP 和 RS 设置不同的限速策略:</p><ul><li>双向不限速<ul><li>192.168.7.<strong>27:12334</strong>: 双向不限速</li></ul></li><li>针对<strong>VIP</strong>限制<ul><li>192.168.7.<strong>182</strong>:12335: 出站/上传 <code>150Mbps</code> （即 VIP 上传带宽）</li><li>192.168.7.<strong>183</strong>:12335: 出站/上传 <code>80Mbps</code> （即 VIP 上传带宽）</li></ul></li><li>针对<strong>RS</strong>限制<ul><li>192.168.7.<strong>27</strong>:12335: 限制入站 <code>200Mbps</code> （即 RS 下载带宽）</li><li>192.168.7.<strong>95</strong>:12335: 限制入站 <code>250Mbps</code> （即 RS 下载带宽）</li></ul></li></ul><h5 id="配置方式-1"><a href="#配置方式-1" class="headerlink" title="配置方式"></a>配置方式</h5><h6 id="添加限速"><a href="#添加限速" class="headerlink" title="添加限速"></a>添加限速</h6><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable"><span class="token environment constant">PATH</span></span><span class="token operator">=</span>/usr/local/dpvs-1.9.2/bin:<span class="token environment constant">$PATH</span>dpip <span class="token function">link</span> <span class="token builtin class-name">set</span> dpdk0 tc-egress ondpip qsch <span class="token function">add</span> dev dpdk0 root pfifo_fastdpip qsch <span class="token function">add</span> dev dpdk0 handle <span class="token number">1</span>:0 parent root bfifo limit <span class="token number">10000000</span>dpip qsch <span class="token function">add</span> dev dpdk0 handle <span class="token number">10</span>:0 parent <span class="token number">1</span>:0 pfifo limit <span class="token number">100000</span>dpip qsch <span class="token function">add</span> dev dpdk0 handle <span class="token number">20</span>:0 parent <span class="token number">1</span>:0 tbf rate 200m burst <span class="token number">21000000</span> latency 2msdpip qsch <span class="token function">add</span> dev dpdk0 handle <span class="token number">30</span>:0 parent <span class="token number">1</span>:0 tbf rate 250m burst <span class="token number">26000000</span> latency 2msdpip qsch <span class="token function">add</span> dev dpdk0 handle <span class="token number">40</span>:0 parent <span class="token number">1</span>:0 tbf rate 150m burst <span class="token number">16000000</span> latency 2ms limit <span class="token number">30000000</span>dpip qsch <span class="token function">add</span> dev dpdk0 handle <span class="token number">50</span>:0 parent <span class="token number">1</span>:0 tbf rate 80m burst <span class="token number">9000000</span> latency 2ms limit <span class="token number">8000</span>dpip cls <span class="token function">add</span> dev dpdk0 qsch root handle <span class="token number">0</span>:1 match pattern <span class="token string">'tcp,oif=dpdk0'</span> target <span class="token number">1</span>:dpip cls <span class="token function">add</span> dev dpdk0 qsch <span class="token number">1</span>: handle <span class="token number">1</span>:1 match pattern <span class="token string">'tcp,to=:12334,oif=dpdk0'</span> target <span class="token number">10</span>:dpip cls <span class="token function">add</span> dev dpdk0 qsch <span class="token number">1</span>: handle <span class="token number">1</span>:2 match pattern <span class="token string">'tcp,to=192.168.7.27:12335,oif=dpdk0'</span> target <span class="token number">20</span>:dpip cls <span class="token function">add</span> dev dpdk0 qsch <span class="token number">1</span>: handle <span class="token number">1</span>:3 match pattern <span class="token string">'tcp,to=192.168.7.95:12335,oif=dpdk0'</span> target <span class="token number">30</span>:dpip cls <span class="token function">add</span> dev dpdk0 qsch <span class="token number">1</span>: handle <span class="token number">1</span>:4 match pattern <span class="token string">'tcp,from=192.168.7.182:12335,oif=dpdk0'</span> target <span class="token number">40</span>:dpip cls <span class="token function">add</span> dev dpdk0 qsch <span class="token number">1</span>: handle <span class="token number">1</span>:5 match pattern <span class="token string">'tcp,from=192.168.7.183:12335,oif=dpdk0'</span> target <span class="token number">50</span>:<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h6 id="查看策略"><a href="#查看策略" class="headerlink" title="查看策略"></a>查看策略</h6><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">dpip qsch show dev dpdk0dpip cls show dev dpdk0 qsch rootdpip cls show dev dpdk0 qsch <span class="token number">1</span>:<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h6 id="删除策略"><a href="#删除策略" class="headerlink" title="删除策略"></a>删除策略</h6><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">dpip qsch del dev dpdk0 root pfifo_fastdpip qsch del dev dpdk0 handle <span class="token number">1</span>:0 parent rootdpip qsch del dev dpdk0 handle <span class="token number">10</span>:0 parent <span class="token number">1</span>:0dpip qsch del dev dpdk0 handle <span class="token number">20</span>:0 parent <span class="token number">1</span>:0dpip qsch del dev dpdk0 handle <span class="token number">30</span>:0 parent <span class="token number">1</span>:0dpip qsch del dev dpdk0 handle <span class="token number">40</span>:0 parent <span class="token number">1</span>:0dpip qsch del dev dpdk0 handle <span class="token number">50</span>:0 parent <span class="token number">1</span>:0<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h5 id="验证测试"><a href="#验证测试" class="headerlink" title="验证测试"></a>验证测试</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">Uploading to <span class="token number">192.168</span>.7.182:12334 <span class="token punctuation">..</span>.<span class="token comment"># iperf3 -c 192.168.7.182 -p 12334 -t 10</span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12334</span><span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">61150</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12334</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">91.0</span> MBytes   <span class="token number">763</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">95.6</span> MBytes   <span class="token number">802</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">93.3</span> MBytes   <span class="token number">782</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">82.7</span> MBytes   <span class="token number">693</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">84.5</span> MBytes   <span class="token number">709</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">84.5</span> MBytes   <span class="token number">709</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">96.8</span> MBytes   <span class="token number">812</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">86.0</span> MBytes   <span class="token number">722</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">96.5</span> MBytes   <span class="token number">810</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec   <span class="token number">100</span> MBytes   <span class="token number">839</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">911</span> MBytes   <span class="token number">764</span> Mbits/sec                  sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">911</span> MBytes   <span class="token number">764</span> Mbits/sec                  receiveriperf Done.<span class="token comment"># ---</span>Downloading from <span class="token number">192.168</span>.7.182:12334 <span class="token punctuation">..</span>.<span class="token comment"># iperf3 -c 192.168.7.182 -p 12334 -t 10 -R</span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12334</span>Reverse mode, remote <span class="token function">host</span> <span class="token number">192.168</span>.7.182 is sending<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">61161</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12334</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">94.3</span> MBytes   <span class="token number">791</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">90.2</span> MBytes   <span class="token number">756</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">92.5</span> MBytes   <span class="token number">776</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">94.3</span> MBytes   <span class="token number">791</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">95.6</span> MBytes   <span class="token number">802</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">92.8</span> MBytes   <span class="token number">778</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">92.2</span> MBytes   <span class="token number">774</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">95.7</span> MBytes   <span class="token number">802</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">94.5</span> MBytes   <span class="token number">793</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">95.4</span> MBytes   <span class="token number">801</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth       Retr<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">938</span> MBytes   <span class="token number">787</span> Mbits/sec    <span class="token number">0</span>             sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">938</span> MBytes   <span class="token number">787</span> Mbits/sec                  receiveriperf Done.<span class="token comment"># ---</span>Uploading to <span class="token number">192.168</span>.7.182:12335 <span class="token punctuation">..</span>.<span class="token comment"># iperf3 -c 192.168.7.182 -p 12335 -t 10</span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12335</span><span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">61179</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12335</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">38.6</span> MBytes   <span class="token number">324</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.01   sec  <span class="token number">22.8</span> MBytes   <span class="token number">191</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.01</span>-3.01   sec  <span class="token number">20.1</span> MBytes   <span class="token number">168</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.01</span>-4.01   sec  <span class="token number">27.3</span> MBytes   <span class="token number">229</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.01</span>-5.01   sec  <span class="token number">18.7</span> MBytes   <span class="token number">157</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.01</span>-6.00   sec  <span class="token number">27.3</span> MBytes   <span class="token number">230</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">20.1</span> MBytes   <span class="token number">169</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">23.4</span> MBytes   <span class="token number">197</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">22.2</span> MBytes   <span class="token number">186</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">20.2</span> MBytes   <span class="token number">170</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">241</span> MBytes   <span class="token number">202</span> Mbits/sec                  sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">241</span> MBytes   <span class="token number">202</span> Mbits/sec                  receiveriperf Done.<span class="token comment"># ---</span>Downloading from <span class="token number">192.168</span>.7.182:12335 <span class="token punctuation">..</span>.<span class="token comment"># iperf3 -c 192.168.7.182 -p 12335 -t 10 -R</span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.182, port <span class="token number">12335</span>Reverse mode, remote <span class="token function">host</span> <span class="token number">192.168</span>.7.182 is sending<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">61188</span> connected to <span class="token number">192.168</span>.7.182 port <span class="token number">12335</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">31.1</span> MBytes   <span class="token number">260</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">17.5</span> MBytes   <span class="token number">146</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">17.3</span> MBytes   <span class="token number">145</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">17.5</span> MBytes   <span class="token number">148</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">13.3</span> MBytes   <span class="token number">111</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">19.7</span> MBytes   <span class="token number">166</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">17.4</span> MBytes   <span class="token number">146</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">17.4</span> MBytes   <span class="token number">146</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">17.3</span> MBytes   <span class="token number">145</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">17.4</span> MBytes   <span class="token number">145</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth       Retr<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">186</span> MBytes   <span class="token number">156</span> Mbits/sec   <span class="token number">38</span>             sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">186</span> MBytes   <span class="token number">156</span> Mbits/sec                  receiveriperf Done.<span class="token comment"># ---</span>Uploading to <span class="token number">192.168</span>.7.183:12335 <span class="token punctuation">..</span>.<span class="token comment"># iperf3 -c 192.168.7.183 -p 12335 -t 10</span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.183, port <span class="token number">12335</span><span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">61197</span> connected to <span class="token number">192.168</span>.7.183 port <span class="token number">12335</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">45.8</span> MBytes   <span class="token number">383</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">27.2</span> MBytes   <span class="token number">228</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">30.1</span> MBytes   <span class="token number">253</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">32.3</span> MBytes   <span class="token number">271</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">11.6</span> MBytes  <span class="token number">97.6</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">28.1</span> MBytes   <span class="token number">236</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">32.4</span> MBytes   <span class="token number">272</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">33.2</span> MBytes   <span class="token number">277</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">36.7</span> MBytes   <span class="token number">309</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">29.3</span> MBytes   <span class="token number">246</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">307</span> MBytes   <span class="token number">257</span> Mbits/sec                  sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">306</span> MBytes   <span class="token number">257</span> Mbits/sec                  receiveriperf Done.<span class="token comment"># ---</span>Downloading from <span class="token number">192.168</span>.7.183:12335 <span class="token punctuation">..</span>.<span class="token comment"># iperf3 -c 192.168.7.183 -p 12335 -t 10 -R</span>Connecting to <span class="token function">host</span> <span class="token number">192.168</span>.7.183, port <span class="token number">12335</span>Reverse mode, remote <span class="token function">host</span> <span class="token number">192.168</span>.7.183 is sending<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span> <span class="token builtin class-name">local</span> <span class="token number">192.168</span>.7.53 port <span class="token number">61205</span> connected to <span class="token number">192.168</span>.7.183 port <span class="token number">12335</span><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-1.00   sec  <span class="token number">15.2</span> MBytes   <span class="token number">128</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">1.00</span>-2.00   sec  <span class="token number">6.29</span> MBytes  <span class="token number">52.8</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">2.00</span>-3.00   sec  <span class="token number">12.4</span> MBytes   <span class="token number">103</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">3.00</span>-4.00   sec  <span class="token number">10.5</span> MBytes  <span class="token number">88.5</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">4.00</span>-5.00   sec  <span class="token number">6.21</span> MBytes  <span class="token number">52.3</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">5.00</span>-6.00   sec  <span class="token number">12.5</span> MBytes   <span class="token number">105</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">6.00</span>-7.00   sec  <span class="token number">8.83</span> MBytes  <span class="token number">73.8</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">7.00</span>-8.00   sec  <span class="token number">6.21</span> MBytes  <span class="token number">52.1</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">8.00</span>-9.00   sec  <span class="token number">12.4</span> MBytes   <span class="token number">104</span> Mbits/sec<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">9.00</span>-10.00  sec  <span class="token number">8.86</span> MBytes  <span class="token number">74.0</span> Mbits/sec- - - - - - - - - - - - - - - - - - - - - - - - -<span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bandwidth       Retr<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec   <span class="token number">103</span> MBytes  <span class="token number">86.1</span> Mbits/sec  <span class="token number">4590</span>             sender<span class="token punctuation">[</span>  <span class="token number">4</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec  <span class="token number">99.5</span> MBytes  <span class="token number">83.4</span> Mbits/sec                  receiveriperf Done.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>策略生效。</p><h5 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h5><p>本次操作的限速规则可以理解成下面的一种树状结构:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">root qdisc └─ pfifo_fast qdisc <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">0</span>:1<span class="token punctuation">)</span>     ├─ tbf qdisc <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:2<span class="token punctuation">)</span>     │   └─ cls match <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:2 qdisc <span class="token number">10</span>:<span class="token punctuation">)</span> <span class="token punctuation">(</span>pkttype 0x0800 prio <span class="token number">0</span> TCP,to<span class="token operator">=</span><span class="token number">0.0</span>.0.0-0.0.0.0:12334-12334,oif<span class="token operator">=</span>dpdk0<span class="token punctuation">)</span> <span class="token punctuation">(</span>target <span class="token number">10</span>:<span class="token punctuation">)</span>     ├─ tbf qdisc <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:2<span class="token punctuation">)</span>     │   └─ cls match <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:2 qdisc <span class="token number">20</span>:<span class="token punctuation">)</span> <span class="token punctuation">(</span>pkttype 0x0800 prio <span class="token number">0</span> TCP,to<span class="token operator">=</span><span class="token number">192.168</span>.7.27-192.168.7.27:12335-12335,oif<span class="token operator">=</span>dpdk0<span class="token punctuation">)</span> <span class="token punctuation">(</span>target <span class="token number">20</span>:<span class="token punctuation">)</span>     ├─ tbf qdisc <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:3<span class="token punctuation">)</span>     │   └─ cls match <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:3 qdisc <span class="token number">30</span>:<span class="token punctuation">)</span> <span class="token punctuation">(</span>pkttype 0x0800 prio <span class="token number">0</span> TCP,to<span class="token operator">=</span><span class="token number">192.168</span>.7.95-192.168.7.95:12335-12335,oif<span class="token operator">=</span>dpdk0<span class="token punctuation">)</span> <span class="token punctuation">(</span>target <span class="token number">30</span>:<span class="token punctuation">)</span>     ├─ tbf qdisc <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:4<span class="token punctuation">)</span>     │   └─ cls match <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:4 qdisc <span class="token number">40</span>:<span class="token punctuation">)</span> <span class="token punctuation">(</span>pkttype 0x0800 prio <span class="token number">0</span> TCP,from<span class="token operator">=</span><span class="token number">192.168</span>.7.182-192.168.7.182:12335-12335,oif<span class="token operator">=</span>dpdk0<span class="token punctuation">)</span> <span class="token punctuation">(</span>target <span class="token number">40</span>:<span class="token punctuation">)</span>     ├─ tbf qdisc <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:5<span class="token punctuation">)</span>     │   └─ cls match <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:5 qdisc <span class="token number">50</span>:<span class="token punctuation">)</span> <span class="token punctuation">(</span>pkttype 0x0800 prio <span class="token number">0</span> TCP,from<span class="token operator">=</span><span class="token number">192.168</span>.7.183-192.168.7.183:12335-12335,oif<span class="token operator">=</span>dpdk0<span class="token punctuation">)</span> <span class="token punctuation">(</span>target <span class="token number">50</span>:<span class="token punctuation">)</span>     ├─ pfifo qdisc <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">1</span>:6<span class="token punctuation">)</span> <span class="token punctuation">(</span>limit <span class="token number">100000</span><span class="token punctuation">)</span>     └─ bfifo qdisc <span class="token punctuation">(</span>dev dpdk0 parent <span class="token number">0</span>:5<span class="token punctuation">)</span> <span class="token punctuation">(</span>cls <span class="token number">5</span> limit <span class="token number">10000000</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>从上面的结构可以看出，即便流量方向都是 <code>egress</code> ，但你仍可以根据 <code>from</code> 或 <code>to</code> 的方式实现出入站的限速策略。</p><p><strong>写在最后</strong></p><p>生产环境中，应该将 <code>ingress</code> 和 <code>egress</code> 分开配置，但本篇主要仅做功能介绍，仅提供一个配置思路。</p><hr><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://tldp.org/HOWTO/Traffic-Control-HOWTO/elements.html#e-shaping">Traditional Elements of Traffic Control</a></p><p><a href="https://blog.csdn.net/dog250/article/details/40483627">Linux TC(Traffic Control)框架原理解析 - CSDN</a></p><p><a href="https://www.jianshu.com/p/4477c68c9ec4">TC限速实践 - 简书</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;基本信息&quot;&gt;&lt;a href=&quot;#基本信息&quot; class=&quot;headerlink&quot; title=&quot;基本信息&quot;&gt;&lt;/a&gt;基本信息&lt;/h2&gt;&lt;h3 id=&quot;版本支持&quot;&gt;&lt;a href=&quot;#版本支持&quot; class=&quot;headerlink&quot; title=&quot;版本支持&quot;&gt;&lt;/a</summary>
      
    
    
    
    <category term="network" scheme="https://nestealin.com/categories/network/"/>
    
    
    <category term="dpvs" scheme="https://nestealin.com/tags/dpvs/"/>
    
    <category term="tc" scheme="https://nestealin.com/tags/tc/"/>
    
    <category term="traffic control" scheme="https://nestealin.com/tags/traffic-control/"/>
    
    <category term="限速" scheme="https://nestealin.com/tags/%E9%99%90%E9%80%9F/"/>
    
    <category term="流控" scheme="https://nestealin.com/tags/%E6%B5%81%E6%8E%A7/"/>
    
  </entry>
  
  <entry>
    <title>在CentOS7搭建PPTP-VPN服务及客户端配置</title>
    <link href="https://nestealin.com/b47c18ed/"/>
    <id>https://nestealin.com/b47c18ed/</id>
    <published>2023-02-04T14:38:05.000Z</published>
    <updated>2024-06-29T07:26:38.949Z</updated>
    
    <content type="html"><![CDATA[<h2 id="服务端部署"><a href="#服务端部署" class="headerlink" title="服务端部署"></a>服务端部署</h2><h3 id="环境检查"><a href="#环境检查" class="headerlink" title="环境检查"></a>环境检查</h3><p>查看系统是否支持PPTP</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">modprobe ppp-compress-18 <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">echo</span> success<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>应该输出：success</p><p>查看系统是否开启TUN/TAP</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">cat</span> /dev/net/tun<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>应该输出：<code>cat: /dev/net/tun: File descriptor in bad state</code></p><p>是否开启ppp</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">cat</span> /dev/ppp<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>应该输出：<code>cat: /dev/ppp: No such device or address</code></p><p>如果环境不满足上面3个条件，表示很可能不支持 pptp 。</p><p>例外：linode的 xen 、kvm 服务器，也是支持的 pptp 的。可能是 linode 内核是定制的，并不是外部 ko 模块，与原版 CentOS 表现有所不一致。</p><h3 id="环境安装"><a href="#环境安装" class="headerlink" title="环境安装"></a>环境安装</h3><h4 id="安装必要包"><a href="#安装必要包" class="headerlink" title="安装必要包"></a>安装必要包</h4><p>首先安装 epel 源</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yum <span class="token function">install</span> -y epel-release<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>安装 pptp 相关包</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yum <span class="token function">install</span> pptpd net-tools iptables-services -y<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h4 id="修改相关配置文件"><a href="#修改相关配置文件" class="headerlink" title="修改相关配置文件"></a>修改相关配置文件</h4><ul><li>以下修改涉及三个主要配置:<ul><li>主服务配置文件 <code>/etc/pptpd.conf</code></li><li>DNS等选项配置文件 <code>/etc/ppp/options.pptpd</code></li><li>用户授权配置文件 <code>/etc/ppp/chap-secrets</code></li></ul></li></ul><h5 id="1-主配置"><a href="#1-主配置" class="headerlink" title="1. 主配置"></a>1. 主配置</h5><blockquote><p><code>/etc/pptpd.conf</code></p></blockquote><p>结尾处增加如下两行，分别是 pptp 服务的虚拟网段网关，及分配给客户端的地址范围。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">localip <span class="token number">192.168</span>.9.1remoteip <span class="token number">192.168</span>.9.101-199<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h5 id="2-DNS配置"><a href="#2-DNS配置" class="headerlink" title="2. DNS配置"></a>2. DNS配置</h5><blockquote><p><code>/etc/ppp/options.pptpd</code></p></blockquote><p>结尾增加两行，给虚拟网段用的 dns 服务，可以使用主机商提供的 dns 服务器地址或公共 dns 。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">ms-dns <span class="token number">223.5</span>.5.5ms-dns <span class="token number">119.29</span>.29.29<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>如果是 linode 等海外服务器，可以使用谷歌的公共 dns 服务器地址</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">ms-dns <span class="token number">8.8</span>.8.8ms-dns <span class="token number">8.8</span>.4.4<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h5 id="3-用户授权配置"><a href="#3-用户授权配置" class="headerlink" title="3. 用户授权配置"></a>3. 用户授权配置</h5><blockquote><p><code>/etc/ppp/chap-secrets</code></p></blockquote><p>每行代表一套帐号，该文件默认有简短说明。</p><p>示例如下，以<strong>空格</strong>或者<strong>tab</strong>分隔的4个字段：分别是用户名、服务器名称、密码、客户端IP地址，其中第二和第四字段可以是星号。</p><blockquote><p>注意:</p><ol><li>服务器名 ( pptpd ) 不要随意修改, 如果修改请确保与 <code>/etc/pptpd.conf</code> 中的 <code>name</code> 保持一致。</li><li>最末的 <code>*</code> 代表客户端的 ip 地址由 pptpd 自动分配。</li></ol></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># client  server  secret  IP addresses</span>vpntest pptpd <span class="token number">111222333</span> *<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h4 id="开启iP转发"><a href="#开启iP转发" class="headerlink" title="开启iP转发"></a>开启iP转发</h4><p>编辑 <code>/etc/sysctl.conf</code> 文件</p><blockquote><p>修改配置前可以先执行 <code>sysctl -a | grep &quot;net.ipv4.ip_forward&quot;</code> 进行确认。</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment">#将“net.ipv4.ip_forward”改为1，开启ip转发。这个不是必须的</span>net.ipv4.ip_forward<span class="token operator">=</span><span class="token number">1</span><span class="token comment">#同时注释掉 “net.ipv4.tcp_syncookies = 1” (前面加#)</span><span class="token comment"># net.ipv4.tcp_syncookies = 1</span><span class="token comment">#保存退出`sysctl.conf`文件编辑后，运行下面的命令，能让设置立即生效 </span>sysctl -p<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="启动服务"><a href="#启动服务" class="headerlink" title="启动服务"></a>启动服务</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 启动服务</span><span class="token function">service</span> pptpd start<span class="token function">service</span> pptpd status<span class="token comment"># 添加到开机自启</span>systemctl enabled pptpd<span class="token comment">#启动服务后，可能通过系统日志查看运行情况</span>tailf /var/log/messages<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>至此，已完成服务端的基本部署工作。</p><h3 id="进阶配置"><a href="#进阶配置" class="headerlink" title="进阶配置"></a>进阶配置</h3><blockquote><p>以下配置为可选配置，可根据实际情况进行配置。</p></blockquote><h4 id="修改MTU"><a href="#修改MTU" class="headerlink" title="修改MTU"></a>修改MTU</h4><ol><li><p>输入执行 <code>vi /etc/ppp/ip-up</code> 命令，进入 <code>/etc/ppp/ip-up</code> 文件中。</p></li><li><p>在 <code>/etc/ppp/ip-up</code> 文件中添加 <code>ifconfig ppp1 mtu 1320</code> 命令。</p><p>回显如下图所示，表示命令添加成功。 <img src="/b47c18ed/8f92033d9a4e439589fb4b16c06f2763.png" class=""></p></li></ol><h4 id="公网放行及传输优化"><a href="#公网放行及传输优化" class="headerlink" title="公网放行及传输优化"></a>公网放行及传输优化</h4><p>如果服务器处于公网，还要对 PPTP 服务端口进行放行。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token shebang important">#!/bin/sh</span><span class="token comment"># 允许连接PPTP服务</span>iptables -I INPUT -p tcp --dport <span class="token number">1723</span> -j ACCEPT<span class="token comment"># 允许建立VPN隧道以验证用户名密码</span>iptables -I INPUT -p gre -j ACCEPT<span class="token comment"># 建立NAT转换规则</span>iptables -t nat -I POSTROUTING -s <span class="token number">192.168</span>.9.0/24 -o eth0 -j MASQUERADE<span class="token comment"># 允许pptpd转发</span>iptables -I FORWARD -i ppp+ -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT<span class="token comment"># 优化网络数据传输速度</span>iptables -I FORWARD -p tcp --syn -i ppp+ -j TCPMSS --set-mss <span class="token number">1356</span><span class="token builtin class-name">echo</span> <span class="token string">"完成"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><hr><h2 id="客户端配置"><a href="#客户端配置" class="headerlink" title="客户端配置"></a>客户端配置</h2><h3 id="Windows"><a href="#Windows" class="headerlink" title="Windows"></a>Windows</h3><p>Windows 10自带VPN客户端</p><p>右键右下角电脑图标 “打开’网络和 Internet 设置’” <img src="/b47c18ed/f4d4c2c523fb46768d926350224cef71.png" class=""></p><p>先在左侧栏找到 VPN 然后进行 “添加 VPN 连接” <img src="/b47c18ed/43eb8a70973842718e063a4a844ad00d.png" class=""></p><p>根据提示进行填写，最后保存即可 <img src="/b47c18ed/7ccb62d5bdcb4069ab508caf073f2cc8.png" class=""></p><p>点击刚才添加的 VPN 进行连接 <img src="/b47c18ed/8f18a8b3287347fcb4ec466fb443e873.png" class="" title="1373f47b7379b5c4e7471087f5869723.png"></p><img src="/b47c18ed/1e52ea1cd88845c88240b5fc03c9b6ab.png" class=""><p>连接成功后即可正常使用。</p><h3 id="Linux"><a href="#Linux" class="headerlink" title="Linux"></a>Linux</h3><p><strong>配置CentOS PPTP客户端</strong></p><p>执行如下命令，安装PPTP软件包。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yum <span class="token function">install</span> -y ppp pptp pptp-setup<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>回显如下图所示，表示PPTP安装成功。 <img src="/b47c18ed/644fb9771c4349edbe61d9aa75b9dcc9.png" class=""></p><p>执行如下命令， 连接VPN服务端。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">pptpsetup --create <span class="token builtin class-name">test</span> --server <span class="token punctuation">[</span><span class="token variable">$IP</span><span class="token punctuation">]</span> --username <span class="token punctuation">[</span><span class="token variable">$User</span><span class="token punctuation">]</span> --password <span class="token punctuation">[</span><span class="token variable">$Password</span><span class="token punctuation">]</span> --encrypt --start<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><blockquote><p>说明:</p><p>[$IP] 、[$User] 、[$Password] 为 VPN 服务端的 IP 地址、用户名和密码。</p></blockquote><img src="/b47c18ed/2a16553eec834288b82233fff03cb725.png" class=""><p>回显如下图所示，表示已成功连接VPN服务端。</p><p>当系统提示已经被分配了 <code>192.168.0.234</code> 的客户端地址时，执行如下命令，可以看到 ppp0 网卡。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">ifconfig</span> <span class="token operator">|</span> <span class="token function">grep</span> -A <span class="token number">10</span> ppp<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>回显如下图所示，表示命令执行成功。 <img src="/b47c18ed/d8057104617645e0b8d7f50f53577b49.png" class=""></p><p>执行如下命令，增加默认路由。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">ip</span> route replace default dev ppp0<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>回显如下图所示，表示命令执行成功。 <img src="/b47c18ed/672ab273a97344908af2599d591f97d4.png" class=""></p><p>增加路由后，您就可以访问VPN服务器。</p><h3 id="OSX"><a href="#OSX" class="headerlink" title="OSX"></a>OSX</h3><p>高版本下已经移除系统自带，需要另寻客户端。</p><h3 id="MikroTik"><a href="#MikroTik" class="headerlink" title="MikroTik"></a>MikroTik</h3><p>主界面找到 PPP</p><img src="/b47c18ed/93b02715f58547588a05cea7cdb59483.png" class=""><p>选择 PPTP Client <img src="/b47c18ed/2fd04e9e5c4e400ba522be5ac53adb9a.png" class=""></p><p>在 General 下配置合适 MTU <img src="/b47c18ed/16982bae4aba4feb9725a5740d284031.png" class=""></p><p>在 Dial Out 种配置服务端iP地址/域名、用户名、密码 <img src="/b47c18ed/ec3bd619ca3946a4b8a3388339369d1f.png" class=""></p><p>出现前缀状态 R 代表连接成功 <img src="/b47c18ed/1784f95e5d3548ed86a75590a8b8f925.png" class=""></p><p>可以在 Status 中进行状态确认 <img src="/b47c18ed/64739610cae8495caa09c637d258d476.png" class=""></p><p>此后，就可以进行自定义路由配置 <img src="/b47c18ed/81dbc6f2a2484df688b8c637f96ce05d.png" class=""></p><hr><h2 id="可能遇到的问题"><a href="#可能遇到的问题" class="headerlink" title="可能遇到的问题"></a>可能遇到的问题</h2><ol><li>Windows客户端可以进行DNS解析、HTTP访问，但HTTPS页面加载卡住</li></ol><ul><li><p>原因:</p><p>Windows本机网卡与服务端 <code>pppX</code> 网卡的 mtu 值不匹配。</p></li><li><p>排查方式:</p><ul><li>服务端 <code>ip a</code> 下确认 网卡对应 mtu 值 <img src="/b47c18ed/e7ce50cc33e040398048a73db5655385.png" class=""></li><li>客户端在 <strong>管理员cmd</strong> 下运行 <code>netsh interface ipv4 show subinterfaces</code> 查看 VPN 网卡的 mtu 值。 <img src="/b47c18ed/5888406f5b8a4337ae9e1bf2c7e79c26.png" class=""> <img src="/b47c18ed/8346b4a1f70147e6bb8cec4e4c39948d.png" class=""></li></ul></li><li><p>解决方式:</p><ul><li>客户端方式:<ul><li>在 <strong>管理员cmd</strong> 下运行 <code>netsh interface ipv4 set subinterface &quot;192.168.7.95&quot; mtu=1300 store=persistent</code> 以此保证客户端 mtu <strong>小于或等于</strong>服务端 mtu 即可。</li><li>然后再次验证当前 mtu 与网页加载。 <img src="/b47c18ed/18450fe05a13414fbce089f22e41af56.png" class=""></li></ul></li><li>服务端方式:<ul><li>详见文中 “进阶配置” – “修改MTU” 。</li></ul></li></ul></li></ul><hr><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://help.aliyun.com/document_detail/41345.html">如何使用CentOS 7实例配置PPTP VPN服务端到客户端的连接</a></p><p><a href="https://sandy1890.github.io/2016/10/23/pptpd_iptables/">CentOS 7 使用 pptpd 搭建 VPN 的 iptables 配置</a></p><p><a href="https://superuser.com/questions/1350485/ssl-does-not-work-on-windows-10-against-rutracker-org-via-pptp-but-works-with-l">SSL does not work on Windows 10 against rutracker.org via PPTP, but works with L2TP</a></p><p><a href="https://www.surfacex.cn/tu/IzJ6VqzaZmyNJ3maJ3bAz3Ze.html">Windows10自带VPN客户端怎么连接PPTP VPN（Windows10 VPN客户端使用图文教程）</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;服务端部署&quot;&gt;&lt;a href=&quot;#服务端部署&quot; class=&quot;headerlink&quot; title=&quot;服务端部署&quot;&gt;&lt;/a&gt;服务端部署&lt;/h2&gt;&lt;h3 id=&quot;环境检查&quot;&gt;&lt;a href=&quot;#环境检查&quot; class=&quot;headerlink&quot; title=&quot;环境检查&quot;</summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="pptp" scheme="https://nestealin.com/tags/pptp/"/>
    
    <category term="vpn" scheme="https://nestealin.com/tags/vpn/"/>
    
    <category term="tunnel" scheme="https://nestealin.com/tags/tunnel/"/>
    
    <category term="隧道" scheme="https://nestealin.com/tags/%E9%9A%A7%E9%81%93/"/>
    
  </entry>
  
  <entry>
    <title>在shell中判断端口开启的几种方法</title>
    <link href="https://nestealin.com/5cfb5f71/"/>
    <id>https://nestealin.com/5cfb5f71/</id>
    <published>2023-01-14T13:33:38.000Z</published>
    <updated>2024-06-29T07:26:38.965Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>平时单独检查目标主机端口是否打开，可能会用如下两种方式验证:</p><p>方式一，直接使用 <code>telnet</code> 命令，但如果端口连通后会让窗口挂起，无法自行退出</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">telnet www.baidu.com <span class="token number">80</span><span class="token comment"># >>> 终端输出</span>Trying <span class="token number">14.215</span>.177.38<span class="token punctuation">..</span>.Connected to www.a.shifen.com.Escape character is <span class="token string">'^]'</span><span class="token builtin class-name">.</span>^<span class="token punctuation">]</span>  <span class="token comment"># 需要自行执行 Command+] 进行关闭</span>telnet<span class="token operator">></span> quit<span class="token comment"># 并输入 quit 退出连接</span>Connection closed.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>方式二，使用管道 + <code>telnet</code> 命令，即可实现单行执行</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">echo</span> <span class="token string">""</span> <span class="token operator">|</span> telnet www.baidu.com <span class="token number">80</span><span class="token comment"># >>> 终端输出</span>Trying <span class="token number">14.215</span>.177.38<span class="token punctuation">..</span>.Connected to www.baidu.com.Escape character is <span class="token string">'^]'</span><span class="token builtin class-name">.</span>Connection closed by foreign host.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>但一般在 Shell 脚本中往往只需要获取其最终的状态即可，无需观察其连接过程；</p><p>所以本次我们将用多种命令分别来实现端口通断的检测，可用于单行检测与脚本检测。</p><hr><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><h3 id="单行检测"><a href="#单行检测" class="headerlink" title="单行检测"></a>单行检测</h3><h4 id="telnet命令单行执行"><a href="#telnet命令单行执行" class="headerlink" title="telnet命令单行执行"></a>telnet命令单行执行</h4><blockquote><p>shell中需要在下一行使用 <code>echo $?</code> 获取上一行执行结果状态</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">echo</span> <span class="token string">""</span> <span class="token operator">|</span> telnet www.baidu.com <span class="token number">80</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h4 id="nc命令单行执行与带结果输出"><a href="#nc命令单行执行与带结果输出" class="headerlink" title="nc命令单行执行与带结果输出"></a>nc命令单行执行与带结果输出</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 单纯执行，成功状态码0，失败状态码1</span><span class="token function">nc</span> -z -w <span class="token number">5</span> www.baidu.com <span class="token number">80</span><span class="token punctuation">;</span> <span class="token builtin class-name">echo</span> <span class="token variable">$?</span><span class="token comment"># 带结果输出</span><span class="token function">nc</span> -z -w <span class="token number">5</span> www.baidu.com <span class="token number">80</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">echo</span> OK <span class="token operator">||</span> <span class="token builtin class-name">echo</span> Failed<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="bash命令单行执行与带结果输出"><a href="#bash命令单行执行与带结果输出" class="headerlink" title="bash命令单行执行与带结果输出"></a>bash命令单行执行与带结果输出</h4><blockquote><p>bash自身包含的一种方式： <code>/dev/tcp/host/port</code> 和 <code>/dev/udp/host/port</code></p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 单纯执行，成功状态码0，失败状态码1，超时状态码124</span><span class="token function">timeout</span> <span class="token number">5</span> <span class="token function">bash</span> -c <span class="token string">"echo >/dev/tcp/www.baidu.com/180"</span> <span class="token operator">></span> /dev/null <span class="token operator"><span class="token file-descriptor important">2</span>></span><span class="token file-descriptor important">&amp;1</span> <span class="token punctuation">;</span> <span class="token builtin class-name">echo</span> <span class="token variable">$?</span><span class="token comment"># 带结果输出</span><span class="token comment"># 注意: MACOS 下没有 timeout 命令</span><span class="token function">timeout</span> <span class="token number">5</span> <span class="token function">bash</span> -c <span class="token string">"echo >/dev/tcp/www.baidu.com/80"</span> <span class="token operator">></span> /dev/null <span class="token operator"><span class="token file-descriptor important">2</span>></span><span class="token file-descriptor important">&amp;1</span> <span class="token operator">&amp;&amp;</span> <span class="token builtin class-name">echo</span> <span class="token string">"port 80 is open"</span> <span class="token operator">||</span> <span class="token builtin class-name">echo</span> <span class="token string">"port 80 is closed"</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>在这里，<code>timeout</code> 会运行其后的子命令，若在指定的超时时间还未完成的话， <code>timeout</code> 会 kill 掉子命令对应的进程。在这种情况下，<code>bash</code> 就是一个子命令，用 <code>/dev/tcp</code> 的特殊方式尝试与目标主机的指定端口建连。</p><p>如果 <code>bash</code> 可以指定的超时时间内与目标主机端口建连，<code>cat</code> 会立即终止 ( 由于其是从 <code>/dev/null</code> 中读取内容 ) ，<code>bash</code> 命令接着也会执行完毕，最终返回一个 <strong>0</strong> 状态码。</p><p>若在超时时间范围内与目标主机端口建连失败，<code>bash</code> 会退出并与 <code>timeout</code> 一起返回一个 <strong>1</strong> 状态码。</p><p>若过了超时时间后 <code>bash</code> 还是无法成功建连，<code>timeout</code> 就会 <code>kill</code> 掉 <code>bash</code> 并返回一个 <strong>124</strong> 状态码。</p><h3 id="脚本检测"><a href="#脚本检测" class="headerlink" title="脚本检测"></a>脚本检测</h3><h4 id="根据执行状态码判断"><a href="#根据执行状态码判断" class="headerlink" title="根据执行状态码判断"></a>根据执行状态码判断</h4><p>利用 <code>nc</code> 、<code>/dev/tcp</code> 、<code>nmap</code> 三种方式的执行状态码判断端口通断。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token shebang important">#!/bin/bash</span><span class="token assign-left variable">SERVER</span><span class="token operator">=</span>www.baidu.com<span class="token assign-left variable">PORT</span><span class="token operator">=</span><span class="token number">80</span><span class="token comment"># 方式一</span><span class="token function">nc</span> -w <span class="token number">3</span> -z <span class="token variable">$SERVER</span> <span class="token variable">$PORT</span><span class="token comment"># 方式二</span><span class="token comment"># &lt;/dev/tcp/$SERVER/$PORT</span><span class="token comment"># 方法三，需要安装nmap，yum install -y nmap</span><span class="token comment"># nmap -p $PORT $SERVER</span><span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$?</span>"</span> -ne <span class="token number">0</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>  <span class="token builtin class-name">echo</span> <span class="token string">"Connection to <span class="token variable">$SERVER</span> on port <span class="token variable">$PORT</span> failed"</span>  <span class="token builtin class-name">exit</span> <span class="token number">1</span><span class="token keyword">else</span>  <span class="token builtin class-name">echo</span> <span class="token string">"Connection to <span class="token variable">$SERVER</span> on port <span class="token variable">$PORT</span> succeeded"</span>  <span class="token builtin class-name">exit</span> <span class="token number">0</span><span class="token keyword">fi</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="封装方法"><a href="#封装方法" class="headerlink" title="封装方法"></a>封装方法</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">vim</span> port_check.sh<span class="token comment">#!/bin/bash</span><span class="token keyword">function</span> <span class="token function-name function">check_port</span> <span class="token punctuation">&#123;</span>    <span class="token assign-left variable">status</span><span class="token operator">=</span><span class="token variable"><span class="token variable">`</span><span class="token function">nc</span> -w <span class="token number">3</span> -z www.baidu.com <span class="token number">80</span><span class="token punctuation">;</span> <span class="token builtin class-name">echo</span> $?<span class="token variable">`</span></span>    <span class="token builtin class-name">echo</span> <span class="token variable">$status</span>    <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$status</span>"</span> -eq <span class="token number">0</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>      <span class="token builtin class-name">echo</span> <span class="token string">"Success."</span>    <span class="token keyword">else</span>      <span class="token builtin class-name">echo</span> <span class="token string">"Failed."</span>    <span class="token keyword">fi</span><span class="token punctuation">&#125;</span>check_port<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>执行 <code>sh port_check.sh</code> ，输出如下:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">Connection to www.baidu.com port <span class="token number">80</span> <span class="token punctuation">[</span>tcp/http<span class="token punctuation">]</span> succeeded<span class="token operator">!</span><span class="token number">0</span>Success.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><hr><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://blog.csdn.net/whatday/article/details/105408608">linux shell 检查端口开放</a></p><p><a href="https://blog.51cto.com/xoyabc/1836353">shell中判断远程主机的某个tcp端口是否存活</a></p><p><a href="https://stackoverflow.com/questions/4922943/test-if-remote-tcp-port-is-open-from-a-shell-script">Test if remote TCP port is open from a shell script</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;平时单独检查目标主机端口是否打开，可能会用如下两种方式验证:&lt;/p&gt;
&lt;p&gt;方式一，直接使用 &lt;code&gt;telnet&lt;/code&gt; 命令，</summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="tcp端口" scheme="https://nestealin.com/tags/tcp%E7%AB%AF%E5%8F%A3/"/>
    
    <category term="udp端口" scheme="https://nestealin.com/tags/udp%E7%AB%AF%E5%8F%A3/"/>
    
    <category term="端口检测" scheme="https://nestealin.com/tags/%E7%AB%AF%E5%8F%A3%E6%A3%80%E6%B5%8B/"/>
    
    <category term="telnet" scheme="https://nestealin.com/tags/telnet/"/>
    
    <category term="nc" scheme="https://nestealin.com/tags/nc/"/>
    
    <category term="nmap" scheme="https://nestealin.com/tags/nmap/"/>
    
  </entry>
  
  <entry>
    <title>DPVS下管理及配置IPVS</title>
    <link href="https://nestealin.com/71c02569/"/>
    <id>https://nestealin.com/71c02569/</id>
    <published>2022-11-25T16:12:30.000Z</published>
    <updated>2024-06-29T07:26:38.744Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前置条件"><a href="#前置条件" class="headerlink" title="前置条件"></a>前置条件</h2><h3 id="DPIP配置"><a href="#DPIP配置" class="headerlink" title="DPIP配置"></a>DPIP配置</h3><p>通过dpip命令检查对应网卡是否已存在测试iP及路由。</p><blockquote><p>本文以100.96.122.212为测试SIP为例。</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 检查网卡IP</span>/usr/local/dpvs/bin/dpip addr show<span class="token comment"># 将SIP添加至dpdk0网卡上</span><span class="token comment"># 正常情况下，通过keepalived配置文件启动后，会自动调用dpip添加至网卡，无需手动添加</span>/usr/local/dpvs/bin/dpip addr <span class="token function">add</span> <span class="token number">100.96</span>.122.212 dev dpdk0<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>添加sip的同时，也会自动生成对应路由</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 查看路由</span>/usr/local/dpvs/bin/dpip route show<span class="token operator">>></span><span class="token operator">></span>inet <span class="token number">100.96</span>.122.212/32 via <span class="token number">0.0</span>.0.0 src <span class="token number">0.0</span>.0.0 dev dpdk0 mtu <span class="token number">1500</span> tos <span class="token number">0</span> scope <span class="token function">host</span> metric <span class="token number">0</span> proto auto<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="测试服务端说明"><a href="#测试服务端说明" class="headerlink" title="测试服务端说明"></a>测试服务端说明</h3><p>本次服务端为Nginx，通过内置变量来响应客户端请求信息。</p><p>参考配置</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span>  <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span>  test.nestealin.com</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">charset</span> utf-8</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">access_log</span>  logs/test.nestealin.com.access.main.log  main</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">error_log</span>  logs/test.nestealin.com.error.log error</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">&#123;</span>      <span class="token directive"><span class="token keyword">add_header</span> Content-Type application/json</span> <span class="token punctuation">;</span>      <span class="token directive"><span class="token keyword">return</span> <span class="token number">200</span> <span class="token string">'&#123;"remote_addr":"<span class="token variable">$remote_addr</span>","remote_port":"<span class="token variable">$remote_port</span>","clientRealIp":"<span class="token variable">$clientRealIp</span>","time_local":"<span class="token variable">$time_local</span>"&#125;'</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>  <span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><hr><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><h3 id="1-添加SIP-Service-iP-Service-Address"><a href="#1-添加SIP-Service-iP-Service-Address" class="headerlink" title="1. 添加SIP(Service iP / Service-Address)"></a>1. 添加SIP(Service iP / Service-Address)</h3><blockquote><p>如下参数解读: rr 模式，支持 synproxy 的 SIP 100.96.122.212 监听 80 端口</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 支持synproxy的rr模式</span>/usr/local/dpvs/bin/ipvsadm -A -t <span class="token number">100.96</span>.122.212:80 -s rr -j <span class="token builtin class-name">enable</span><span class="token comment"># wrr模式</span><span class="token comment"># 支持synproxy的rr模式，不支持synproxy</span>/usr/local/dpvs/bin/ipvsadm -A -t <span class="token number">100.96</span>.122.212:80 -s wrr<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li><strong>注意:</strong> SIP监听端口必须与RS端口保持一致，无法差异映射。</li><li>synproxy模式管理: <ul><li>参数: <code>-j</code> | <code>--synproxy</code></li><li>FLAG: enable | disable ( default: disable )</li></ul></li></ul><h3 id="2-添加RS-Real-Server"><a href="#2-添加RS-Real-Server" class="headerlink" title="2. 添加RS(Real Server)"></a>2. 添加RS(Real Server)</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 监听80端口，权重20</span>/usr/local/dpvs/bin/ipvsadm -a -t <span class="token number">100.96</span>.122.212:80 -r <span class="token number">192.168</span>.7.27:80 -w <span class="token number">20</span> -b<span class="token comment"># 监听443端口，权重10</span>/usr/local/dpvs/bin/ipvsadm  -a -t <span class="token number">100.96</span>.122.212:443 -r <span class="token number">192.168</span>.10.2:443 -w <span class="token number">10</span> -b<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>FULLNAT模式管理: <ul><li>参数:  <code>-b</code> | <code>--fullnat</code></li></ul></li></ul><h3 id="3-添加LIP-Local-iP-Local-Address"><a href="#3-添加LIP-Local-iP-Local-Address" class="headerlink" title="3. 添加LIP(Local iP/Local-Address)"></a>3. 添加LIP(Local iP/Local-Address)</h3><p>即SNAT-iP，用于向RS转发时用的ip。</p><blockquote><p>注意，LIP需要与RS在同一通信子网中，否则会造成转发失败。</p></blockquote><p>由于 RS 的 CIDR 为 192.168.7.0/24 ，所以本次实验采用统一子网iP作为LiP。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 语法</span>ipvsadm -P -t service-address:port -z local-address:port<span class="token comment"># 例如</span>/usr/local/dpvs/bin/ipvsadm -P -t <span class="token number">100.96</span>.122.212:80 -z <span class="token number">192.168</span>.7.233 -F dpdk0/usr/local/dpvs/bin/ipvsadm -P -t <span class="token number">100.96</span>.122.212:80 -z <span class="token number">192.168</span>.7.234 -F dpdk0<span class="token comment"># 确认当前LIP</span>/usr/local/dpvs/bin/ipvsadm -G -t <span class="token number">100.96</span>.122.212:80VIP:VPORT            TOTAL    SNAT_IP              CONFLICTS  CONNS<span class="token number">100.96</span>.122.212:80    <span class="token number">2</span>                              <span class="token number">192.168</span>.7.233        <span class="token number">0</span>          <span class="token number">0</span>                              <span class="token number">192.168</span>.7.234        <span class="token number">0</span>          <span class="token number">0</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>以上，添加了两个转发IP。</p><h3 id="4-测试验证"><a href="#4-测试验证" class="headerlink" title="4. 测试验证"></a>4. 测试验证</h3><blockquote><p> 本次实验采取静态路由方式验证，线上可考虑ospf、bgp等方式宣告SIP。</p></blockquote><p>登陆客户端机器，配置静态路由，并验证请求。</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 添加静态路由</span>route <span class="token function">add</span> -host <span class="token number">100.96</span>.122.210 gw <span class="token number">192.168</span>.7.82 dev eth0<span class="token comment"># 验证请求</span><span class="token comment"># curl 100.96.122.212</span><span class="token punctuation">&#123;</span><span class="token string">"remote_addr"</span><span class="token builtin class-name">:</span><span class="token string">"192.168.7.233"</span>,<span class="token string">"remote_port"</span><span class="token builtin class-name">:</span><span class="token string">"1037"</span>,<span class="token string">"clientRealIp"</span><span class="token builtin class-name">:</span><span class="token string">"192.168.7.233"</span>,<span class="token string">"time_local"</span><span class="token builtin class-name">:</span><span class="token string">"25/Nov/2022:22:40:42 +0800"</span><span class="token punctuation">&#125;</span><span class="token comment"># curl 100.96.122.212</span><span class="token punctuation">&#123;</span><span class="token string">"remote_addr"</span><span class="token builtin class-name">:</span><span class="token string">"192.168.7.234"</span>,<span class="token string">"remote_port"</span><span class="token builtin class-name">:</span><span class="token string">"1037"</span>,<span class="token string">"clientRealIp"</span><span class="token builtin class-name">:</span><span class="token string">"192.168.7.234"</span>,<span class="token string">"time_local"</span><span class="token builtin class-name">:</span><span class="token string">"25/Nov/2022:22:40:45 +0800"</span><span class="token punctuation">&#125;</span><span class="token comment"># curl 100.96.122.212</span><span class="token punctuation">&#123;</span><span class="token string">"remote_addr"</span><span class="token builtin class-name">:</span><span class="token string">"192.168.7.233"</span>,<span class="token string">"remote_port"</span><span class="token builtin class-name">:</span><span class="token string">"1034"</span>,<span class="token string">"clientRealIp"</span><span class="token builtin class-name">:</span><span class="token string">"192.168.7.233"</span>,<span class="token string">"time_local"</span><span class="token builtin class-name">:</span><span class="token string">"25/Nov/2022:22:40:47 +0800"</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>可以看出，分别使用了192.168.7.233、192.168.7.234两个LiP进行转发，请求Nginx。</p><blockquote><p>如果需要获取源客户端IP信息，则需要在Nginx侧安装并启用TOA插件。</p></blockquote><hr><h2 id="ipvsadm-常用命令说明"><a href="#ipvsadm-常用命令说明" class="headerlink" title="ipvsadm-常用命令说明"></a>ipvsadm-常用命令说明</h2><h3 id="连接管理"><a href="#连接管理" class="headerlink" title="连接管理"></a>连接管理</h3><h4 id="查看SIP连接、转发状态"><a href="#查看SIP连接、转发状态" class="headerlink" title="查看SIP连接、转发状态"></a>查看SIP连接、转发状态</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/dpvs/bin/ipvsadm -Ln<span class="token operator">>></span><span class="token operator">></span>IP Virtual Server version <span class="token number">0.0</span>.0 <span class="token punctuation">(</span>size<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">)</span>Prot LocalAddress:Port Scheduler Flags  -<span class="token operator">></span> RemoteAddress:Port           Forward Weight ActiveConn InActConnTCP  <span class="token number">100.96</span>.122.210:80 rr synproxy  -<span class="token operator">></span> <span class="token number">192.168</span>.7.27:80              FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span>TCP  <span class="token number">100.96</span>.122.212:80 rr synproxy  -<span class="token operator">></span> <span class="token number">192.168</span>.7.27:80              FullNat <span class="token number">10</span>     <span class="token number">0</span>          <span class="token number">0</span>TCP  <span class="token number">192.168</span>.7.182:80 rr synproxy  -<span class="token operator">></span> <span class="token number">192.168</span>.7.81:80              FullNat <span class="token number">100</span>    <span class="token number">0</span>          <span class="token number">0</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="查看当前所有连接状态"><a href="#查看当前所有连接状态" class="headerlink" title="查看当前所有连接状态"></a>查看当前所有连接状态</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/dpvs/bin/ipvsadm -l -c -n<span class="token operator">>></span><span class="token operator">></span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>tcp 7s     TIME_WAIT   <span class="token number">192.168</span>.7.95:55500 <span class="token number">100.96</span>.122.212:80  <span class="token number">192.168</span>.7.233:1048 <span class="token number">192.168</span>.7.27:80<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>tcp 7s     TIME_WAIT   <span class="token number">192.168</span>.7.95:55492 <span class="token number">100.96</span>.122.212:80  <span class="token number">192.168</span>.7.233:1040 <span class="token number">192.168</span>.7.27:80<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span>tcp 7s     TIME_WAIT   <span class="token number">192.168</span>.7.95:55496 <span class="token number">100.96</span>.122.212:80  <span class="token number">192.168</span>.7.233:1044 <span class="token number">192.168</span>.7.27:80<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span>tcp 7s     TIME_WAIT   <span class="token number">192.168</span>.7.95:55494 <span class="token number">100.96</span>.122.212:80  <span class="token number">192.168</span>.7.233:1049 <span class="token number">192.168</span>.7.27:80<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span>tcp 7s     TIME_WAIT   <span class="token number">192.168</span>.7.95:55498 <span class="token number">100.96</span>.122.212:80  <span class="token number">192.168</span>.7.233:1053 <span class="token number">192.168</span>.7.27:80<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="查看包吞吐速率"><a href="#查看包吞吐速率" class="headerlink" title="查看包吞吐速率"></a>查看包吞吐速率</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/dpvs/bin/ipvsadm -l --rate<span class="token operator">>></span><span class="token operator">></span>IP Virtual Server version <span class="token number">0.0</span>.0 <span class="token punctuation">(</span>size<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">)</span>Prot LocalAddress:Port                 CPS    InPPS   OutPPS    InBPS   OutBPS  -<span class="token operator">></span> RemoteAddress:PortTCP  <span class="token number">100.96</span>.122.210:http                 <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>  -<span class="token operator">></span> <span class="token number">192.168</span>.7.27:http                   <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>TCP  <span class="token number">100.96</span>.122.212:http                 <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>  -<span class="token operator">></span> <span class="token number">192.168</span>.7.27:http                   <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>TCP  <span class="token number">192.168</span>.7.182:http                  <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>  -<span class="token operator">></span> homelab_inspur_node01:http          <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span>        <span class="token number">0</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="SIP管理"><a href="#SIP管理" class="headerlink" title="SIP管理"></a>SIP管理</h3><h4 id="添加SIP"><a href="#添加SIP" class="headerlink" title="添加SIP"></a>添加SIP</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 语法</span>/usr/local/dpvs/bin/ipvsadm -A -t service-address<span class="token punctuation">(</span>SIP<span class="token punctuation">)</span>:port <span class="token punctuation">[</span>-s scheduler<span class="token punctuation">]</span> <span class="token punctuation">[</span>-j eanble/disable<span class="token punctuation">]</span> <span class="token punctuation">[</span>-p <span class="token punctuation">[</span>timeout<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>-M netmask<span class="token punctuation">]</span> <span class="token punctuation">[</span>--pe persistence_engine<span class="token punctuation">]</span><span class="token comment"># 更多参数详见 -h 输出</span>Options:  --scheduler    -s scheduler         one of rr<span class="token operator">|</span>wrr<span class="token operator">|</span>lc<span class="token operator">|</span>wlc<span class="token operator">|</span>lblc<span class="token operator">|</span>lblcr<span class="token operator">|</span>dh<span class="token operator">|</span><span class="token function">sh</span><span class="token operator">|</span><span class="token function">sed</span><span class="token operator">|</span>nq,                                      the default scheduler is wlc.  <span class="token punctuation">..</span>.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>例子</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 以rr轮询方式，添加SIP，并开启synproxy</span>/usr/local/dpvs/bin/ipvsadm -A -t <span class="token number">100.96</span>.122.212:80 -s rr -j <span class="token builtin class-name">enable</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><h4 id="删除SIP"><a href="#删除SIP" class="headerlink" title="删除SIP"></a>删除SIP</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/dpvs/bin/ipvsadm -D -t<span class="token operator">|</span>u<span class="token operator">|</span>f service-address:port<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>例子</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/dpvs/bin/ipvsadm -D -t <span class="token number">100.96</span>.122.212:80<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="RS管理"><a href="#RS管理" class="headerlink" title="RS管理"></a>RS管理</h3><h4 id="添加后端-RS"><a href="#添加后端-RS" class="headerlink" title="添加后端/RS"></a>添加后端/RS</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 语法</span>/usr/local/dpvs/bin/ipvsadm -a<span class="token operator">|</span>e -t<span class="token operator">|</span>u<span class="token operator">|</span>q<span class="token operator">|</span>f service-address -r server-address <span class="token punctuation">[</span>options<span class="token punctuation">]</span><span class="token comment"># 更多参数详见 -h 输出</span>Options:  --gatewaying   -g                   gatewaying <span class="token punctuation">(</span>direct routing<span class="token punctuation">)</span> <span class="token punctuation">(</span>default<span class="token punctuation">)</span>  --ipip         -i                   ipip encapsulation <span class="token punctuation">(</span>tunneling<span class="token punctuation">)</span>  --fullnat      -b                   fullnat mode  --snat         -J                   SNAT mode  --masquerading -m                   masquerading <span class="token punctuation">(</span>NAT<span class="token punctuation">)</span>  <span class="token punctuation">..</span>.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>例子</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 为100.96.122.212:80这组SIP添加192.168.7.27:80</span><span class="token comment"># 设置权重为10并以fullnat方式转发</span>/usr/local/dpvs/bin/ipvsadm -a -t <span class="token number">100.96</span>.122.212:80 -r <span class="token number">192.168</span>.7.27:80 -w <span class="token number">10</span> -b<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h4 id="调整后端权重"><a href="#调整后端权重" class="headerlink" title="调整后端权重"></a>调整后端权重</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 语法</span>ipvsadm -e -t<span class="token operator">|</span>u<span class="token operator">|</span>f service-address<span class="token punctuation">(</span>SIP<span class="token punctuation">)</span>:port -r server-address<span class="token punctuation">(</span>RS<span class="token punctuation">)</span>:port <span class="token punctuation">[</span>options<span class="token punctuation">]</span><span class="token comment"># 更多参数详见 -h 输出</span>Options:  --tcp-service  -t service-address   service-address is host<span class="token punctuation">[</span>:port<span class="token punctuation">]</span>  --udp-service  -u service-address   service-address is host<span class="token punctuation">[</span>:port<span class="token punctuation">]</span>  --fwmark-service  -f fwmark         fwmark is an integer greater than zero  --weight       -w weight            capacity of real server<span class="token punctuation">..</span>.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>例子</p><blockquote><p>调整 1.1.1.4:443 入口的 192.168.10.2:443 后端权重为 10</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/dpvs/bin/ipvsadm -e -t <span class="token number">1.1</span>.1.4:443 -r <span class="token number">192.168</span>.10.2:443 -w <span class="token number">10</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h4 id="删除后端"><a href="#删除后端" class="headerlink" title="删除后端"></a>删除后端</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/dpvs/bin/ipvsadm -d -t <span class="token number">1.1</span>.1.4:443 -r <span class="token number">192.168</span>.10.2:443<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="LIP管理"><a href="#LIP管理" class="headerlink" title="LIP管理"></a>LIP管理</h3><h4 id="添加LIP"><a href="#添加LIP" class="headerlink" title="添加LIP"></a>添加LIP</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 语法</span>ipvsadm -P -t service-address:port -z local-address -F ifname<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>例子</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/dpvs/bin/ipvsadm -P -t <span class="token number">100.96</span>.122.212:80 -z <span class="token number">192.168</span>.7.233 -F dpdk0<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h4 id="查看SIP对应的LIP"><a href="#查看SIP对应的LIP" class="headerlink" title="查看SIP对应的LIP"></a>查看SIP对应的LIP</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 语法</span>ipvsadm -G -t service-address:port<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>例子</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/dpvs/bin/ipvsadm -G -t <span class="token number">100.96</span>.122.212:80<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h4 id="删除指定SIP的LIP"><a href="#删除指定SIP的LIP" class="headerlink" title="删除指定SIP的LIP"></a>删除指定SIP的LIP</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 语法</span>ipvsadm -Q -t service-address:port -z local-address -F ifname<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>例子</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/dpvs/bin/ipvsadm -Q -t <span class="token number">100.96</span>.122.212:80 -z <span class="token number">192.168</span>.7.234 -F dpdk0<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><hr><h2 id="可能遇到的问题"><a href="#可能遇到的问题" class="headerlink" title="可能遇到的问题"></a>可能遇到的问题</h2><h3 id="添加VIP后直接请求造成如下报错"><a href="#添加VIP后直接请求造成如下报错" class="headerlink" title="添加VIP后直接请求造成如下报错"></a>添加VIP后直接请求造成如下报错</h3><blockquote><p>来源于dpvs日志。</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">IPVS: dp_vs_synproxy_ack_rcv: ip_vs_schedule failedIPVS: dp_vs_synproxy_ack_rcv: syn_cookie check failed <span class="token assign-left variable">seq</span><span class="token operator">=</span><span class="token number">2834256631</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>原因是没有配置LIP</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 例如</span>/usr/local/dpvs/bin/ipvsadm -P -t <span class="token number">100.96</span>.122.212:80 -z <span class="token number">192.168</span>.7.234 -F dpdk0<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>添加后再次请求即可。</p><hr><h2 id="参考文档"><a href="#参考文档" class="headerlink" title="参考文档"></a>参考文档</h2><p><a href="https://blog.51cto.com/u_13599730/2312722">ipvsadm实用总结</a></p><p><a href="https://www.cnblogs.com/f-ck-need-u/p/8527125.html">应用负载均衡之LVS(三)：ipvsadm命令</a></p><p><a href="https://www.cnblogs.com/f-ck-need-u/p/7576137.html#lvs">LVS系列文章</a></p><p><a href="https://ieevee.com/tech/2015/12/09/fullnat-2.html">Fullnat系列（二）：如何使用fullnat</a> ( 需注意，与真实dpvs下的真实配置会有略微出入，仅供参考 )</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;前置条件&quot;&gt;&lt;a href=&quot;#前置条件&quot; class=&quot;headerlink&quot; title=&quot;前置条件&quot;&gt;&lt;/a&gt;前置条件&lt;/h2&gt;&lt;h3 id=&quot;DPIP配置&quot;&gt;&lt;a href=&quot;#DPIP配置&quot; class=&quot;headerlink&quot; title=&quot;DPIP配</summary>
      
    
    
    
    <category term="network" scheme="https://nestealin.com/categories/network/"/>
    
    
    <category term="lvs" scheme="https://nestealin.com/tags/lvs/"/>
    
    <category term="dpvs" scheme="https://nestealin.com/tags/dpvs/"/>
    
    <category term="ipvs" scheme="https://nestealin.com/tags/ipvs/"/>
    
    <category term="fullnat" scheme="https://nestealin.com/tags/fullnat/"/>
    
  </entry>
  
  <entry>
    <title>网络性能测试工具-iPerf3使用文档</title>
    <link href="https://nestealin.com/a53c4583/"/>
    <id>https://nestealin.com/a53c4583/</id>
    <published>2022-10-29T16:51:49.000Z</published>
    <updated>2024-06-29T07:26:38.980Z</updated>
    
    <content type="html"><![CDATA[<h2 id="下载安装"><a href="#下载安装" class="headerlink" title="下载安装"></a>下载安装</h2><h3 id="yum-安装"><a href="#yum-安装" class="headerlink" title="yum 安装"></a>yum 安装</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yum <span class="token function">install</span> -y ipef3<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h3 id="源码安装"><a href="#源码安装" class="headerlink" title="源码安装"></a>源码安装</h3><p>下载最新版本源码包，下载地址：<a href="http://downloads.es.net/pub/iperf/">http://downloads.es.net/pub/iperf/</a>。</p><blockquote><p>本文以安装 iperf-3.6.tar.gz 版本为例。</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">yum <span class="token function">install</span> <span class="token function">wget</span> gcc <span class="token function">make</span> -y<span class="token function">wget</span> https://downloads.es.net/pub/iperf/iperf-3.6.tar.gz<span class="token function">tar</span> -zxvf iperf-3.6.tar.gz<span class="token builtin class-name">cd</span> iperf-3.6./configure --prefix<span class="token operator">=</span>/usr/local/iperf<span class="token function">make</span> <span class="token operator">&amp;&amp;</span> <span class="token function">make</span> <span class="token function">install</span><span class="token function">ln</span> -s /usr/local/iperf/bin/iperf3 /usr/bin/iperf3<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><hr><h2 id="iperf介绍及详细使用"><a href="#iperf介绍及详细使用" class="headerlink" title="iperf介绍及详细使用"></a>iperf介绍及详细使用</h2><h3 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h3><p>Iperf 是一个网络性能测试工具。Iperf可以测试最大TCP和UDP带宽性能，具有多种参数和UDP特性，可以根据需要调整，可以报告带宽、延迟抖动和数据包丢失。</p><p><strong>iperf只支持千兆流量的测试，iperf3才支持万兆流量测试</strong></p><p>此外，iperf 分为两种版本:</p><ul><li>unix/linux版，更新比较快，版本最新</li><li>windows版，更新慢</li></ul><p>windows版的iperf叫jperf，或者xjperf。jperf是在iperf基础上开发了更好的UI和新的功能。</p><hr><h3 id="测试场景"><a href="#测试场景" class="headerlink" title="测试场景"></a>测试场景</h3><h4 id="TCP方面"><a href="#TCP方面" class="headerlink" title="TCP方面"></a>TCP方面</h4><ol><li><p>测试网络带宽。</p></li><li><p>支持多线程，在客户端与服务端支持多重连接。</p></li><li><p>报告MSS/MTU值的大小。</p></li><li><p>支持TCP窗口值自定义并可通过套接字缓冲。</p></li></ol><h4 id="UDP方面"><a href="#UDP方面" class="headerlink" title="UDP方面"></a>UDP方面</h4><ol><li><p>可以设置指定带宽的UDP数据流。</p></li><li><p>可以测试网络抖动值、丢包数。</p></li><li><p>支持多播测试。</p></li><li><p>支持多线程，在客户端与服务端支持多重连接。</p></li></ol><h4 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h4><ol><li><p>在适当的地方，选项中可以使用K（kio-）和M（mega-）</p></li><li><p>可以指定运行的总时间，设置可以设置传输的数据总量</p></li><li><p>在报告中，为数据选用最合适的单位</p></li><li><p>服务器支持多重连接，而不是等待一个单线程测试</p></li><li><p>在指定时间间隔重复显示网络带宽，波动和丢包情况</p></li><li><p>服务器端可做后台程序运行</p></li><li><p>服务器端可作为window服务运行</p></li><li><p>使用典型数据流测试链接层压缩对于可用带宽的影响</p></li><li><p>支持传输指定文件，可用定性和定量测试</p></li></ol><hr><h3 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h3><h4 id="TCP测试"><a href="#TCP测试" class="headerlink" title="TCP测试"></a>TCP测试</h4><h5 id="服务端"><a href="#服务端" class="headerlink" title="服务端"></a>服务端</h5><ul><li>-s 表示服务器端；</li><li>-p 定义监听端口号；</li><li>-i 设置每次报告之间的时间间隔，单位为秒，如果设置为非零值，就会按照此时间间隔输出测试报告，默认值为零</li></ul><p>例如:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">iperf3 -s -p <span class="token number">12345</span> -i <span class="token number">1</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h5 id="客户端"><a href="#客户端" class="headerlink" title="客户端"></a>客户端</h5><ul><li>-c 表示服务器的IP地址；</li><li>-p 表示服务器的端口号；</li><li>-i 设置每次报告之间的时间间隔，单位为秒，如果设置为非零值，就会按照此时间间隔输出测试报告，默认值为零；</li><li>-t 设置传输的总时间，iperf在指定的时间内，重复的发送指定长度的数据包，默认是10秒钟；</li><li>-w 设置套接字缓冲区为指定大小<ul><li>对于TCP方式，此设置为TCP窗口大小，416k为tcp最大值；</li><li>对于UDP方式，此设置为接受UDP数据包的缓冲区大小，限制可以接受数据包的最大值；</li></ul></li><li>-P 表示线程数，默认为1；</li><li>-d debug日志输出；</li></ul><p>例如:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 假定服务端IP是192.168.7.151</span>iperf3 -c <span class="token number">192.168</span>.7.151 -p <span class="token number">12345</span> -i <span class="token number">1</span> -w 416k -P <span class="token number">10</span> -t <span class="token number">30</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>参考输出结果如下:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">[</span> ID<span class="token punctuation">]</span> Interval           Transfer     Bitrate<span class="token punctuation">[</span>  <span class="token number">5</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec  <span class="token number">5.50</span> GBytes  <span class="token number">4.73</span> Gbits/sec                  receiver<span class="token punctuation">[</span>  <span class="token number">8</span><span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec  <span class="token number">5.45</span> GBytes  <span class="token number">4.68</span> Gbits/sec                  receiver<span class="token punctuation">[</span>SUM<span class="token punctuation">]</span>   <span class="token number">0.00</span>-10.00  sec  <span class="token number">11.0</span> GBytes  <span class="token number">9.41</span> Gbits/sec                  receiver<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><img src="/a53c4583/20919f3fc783463f986fef3908270497.png" class=""><hr><h4 id="UDP测试"><a href="#UDP测试" class="headerlink" title="UDP测试"></a>UDP测试</h4><h5 id="服务端-1"><a href="#服务端-1" class="headerlink" title="服务端"></a>服务端</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">iperf3 -s -p <span class="token number">12345</span> -i <span class="token number">1</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><h5 id="客户端-1"><a href="#客户端-1" class="headerlink" title="客户端"></a>客户端</h5><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">iperf3 -c <span class="token number">192.168</span>.7.151 -p <span class="token number">12345</span> -i <span class="token number">1</span> -u -t <span class="token number">30</span> -b 10G<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><ul><li>-b 10G 表示在 udp 测试时，设置测试发送的带宽，单位：bit/秒，不设置时默认为：1Mbit/秒，1G 的线路你可以使用 900M 进行测试。</li></ul><h4 id="可能遇到的问题"><a href="#可能遇到的问题" class="headerlink" title="可能遇到的问题"></a>可能遇到的问题</h4><h5 id="1-带宽压测上不去"><a href="#1-带宽压测上不去" class="headerlink" title="1. 带宽压测上不去"></a>1. 带宽压测上不去</h5><p>倘若在大带宽打流测试中达不到预期带宽 ( 例如: 10G网络 ) ，此时不妨检查网卡 MTU 值。</p><p>因为在缺省的网卡设定中，MTU 是 1500 ，也就是一个IP包大小是 1500 ，而对于 10G 网络来说，包太小，意味着相同数据量，包的数量多，每个包的头部数据将消耗大量的网络带宽，可以将 MTU 设置成 9000 ( 参考命令: <code>ifconfig eno5 mtu 9000</code> ) 。</p><hr><h2 id="iperf的参数详解"><a href="#iperf的参数详解" class="headerlink" title="iperf的参数详解"></a>iperf的参数详解</h2><h3 id="GENERAL-OPTIONS"><a href="#GENERAL-OPTIONS" class="headerlink" title="GENERAL OPTIONS"></a>GENERAL OPTIONS</h3><p>（通用参数，不管iperf3跑在client还是Server模式下都适用的参数）</p><table><thead><tr><th>Command line option（命令行参数）</th><th>Description（描述说明）</th></tr></thead><tbody><tr><td><strong>-p</strong>, –port <em><strong>n</strong></em></td><td>The server port for the server to listen on and the client to connect to. This should be the same in both client and server. Default is 5201.<br><br>（<br><br>1、服务端：服务端监听的端口，默认5201端口，同时监听TCP/UDP<br><br>2、客户端：客户端去连接的端口，默认5201，如果同时有-u参数，则用UDP发起连接，如果没有，则默认使用TCP连接<br><br>）<br><br>使用方式：<br><br>iperf3 -s -p 6666, 在6666端口监听<br><br>iperf3 -c 192.168.0.1 -p 6666, 去连接服务端的6666端口</td></tr><tr><td><strong>–cport</strong> <em><strong>n</strong></em></td><td>Option to specify the client-side port. (new in iPerf 3.1)<br><br>本参数提供了一个指定客户端本地端口的选项，区分于-p指定的是服务端的远端端口<br><br>使用方式：<br><br>iperf3 -s –cport 8888, 在服务端指定客户端本地端口只能是8888？ 从测试结果看，这个选项在服务端不起任何作用，但执行命令不会报错<br><br>iperf3 -c 192.168.0.1 –cport 8888，指定客户端选择本地端口为8888</td></tr><tr><td><strong>-f</strong>, –format <em><strong>[kmKM]</strong></em></td><td>A letter specifying the format to print bandwidth numbers in. Supported formats are <br><br><code>&lt;br&gt;    &#39;k&#39; = Kbits/sec           &#39;K&#39; = KBytes/sec    &#39;m&#39; = Mbits/sec           &#39;M&#39; = MBytes/sec&lt;br&gt;</code><br><br>The adaptive formats choose between kilo- and mega- as appropriate.<br><br>指定打印测试结果的带宽（bitrate比特率这一列）时用什么格式显示:k表示：千比特/秒， K表示：千字节/秒， m表示：兆比特/秒， K表示：兆字节/秒。<br><br>客户端和服务端可以用不同的参数，各自按照各自指定的方式打印出带宽测试结果<br><br>使用方式：<br><br>iperf3 -s -f M<br><br>iperf3 -c 192.168.0.1 -f k</td></tr><tr><td><strong>-i</strong>, –interval <em><strong>n</strong></em></td><td>Sets the interval time in seconds between periodic bandwidth, jitter, and loss reports. If non-zero, a report is made every <em><strong>interval</strong></em> seconds of the bandwidth since the last report. If zero, no periodic reports are printed. Default is zero.<br><br>以秒为单位，设置带宽（还有抖动，丢包等）测试报告打印输出的周期。不使用这个选项时，默认周期是1秒，可以使用0和任何0.1秒到60秒之间的参数，如果是0表示不打印周期性的报告，只在整个测试完成时，输出一次报告结果。<br><br>（上面英文解释说默认值是0这个是错误的，默认值实际上是1），客户端和服务端可以使用不同的参数值。<br><br>使用方式：<br><br>iperf3 -s -i 0<br><br>iperf3 -c 192.168.0.1 -i 3.6</td></tr><tr><td><strong>-F</strong>, –file name</td><td><strong>client-side:</strong> read from the file and write to the network, instead of using random data;  <br><strong>server-side:</strong> read from the network and write to the file, instead of throwing the data away.<br><br>客户端：从文件中读取数据，并发送到网络里，如果不加这个选项默认系统会产生随机数据发送到网络里  <br>服务端：把网络上收到的数据写入文件中，默认系统会丢弃收到的数据<br><br>文件格式未知，在google上也找不到什么说明，待后续更新()  <br>使用方式：  <br>iperf3 -s -F ./log.txt<br><br>iperf3 -c 192.168.0.1 -F ./input.txt</td></tr><tr><td><strong>-A</strong>, –affinity <em><strong>n/n,m-F</strong></em></td><td>Set the CPU affinity, if possible (Linux and FreeBSD only). On both the client and server you can set the local affinity by using the n form of this argument (where n is a CPU number). In addition, on the client side you can override the server’s affinity for just that one test, using the n,m form of argument. Note that when using this feature, a process will only be bound to a single CPU (as opposed to a set containing potentialy multiple CPUs).<br><br>如果系统支持则可以设置CPU亲和性（只支持Linux和FreeBSD），说白了就是在设定将iperf3进程跑在哪个CPU上。  <br>客户端和服务端都可以设置CPU亲和性,n表示CPU编号（**<a href="https://blog.csdn.net/meihualing/article/details/112471835">Linux下如何查看CPU编号及其它CPU相关的信息</a>**）。  <br>此外在客户端可以通过”-A n,m”的形式，覆盖server端的CPU亲和性设置（就是覆盖运行server端时，指定运行在哪个CPU上的设置），指定本次运行时iperf3的服务端跑在m号CPU上，但只对这一次运行生效。  <br>注意如果用了这个参数，意味着iperf3只会在指定的CPU上运行（默认不加这个参数时，操作系统会自行调度CPU，负荷重（加多线程？）有可能会把iperf3同时运行在多个CPU上）  <br>使用方式：<br><br>iperf3 -s -A 2，指定服务端运行在2号CPU上<br><br>iperf3 -c 192.168.0.1 -A 0，指定客户端运行在0号CPU上  <br>或者  <br>iperf3 -c 192.168.0.1 -A 0,3，指定本次运行客户端运行在0号CPU上而服务端运行在2号CPU上</td></tr><tr><td><strong>-B</strong>, –bind <em><strong>host</strong></em></td><td>Bind to <em><strong>host</strong></em>, one of this machine’s addresses. For the client this sets the outbound interface. For a server this sets the incoming interface. This is only useful on multihomed hosts, which have multiple network interfaces.<br><br>绑定到主机，主机的一个地址。对客户端来说，这个设置数据发送从哪个接口发送。<br><br>对服务端来说，这是设置数据从哪个接口接收。这个命令只在多宿主主机（二个或者二个以上网络接口）中有用。<br><br>这个选项对接口的定义很不清楚，没有讲清楚 IP接口和物理网卡接口选择时，-B与主机路由的选择关系，<br><br>可以参照另外一个文章有清楚的描述：**<a href="https://blog.csdn.net/meihualing/article/details/112390106">iPerf3 -B (–bind host)绑定发送端网卡/发送IP端地址</a>**<br><br><strong>以及Linux侧路由配置：<a href="https://blog.csdn.net/meihualing/article/details/113058719">Linux上添加路由，删除路由，修改路由配置（路由表项基本知识）</a></strong></td></tr><tr><td><strong>-V</strong>, –verbose</td><td>give more detailed output<br><br>输入更多的详细信息</td></tr><tr><td><strong>-J</strong>, –json</td><td>output in JSON format<br><br>运行结束时，用JSON的格式输出测试结果，默认打印到屏幕上，可以结合下面”–logfile”或者linux本身的重定向命令”&gt;”将输出报告打印到指定文件里</td></tr><tr><td><strong>–logfile</strong> file</td><td>send output to a log file. (new in iPerf 3.1)<br><br>把测试结果存到指定的log文件</td></tr><tr><td><strong>-d</strong>, –debug</td><td>emit debugging output. Primarily (perhaps exclusively) of use to developers.<br><br>打印出更多的调试用的log，主要是给开发者用的，如果不是碰到需要调试的问题，这个参数基本没什么用。</td></tr><tr><td><strong>-v</strong>, –version</td><td>Show version information and quit.<br><br>只要加了-v这个参数，iperf3会显示版本号，然后自动退出</td></tr><tr><td><strong>-h</strong>, –help</td><td>Show a help synopsis and quit.<br><br>只要加了-h这个参数，iperf3会显示帮助信息(包括命令使用格式，各个参数的简明的使用说明)，然后自动退出</td></tr></tbody></table><hr><h3 id="SERVER-SPECIFIC-OPTIONS-服务端专用参数"><a href="#SERVER-SPECIFIC-OPTIONS-服务端专用参数" class="headerlink" title="SERVER SPECIFIC OPTIONS(服务端专用参数)"></a>SERVER SPECIFIC OPTIONS(服务端专用参数)</h3><table><thead><tr><th>Command line option（命令行参数）</th><th>Description（具体描述）</th></tr></thead><tbody><tr><td><strong>-s</strong>, –server</td><td>Run iPerf in server mode. (This will only allow one iperf connection at a time)<br><br>  <br>本次iperf3运行在服务端模式（-c和-s是互斥的，二者必居其一），括号里的这句话：这只允许一次一个iperf connection，是指iperf服务端同一时间只接受一个TCP或者UDP连接。<br><br>意味着同一时间只有一个客户端可以给这个iperf3服务端进程打流。（但可以在通过-p参数，指定在同一个主机的同一个IP地址的不同的端口同时开多个iperf3服务端进程）<br><br>使用方式：<br><br>iperf3 -s</td></tr><tr><td><strong>-D</strong>, –daemon</td><td>Run the server in background as a daemon.<br><br>以daemon的形式在后台运行(不会向控制台窗口输出，可以通过ps -aux | grep iperf3看到对应的后台进程号)<br><br>和用iperf3 -s &amp;命令（注意命令最后的&amp;号）类似，都可以让iperf3在后台运行，但iperf3 -s &amp;命令的话，控制台终端还是可以得到iperf3的打印输出的。<br><br>但用&amp;的后台运行，在你关闭终端时，程序也会关闭，而用-D的，<strong>则在终端关闭后，iperf3 -s会继续在后台运行</strong>。<br><br>下面文章可以详细了解Linux前后台程序，如何让程序在后台运行，如何切换前后台，以及Daemon进程：<br><br><strong><a href="https://blog.csdn.net/meihualing/article/details/112577550">如何在Linux前后台切换程序, 用&amp;把程序运行在后台和以Daemon方式运行的程序（控制台退出后程序继续保持运行）</a></strong><br><br>使用方式:<br><br>iperf3 -s -D</td></tr><tr><td><strong>-I</strong>, –pidfile<em><strong>file</strong></em></td><td>write a file with the process ID, most useful when running as a daemon. (new in iPerf 3.1)<br><br>这介需要iperf3.1以上版本才支持，提供了一个将本次运行的iperf3进程的PID写入到指定文件里的功能，正常的情况下也没啥用，大概率在将程序运行成Daemon程序，<br><br>并用需要通过PID去监控，KILL或者其它控制这个进程的自动化功能时用到（原文件是这么说的，但我觉得这个指供的功能和ps -aux | grep iperf3得到的信息是一样的，<br><br>对于工作在Linux下的人来说并没有什么实际意义，估计是给其它平台的工作者用的）<br><br>使用方式：<br><br>iperf3 -s -I /home/user/iperf.pid<br><br>注意：<br><br>1）当前用户一定要有/home/user目录的写权限<br><br>2）文件可以事先用touch命令创建好，也可以不用创建<br><br>3）iperf3当前进各结束后/home/user/iperf.pid文件会被主动删除<br><br>4）/home/user/iperf.pid一定要使用全路径，不能使用默认的当前路径<br><br>   （使用当前路径分导致各种奇怪的iperf启动失败，或者启动成功了，但指定目录找到不iperf.pid文件），原因不明</td></tr></tbody></table><hr><h3 id="CLIENT-SPECIFIC-OPTIONS（客户端专用参数）"><a href="#CLIENT-SPECIFIC-OPTIONS（客户端专用参数）" class="headerlink" title="CLIENT SPECIFIC OPTIONS（客户端专用参数）"></a>CLIENT SPECIFIC OPTIONS（客户端专用参数）</h3><table><thead><tr><th>Command line option（命令行参数）</th><th>Description（具体描述）</th></tr></thead><tbody><tr><td><strong>-c</strong>, –client <em><strong>host</strong></em></td><td>Run iPerf in client mode, connecting to an iPerf server running on <em><strong>host</strong></em>.<br><br>本次iperf3运行在客户端状态，host指向的是iperf服务端的ip地址<br><br>使用方式:<br><br>iperf3 -c 192.168.0.10, 本机做为客户端连接到192.168.0.10(服务端运行在这人ip地址上)，并做打流量测试</td></tr><tr><td><strong>–sctp</strong></td><td>Use SCTP rather than TCP (Linux, FreeBSD and Solaris). (new in iPerf 3.1)<br><br>使用sctp协议（不加这人选项的话默认使用tcp），iperf3.1及更新的版本开始支持<br><br>使用方式:<br><br>iperf3 -c 192.168.0.10 –sctp</td></tr><tr><td><strong>-u</strong>, –udp</td><td>Use UDP rather than TCP. See also the <a href="https://iperf.fr/iperf-doc.php#3bandwidth">-b</a> option.<br><br>使用udp协议（不加这人选项的话默认使用tcp），使用这个选项的话，还需要查看-b选项，因为UDP是面向数据报的协议，所以一般要用-b指定打多大带宽的数据(不指定-b的话，默认值见对-b参数的解释)<br><br>使用方式:<br><br>iperf3 -c 192.168.0.10 -u</td></tr><tr><td><strong>-b</strong>, –bandwidth <em><strong>n[KM]</strong></em></td><td>Set target bandwidth to n bits/sec (default 1 Mbit/sec for UDP, unlimited for TCP). If there are multiple streams (-P flag), the bandwidth limit is applied separately to each stream. You can also add a ’/’ and a number to the bandwidth specifier. This is called “burst mode”. It will send the given number of packets without pausing, even if that temporarily exceeds the specified bandwidth limit.<br><br>设置本次测试的发送带宽成n 比特/秒（对UDP来说<strong>默认是1M 比特/秒，对TCP来说默认是不限制</strong>），如果同时还设置了多线程(-P选项)，当前这个-b的带宽指定的是每个线程的发送带宽。<br><br>我们还可以在带宽后面加上/和一个数字。我们称这个为“突发脉冲模式”。加了这个“/数字”后，iperf3客户端会一次连续发送指定的数量的数据包，中间不做任何间隔（不加这个 “/数字”时，iperf3会根据每个报文的长度，算出为了达到指定的带宽，每秒需要发送几个报文，然后每个数据报文会被以平均的时间间隔进行发送），即使中间会有偶尔的超出带宽限制<br><br>使用方式:<br><br>iperf3 -c 192.168.0.10 -u -b 100M，报文平均的落在时间线上<br><br>或者<br><br>iperf3 -c 192.168.0.10 -u -b 100M/40，报文以40个为一组，连续发送40个报文，每一组平均的落在时间线上，每一组发送时可能超出-b指定的带宽，但iperf3保证整个打流期间的平均带宽不超过指定值。<br><br>详见：**<a href="https://blog.csdn.net/meihualing/article/details/112791974">iperf3 -b参数详细图文分析</a>**</td></tr><tr><td><strong>-t</strong>, –time <em><strong>n</strong></em></td><td>The time in seconds to transmit for. iPerf normally works by repeatedly sending an array of <em><strong>len</strong></em> bytes for <em><strong>time</strong></em> seconds. Default is 10 seconds. See also the <a href="https://iperf.fr/iperf-doc.php#3len">-l</a>, <a href="https://iperf.fr/iperf-doc.php#3blockcount">-k</a> and <a href="https://iperf.fr/iperf-doc.php#3num">-n</a> options.<br><br>定义本次发送报文测试要持续的时间，单位为秒iPerf通常工作的模式是：持续-t定义的时间（秒）不停的重复发送一组长度为-l定义的数据包。默认值是10秒。参照-l, -k和-n选项  <br>使用方式：  <br>iperf3 -c 127.0.0.1 -u -t 11  <br>注意这个参数不能和-n或者-k同时使用，上述例子表示连续发送11秒钟时间后停止测试</td></tr><tr><td><strong>-n</strong>, –num <em><strong>n[KM]</strong></em></td><td>The number of buffers to transmit. Normally, iPerf sends for 10 seconds. The -n option overrides this and sends an array of <em><strong>len</strong></em> bytes <em><strong>num</strong></em> times, no matter how long that takes. See also the <a href="https://iperf.fr/iperf-doc.php#3len">-l</a>, <a href="https://iperf.fr/iperf-doc.php#3blockcount">-k</a> and <a href="https://iperf.fr/iperf-doc.php#3time">-t</a> options.<br><br>定义本次发送报文要发送的总的数据长度，单位是字节。默认情况下iperf持续发送10秒时间。加了-n选项后，就不覆盖了10秒这个默认设置，而是发送-n指定长度的数据,发送完后停止。参照-l,-k和-t选项  <br>使用方式：  <br>iperf3 -c 127.0.0.1 -u -n 40M  <br>注意这个参数不能和-t或者-k同时使用,长度后面不带单位的话默认单位是字节，也可以用K/M表示千/兆字节，上述例子表示总共要发送40M字节的报文</td></tr><tr><td><strong>-k</strong>, –blockcount <em><strong>n[KM]</strong></em></td><td>The number of blocks (packets) to transmit. (instead of -t or -n) See also the <a href="https://iperf.fr/iperf-doc.php#3time">-t</a>, <a href="https://iperf.fr/iperf-doc.php#3len">-l</a> and <a href="https://iperf.fr/iperf-doc.php#3num">-n</a> options.<br><br>定义本次发送报文要发送的报文个数。发送-k指定个数的报文,发送完后停止。参照-l,-n和-t选项  <br>使用方式：  <br>iperf3 -c 127.0.0.1 -u -k 37  <br>注意这个参数不能和-t或者-n同时使用,上面例子表示总共要发送37个报文</td></tr><tr><td><strong>-l</strong>, –length <em><strong>n[KM]</strong></em></td><td>The length of buffers to read or write. iPerf works by writing an array of <em><strong>len</strong></em> bytes a number of times. Default is 128 KB for TCP, 8 KB for UDP. See also the <a href="https://iperf.fr/iperf-doc.php#3num">-n</a>, <a href="https://iperf.fr/iperf-doc.php#3blockcount">-k</a> and <a href="https://iperf.fr/iperf-doc.php#3time">-t</a> options.<br><br>每次发报的报文长度。iperf发送一组长度为-l指定的数据报文，每个数据报文的长度都是-l指定的长度。默认TCP是128KB, UDP是8KB。参照-n, -k和-t选项。<br><br>使用方式:<br><br>iperf3 -c 192.168.3.15 -u -l 2K<br><br>注意: 这个参数可以和-n, -k和-t参数一起使用。</td></tr><tr><td><strong>-P</strong>, –parallel <em><strong>n</strong></em></td><td>The number of simultaneous connections to make to the server. Default is 1.<br><br>到iperf3服务器端并行的连接数量，默认值是1。（未知并行这个参数其实不是个多线程？这个需要看原代码。如果不是多纯种那么很奇怪为什么多线程在某些测试过程中能测出更大的带宽？）<br><br>使用方式:<br><br>iperf3 -c 192.168.3.15 -u -P 3<br><br>表示开3个连接，这里可以查看链接文章：<strong>如何查看LINUX里的某个进程的线程</strong></td></tr><tr><td><strong>-R</strong>, –reverse</td><td>Run in reverse mode (server sends, client receives).<br><br>工作在反向连接模式（服务器端发送，客户端接收）<br><br>使用方式：<br><br>iperf3 -c 192.168.3.15 -u -R</td></tr><tr><td><strong>-w</strong>, –window <em><strong>n[KM]</strong></em></td><td>Sets the socket buffer sizes to the specified value. For TCP, this sets the TCP window size. (this gets sent to the server and used on that side too)<br><br>设置socket缓冲的大小。对TCP来说，这个用于设置 TCP 窗口接收的大小（这个选项会被发送到服务器端，同样的参数会在服务器端生效）<br><br>iperf3 -c 192.168.3.15 -w 100k<br><br>对于UDP来说，通常不需要设置这个参数，这个数设置得太小了，会导致发送端发送速度慢，<br><br>对于TCP来说，这个参数的设置值的计算和选择方法详见：<strong>TCP滑动窗口协议与窗口大小的计算</strong></td></tr><tr><td><strong>-M</strong>, –set-mss <em><strong>n</strong></em></td><td>Attempt to set the TCP maximum segment size (MSS). The MSS is usually the MTU - 40 bytes for the TCP/IP header. For ethernet, the MSS is 1460 bytes (1500 byte MTU).<br><br>尝试去设置TCP的MSS最大分片长度。MSS通常是MTU减去40字节的TCP/IP首部。对以达网来说MSS是1460（MTU是1500字节）<br><br>使用方式：<br><br>iperf3 -c 192.168.3.15 -M 100<br><br>MSS设置得很小，会导致TCP分成很多个小包进行发送，过小会导致带宽测试结果偏小。<br><br>详见：**<a href="https://blog.csdn.net/meihualing/article/details/113739693">TCP的MSS的计算与详解</a>**</td></tr><tr><td><strong>-N</strong>, –no-delay</td><td>Set the TCP no delay option, disabling Nagle’s algorithm. Normally this is only disabled for interactive applications like telnet.<br><br>设置TCP的不延时选项，关闭Nagle’s算法，通常这个选项只用于交互式人机对话的应用程序中，比如Telnet<br><br>使用方式：<br><br>iperf3 -c 192.168.3.26 -N</td></tr><tr><td><strong>-4</strong>, –version4</td><td>only use IPv4.<br><br>只使用IPv4</td></tr><tr><td><strong>-6</strong>, –version4</td><td>only use IPv6.<br><br>只使用IPv6, 注意这个要配合IPv6的地址一起使用</td></tr><tr><td><strong>-S</strong>, –tos <em><strong>n</strong></em></td><td>The type-of-service for outgoing packets. (Many routers ignore the TOS field.) You may specify the value in hex with a ‘0x’ prefix, in octal with a ‘0’ prefix,<br><br>or in decimal. For example, ‘0x10’ hex = ‘020’ octal = ‘16’ decimal. The TOS numbers specified in RFC 1349 are: <br><br>    IPTOS_LOWDELAY     minimize delay        0x10<br><br>    IPTOS_THROUGHPUT   maximize throughput   0x08<br><br>    IPTOS_RELIABILITY  maximize reliability  0x04<br><br>    IPTOS_LOWCOST      minimize cost         0x02<br><br>设置被发送出去的报文的TOS字段。(目前很多路由器是不处理TOS字段的)，可以用0x打头输入16进制数，0打头输入8进制数，或者不需要前缀则默认是10进制数。<br><br>比如: 16进制的”0x10”表示8进制的”020”表示十进制的16。<br><br>TOS定义如下：<br><br>    IPTOS_LOWDELAY     最小延时        0x10<br><br>    IPTOS_THROUGHPUT   最大带宽   0x08<br><br>    IPTOS_RELIABILITY  可靠性最好  0x04<br><br>    IPTOS_LOWCOST      最便宜         0x02<br><br>使用方式：<br><br>iperf3 -c 192.168.3.15 -S 0x10</td></tr><tr><td><strong>-L</strong>, –flowlabel <em><strong>n</strong></em></td><td>Set the IPv6 flow label (currently only supported on Linux).<br><br>设置IPv6的流标签（目前只有Linux版本的iperf3能支持）</td></tr><tr><td><strong>-Z</strong>, –zerocopy</td><td>Use a “zero copy” method of sending data, such as sendfile(2), instead of the usual write(2). This uses much less CPU.<br><br>使用“零拷贝”办法来发送数据，比如使用sendfile(2)代替write(2).这会减少CPU的占用率<br><br>使用方式：<br><br>iperf3 -c 192.168.3.15 -u -Z</td></tr><tr><td><strong>-O</strong>, –omit <em><strong>n</strong></em></td><td>Omit the first n seconds of the test, to skip past the TCP <a href="https://en.wikipedia.org/wiki/Slow-start">TCP slowstart</a> period.<br><br>忽略最前面n秒的测试结果，通常用来跳过<strong>TCP慢启动</strong>过程<br><br>使用方式：<br><br>iperf3 -c 192.168.3.15 -O 20 -t 40<br><br>忽略最前面的20秒，然后再打40秒的流(见-t参数)<br><br>详见：<strong>TCP慢启动过程详解</strong></td></tr><tr><td><strong>-T, –title <em><strong>str</strong></em></strong></td><td>Prefix every output line with this string.<br><br>每行打印输出内容前加一个前缀<br><br>使用方式：<br><br>iperf3 -c 192.168.3.15 -T 这是前缀<br><br>在每行输入前面加了“这是前缀”这4个字，不知道这个功能有什么用</td></tr><tr><td><strong>-C</strong>, –linux-congestion <em><strong>algo</strong></em></td><td>Set the <a href="https://en.wikipedia.org/wiki/TCP_congestion-avoidance_algorithm">congestion control algorithm</a> (Linux only for iPerf 3.0, Linux and FreeBSD for iPerf 3.1).<br><br>设置<strong>TCP拥塞控制算法</strong>(在LINUX上3.0以上支持，在LINUX和FREEBSD上3.1以下版本支持)</td></tr></tbody></table>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;下载安装&quot;&gt;&lt;a href=&quot;#下载安装&quot; class=&quot;headerlink&quot; title=&quot;下载安装&quot;&gt;&lt;/a&gt;下载安装&lt;/h2&gt;&lt;h3 id=&quot;yum-安装&quot;&gt;&lt;a href=&quot;#yum-安装&quot; class=&quot;headerlink&quot; title=&quot;yum 安</summary>
      
    
    
    
    <category term="network" scheme="https://nestealin.com/categories/network/"/>
    
    
    <category term="iperf3" scheme="https://nestealin.com/tags/iperf3/"/>
    
    <category term="网络压测" scheme="https://nestealin.com/tags/%E7%BD%91%E7%BB%9C%E5%8E%8B%E6%B5%8B/"/>
    
    <category term="带宽压测" scheme="https://nestealin.com/tags/%E5%B8%A6%E5%AE%BD%E5%8E%8B%E6%B5%8B/"/>
    
  </entry>
  
  <entry>
    <title>Prometheus的分布式数据存储--VictoriaMetrics部署文档</title>
    <link href="https://nestealin.com/7dbee069/"/>
    <id>https://nestealin.com/7dbee069/</id>
    <published>2022-09-12T15:21:10.000Z</published>
    <updated>2024-06-29T07:26:38.907Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>当前单节点Prometheus集中存储多个集群数据，数据单点且索引性能低下，官方架构问题无法横向扩展优化。</p><h2 id="目的"><a href="#目的" class="headerlink" title="目的"></a>目的</h2><ol><li>需要分布式数据存储，支持并发查询，优化查询性能</li><li>可以兼容Prometheus写入或服务端中转写入</li><li>可支持数据副本（次要）</li></ol><h2 id="架构"><a href="#架构" class="headerlink" title="架构"></a>架构</h2><p>VictoriaMetrics是一个快速、高效和可扩展的时序数据库，可作为Prometheus的长期存储(long-term storage)。</p><p>VictoriaMetrics支持PromQL查询语言，也支持Influxdb行协议，对当前主流的时序协议支持比较好。</p><img src="/7dbee069/f3088b56cde14b09ac45ffdf85a4ad8a.png" class=""><p>单实例的victoriametric只有一个进程。</p><p>集群版的victoriametrics有3类进程，即3类微服务组成：</p><ul><li>vmstorage: 数据存储节点，负责存储时序数据；</li><li>vmselect: 数据查询节点，负责接收用户查询请求，向vmstorage查询时序数据；</li><li>vminsert: 数据插入节点，负责接收用户插入请求，向vmstorage写入时序数据；</li></ul><p>在部署时可以按照需求，不同的微服务部署不同的副本，以应对业务需求：</p><ul><li>若数据量比较大，部署较多的vmstorage副本；</li><li>若查询请求比较多，部署较多的vmselect副本；</li><li>若插入请求比较多，部署较多的vminsert副本；</li></ul><blockquote><p>集群中vmselect、vminsert节点都是无状态的，唯一有状态的是vmstorage。</p></blockquote><h2 id="部署模式"><a href="#部署模式" class="headerlink" title="部署模式"></a>部署模式</h2><h3 id="单节点版"><a href="#单节点版" class="headerlink" title="单节点版"></a>单节点版</h3><p>直接运行一个二进制文件，既可以运行，官方建议采集数据点(data points)低于100w/s，推荐VM单节点版，简单好维护，但不支持告警。</p><h3 id="集群版"><a href="#集群版" class="headerlink" title="集群版"></a>集群版</h3><p>支持数据水平拆分，把功能拆分为vmstorage、 vminsert、vmselect，如果要替换Prometheus，还需要vmagent、vmalert。</p><p>集群版主要特点：</p><ul><li>支持单节点版本的所有功能。</li><li>性能和容量水平扩展。</li><li>支持时间序列数据的多个独立命名空间（多租户）。</li><li>支持多副本。</li></ul><h2 id="集群部署"><a href="#集群部署" class="headerlink" title="集群部署"></a>集群部署</h2><h3 id="简述"><a href="#简述" class="headerlink" title="简述"></a>简述</h3><p>本次实验采用3台 vmstorage 作为存储集群，2台 vminsert 实现写入服务高可用，2台 vmselect 实现查询服务高可用，写入数据采用2副本分散存储；</p><p>待VM集群就绪后，将对接现有Prometheus，实现现有监控远程写入，并接入现有grafana实现数据查询。</p><h3 id="集群信息"><a href="#集群信息" class="headerlink" title="集群信息"></a>集群信息</h3><table><thead><tr><th align="left">节点IP</th><th align="left">节点角色</th><th align="left">备注</th></tr></thead><tbody><tr><td align="left">192.168.7.33</td><td align="left">vmstorage、vminsert、vmselect</td><td align="left"></td></tr><tr><td align="left">192.168.7.34</td><td align="left">vmstorage、vminsert、vmselect</td><td align="left"></td></tr><tr><td align="left">192.168.7.35</td><td align="left">vmstorage</td><td align="left"></td></tr><tr><td align="left">192.168.7.81</td><td align="left">prometheus、grafana</td><td align="left"></td></tr><tr><td align="left">192.168.7.81</td><td align="left">nginx(写入、查询组件服务负载均衡)</td><td align="left">通过域名访问</td></tr></tbody></table><blockquote><p>数据路径:</p><p>/usr/local/victoria-metrics: vmstorage、vminsert、vmselect二进制目录</p><p>/data1/vmstorage_data: vmstorage数据路径</p></blockquote><h3 id="部署过程"><a href="#部署过程" class="headerlink" title="部署过程"></a>部署过程</h3><ul><li>以下需要在所有节点操作</li></ul><p>目录环境准备</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">mkdir</span> /usr/local/victoria-metrics<span class="token function">mkdir</span> /data1/vmstorage_data<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>准备版本包</p><p><a href="https://github.com/VictoriaMetrics/VictoriaMetrics/releases">https://github.com/VictoriaMetrics/VictoriaMetrics/releases</a></p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">cd</span> /opt/<span class="token function">wget</span> https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.80.0/victoria-metrics-linux-amd64-v1.80.0-cluster.tar.gz<span class="token function">tar</span> zxvf victoria-metrics-linux-amd64-v1.80.0-cluster.tar.gz -C /usr/local/victoria-metrics<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h4 id="vmstorage"><a href="#vmstorage" class="headerlink" title="vmstorage"></a>vmstorage</h4><p>首先需要把存储部署上，多个存储之间数据是不同步的，也就是说所有的storege组件之间是感知不到彼此的。</p><p>最终数据通过vmselect和vminsert采用一致性hash算法来确定读取/写入哪台节点。</p><blockquote><p>vmstorage属于有状态服务，在cluster模式下有三个端口:</p><ol><li>8482端口是API端口</li><li>8400是端口给vminsert写数据的</li><li>8401端口是给vmselect查询数据的</li></ol></blockquote><p>高可用说明:</p><p>启用复制保证了多达 <code>N-1</code> 个 <code>vmstorage</code> 节点不可用，所有数据仍可用于查询。集群必须至少包含 <code>2*N-1</code> 个 <code>vmstorage</code> 节点，其中 <code>N</code> 是复制因子，以便在 <code>N-1</code> 个存储节点丢失时为新摄取的数据维持指定的复制因子。</p><p>例如，当 <code>-replicationFactor=3</code> 传递给 <code>vminsert</code> 时，它将所有摄取的数据复制到 3 个不同的 <code>vmstorage</code> 节点，因此最多可以丢失 2 个 <code>vmstorage</code> 节点而不会丢失数据。<code>vmstorage</code> 节点的最小数量应该等于 <code>2*3-1 = 5</code>，因此当 2 个 <code>vmstorage</code> 节点丢失时，剩余的 3 个 <code>vmstorage</code> 节点可以为新摄取的数据提供服务。</p><p>启动命令:</p><blockquote><p>主要参数:</p><ul><li>-retentionPeriod # 存储时间，单位是月</li><li>-storageDataPath # 数据存放路径</li></ul></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/victoria-metrics/vmstorage-prod -httpListenAddr <span class="token string">"0.0.0.0:8482"</span> <span class="token punctuation">\</span>   <span class="token comment"># vmstorage监听端口</span>    -storageDataPath /data1/vmstorage_data <span class="token punctuation">\</span>                       <span class="token comment"># 数据存储位置</span>    -retentionPeriod 60d <span class="token punctuation">\</span>                          <span class="token comment"># 数据保留多久</span>    -vminsertAddr <span class="token string">"0.0.0.0:8400"</span> <span class="token punctuation">\</span>                  <span class="token comment"># insert服务连接的端口</span>    -vmselectAddr <span class="token string">"0.0.0.0:8401"</span> <span class="token punctuation">\</span>                  <span class="token comment"># select服务连接的端口</span>    -dedup.minScrapeInterval<span class="token operator">=</span>30s <span class="token punctuation">\</span>                  <span class="token comment"># 和vmselect保持一致</span>    -loggerTimezone <span class="token string">"Asia/Shanghai"</span> <span class="token punctuation">\</span>    -loggerLevel INFO<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>/etc/systemd/system/vmstorage.service</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">[</span>Unit<span class="token punctuation">]</span><span class="token assign-left variable">Description</span><span class="token operator">=</span>vmstorage<span class="token assign-left variable">After</span><span class="token operator">=</span>network.target<span class="token punctuation">[</span>Service<span class="token punctuation">]</span><span class="token assign-left variable">WorkingDirectory</span><span class="token operator">=</span>/usr/local/victoria-metrics<span class="token assign-left variable">ExecStart</span><span class="token operator">=</span>/usr/local/victoria-metrics/vmstorage-prod -httpListenAddr <span class="token string">"0.0.0.0:8482"</span> <span class="token punctuation">\</span>    -storageDataPath /data1/vmstorage_data <span class="token punctuation">\</span>    -retentionPeriod 60d <span class="token punctuation">\</span>    -vminsertAddr <span class="token string">"0.0.0.0:8400"</span> <span class="token punctuation">\</span>    -vmselectAddr <span class="token string">"0.0.0.0:8401"</span> <span class="token punctuation">\</span>    -dedup.minScrapeInterval<span class="token operator">=</span>30s <span class="token punctuation">\</span>    -loggerTimezone <span class="token string">"Asia/Shanghai"</span> <span class="token punctuation">\</span>    -loggerLevel INFO<span class="token assign-left variable">Restart</span><span class="token operator">=</span>always<span class="token assign-left variable">RestartSec</span><span class="token operator">=</span><span class="token number">15</span><span class="token assign-left variable">LimitNOFILE</span><span class="token operator">=</span><span class="token number">65536</span><span class="token assign-left variable">OOMScoreAdjust</span><span class="token operator">=</span>-999<span class="token punctuation">[</span>Install<span class="token punctuation">]</span><span class="token assign-left variable">WantedBy</span><span class="token operator">=</span>multi-user.target<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="vminsert"><a href="#vminsert" class="headerlink" title="vminsert"></a>vminsert</h4><p>属于无状态服务，指向所有的 vmstorage，监听端口 8480即可。</p><blockquote><p>线上可考虑将存储节点IP改为域名</p></blockquote><p>启动命令:</p><blockquote><p>主要参数：</p><ul><li>-storageNode=<vmstorage_host>:8400</li></ul></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/victoria-metrics/vminsert-prod -httpListenAddr <span class="token string">"0.0.0.0:8480"</span> <span class="token punctuation">\</span>    -storageNode <span class="token number">192.168</span>.7.33:8400,192.168.7.34:8400,192.168.7.35:8400 <span class="token punctuation">\</span>       <span class="token comment"># 指定所有storege节点</span>    -replicationFactor <span class="token number">2</span> <span class="token punctuation">\</span>                                                  <span class="token comment"># 副本数2</span>    -loggerTimezone<span class="token string">"Asia/Shanghai"</span> <span class="token punctuation">\</span>    -loggerLevel INFO<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>/etc/systemd/system/vminsert.service</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">[</span>Unit<span class="token punctuation">]</span><span class="token assign-left variable">Description</span><span class="token operator">=</span>vminsert<span class="token assign-left variable">After</span><span class="token operator">=</span>network.target<span class="token punctuation">[</span>Service<span class="token punctuation">]</span><span class="token assign-left variable">WorkingDirectory</span><span class="token operator">=</span>/usr/local/victoria-metrics<span class="token assign-left variable">ExecStart</span><span class="token operator">=</span>/usr/local/victoria-metrics/vminsert-prod -httpListenAddr <span class="token string">"0.0.0.0:8480"</span> <span class="token punctuation">\</span>    -storageNode <span class="token string">"192.168.7.33:8400,192.168.7.34:8400,192.168.7.35:8400"</span> <span class="token punctuation">\</span>    -replicationFactor <span class="token number">2</span> <span class="token punctuation">\</span>    -loggerTimezone <span class="token string">"Asia/Shanghai"</span> <span class="token punctuation">\</span>    -loggerLevel INFO<span class="token assign-left variable">Restart</span><span class="token operator">=</span>always<span class="token assign-left variable">RestartSec</span><span class="token operator">=</span><span class="token number">15</span><span class="token assign-left variable">LimitNOFILE</span><span class="token operator">=</span><span class="token number">65536</span><span class="token assign-left variable">OOMScoreAdjust</span><span class="token operator">=</span>-999<span class="token punctuation">[</span>Install<span class="token punctuation">]</span><span class="token assign-left variable">WantedBy</span><span class="token operator">=</span>multi-user.target<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li>其中，replicationFactor代表数据副本数。</li></ul><h4 id="vmselect"><a href="#vmselect" class="headerlink" title="vmselect"></a>vmselect</h4><p>属于无状态服务，指向所有的 vmstorage 的 8401 端口、所有 vmselect 的 8481 端口即可。</p><blockquote><p>线上可考虑将存储节点、查询节点IP改为域名</p></blockquote><p>启动命令:</p><blockquote><p>主要参数：</p><ul><li>selectNode=<vmselect_host>:8481</li><li>storageNode=<vmstorage_host>:8401</li></ul></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/usr/local/victoria-metrics/vmselect-prod -httpListenAddr <span class="token string">"0.0.0.0:8481"</span> <span class="token punctuation">\</span>    -selectNode <span class="token number">192.168</span>.7.33:8481,192.168.7.34:8481 <span class="token punctuation">\</span>    <span class="token comment"># select的所有节点</span>    -storageNode <span class="token number">192.168</span>.7.33:8401,192.168.7.34:8401,192.168.7.35:8401 <span class="token punctuation">\</span>   <span class="token comment"># 指定所有storage节点</span>    -dedup.minScrapeInterval<span class="token operator">=</span>30s <span class="token punctuation">\</span>                                      <span class="token comment"># 重复数据删除，如果是从Prometheus写入的话，必须和Prometheus的scrape_interval保持一致。</span>    -loggerTimezone <span class="token string">"Asia/Shanghai"</span> <span class="token punctuation">\</span>    -loggerLevel INFO<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>/etc/systemd/system/vmselect.service</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">[</span>Unit<span class="token punctuation">]</span><span class="token assign-left variable">Description</span><span class="token operator">=</span>vmselect<span class="token assign-left variable">After</span><span class="token operator">=</span>network.target<span class="token punctuation">[</span>Service<span class="token punctuation">]</span><span class="token assign-left variable">WorkingDirectory</span><span class="token operator">=</span>/usr/local/victoria-metrics<span class="token assign-left variable">ExecStart</span><span class="token operator">=</span>/usr/local/victoria-metrics/vmselect-prod -httpListenAddr <span class="token string">"0.0.0.0:8481"</span> <span class="token punctuation">\</span>    -selectNode <span class="token number">192.168</span>.7.33:8481,192.168.7.34:8481 <span class="token punctuation">\</span>    -storageNode <span class="token number">192.168</span>.7.33:8401,192.168.7.34:8401,192.168.7.35:8401 <span class="token punctuation">\</span>    -dedup.minScrapeInterval<span class="token operator">=</span>30s <span class="token punctuation">\</span>    -loggerTimezone <span class="token string">"Asia/Shanghai"</span> <span class="token punctuation">\</span>    -loggerLevel INFO<span class="token assign-left variable">Restart</span><span class="token operator">=</span>always<span class="token assign-left variable">RestartSec</span><span class="token operator">=</span><span class="token number">15</span><span class="token assign-left variable">LimitNOFILE</span><span class="token operator">=</span><span class="token number">65536</span><span class="token assign-left variable">OOMScoreAdjust</span><span class="token operator">=</span>-999<span class="token punctuation">[</span>Install<span class="token punctuation">]</span><span class="token assign-left variable">WantedBy</span><span class="token operator">=</span>multi-user.target<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="使用systemd托管应用，执行启动"><a href="#使用systemd托管应用，执行启动" class="headerlink" title="使用systemd托管应用，执行启动"></a>使用systemd托管应用，执行启动</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">cp</span> *.service /etc/systemd/system/systemctl daemon-reload<span class="token function">service</span> vmstorage start<span class="token function">service</span> vminsert start<span class="token function">service</span> vmselect start<span class="token function">service</span> vmstorage status<span class="token function">service</span> vminsert status<span class="token function">service</span> vmselect status<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="验证服务端口"><a href="#验证服务端口" class="headerlink" title="验证服务端口"></a>验证服务端口</h4><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># vmstorage</span><span class="token function">curl</span> http://192.168.7.33:8482/metrics<span class="token function">curl</span> http://192.168.7.34:8482/metrics<span class="token function">curl</span> http://192.168.7.35:8482/metrics<span class="token comment"># vminsert</span><span class="token function">curl</span> http://192.168.7.33:8480/metrics<span class="token function">curl</span> http://192.168.7.34:8480/metrics<span class="token comment"># vmselect </span><span class="token function">curl</span> http://192.168.7.33:8481/metrics<span class="token function">curl</span> http://192.168.7.34:8481/metrics<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="配置负载均衡"><a href="#配置负载均衡" class="headerlink" title="配置负载均衡"></a>配置负载均衡</h4><ul><li>写入地址格式: <code>http://&lt;vminsert&gt;:8480/insert/&lt;accountID&gt;/&lt;suffix&gt;&quot;</code><ul><li>例如: <code>http://&lt;vminsert&gt;:8480/insert/11542/prom1-online&quot;</code></li></ul></li><li>查询地址格式: <code>http://&lt;vmselect&gt;:8481/select/&lt;accountID&gt;/&lt;suffix&gt;&quot;</code><ul><li>例如: <code>http://&lt;vminsert&gt;:8481/select/11542/prom1-online&quot;</code></li></ul></li></ul><p>此时 <code>accountID</code> 必须与 <code>prometheus.yml</code> 中配置的 <code>accountID</code> 一致.</p><ul><li>suffix 后面可以是下面的字符串，和 prometheus 的 api 对应：</li></ul><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">/api/v1/query           :performs PromQL instant query/api/v1/query_range     :performs PromQL range query/api/v1/series          :performs series query/api/v1/labels                       :returns a list of label names/api/v1/label/<span class="token operator">&lt;</span>label_name<span class="token operator">></span>/values    :returns values <span class="token keyword">for</span> the given <span class="token operator">&lt;</span>label_name<span class="token operator">></span> according to API/federate                            :returns federated metrics/api/v1/export      <span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>通过 Prometheus 的 API 查询：</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> -g <span class="token string">'http://localhost:19522/api/v1/series'</span> --data-urlencode <span class="token string">'match[]=up&#123;&#125;'</span> <span class="token operator">|</span> jq<span class="token punctuation">&#123;</span>  <span class="token string">"status"</span><span class="token builtin class-name">:</span> <span class="token string">"success"</span>,  <span class="token string">"data"</span><span class="token builtin class-name">:</span> <span class="token punctuation">[</span>    <span class="token punctuation">..</span>.    <span class="token punctuation">&#123;</span>      <span class="token string">"__name__"</span><span class="token builtin class-name">:</span> <span class="token string">"up"</span>,      <span class="token string">"hostname"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab_k8s_03"</span>,      <span class="token string">"idc"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab"</span>,      <span class="token string">"instance"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.33:19523"</span>,      <span class="token string">"ip"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.33:19523"</span>,      <span class="token string">"job"</span><span class="token builtin class-name">:</span> <span class="token string">"host_node_exporter"</span>    <span class="token punctuation">&#125;</span>,    <span class="token punctuation">&#123;</span>      <span class="token string">"__name__"</span><span class="token builtin class-name">:</span> <span class="token string">"up"</span>,      <span class="token string">"hostname"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab_k8s_04"</span>,      <span class="token string">"idc"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab"</span>,      <span class="token string">"instance"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.34:19523"</span>,      <span class="token string">"ip"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.34:19523"</span>,      <span class="token string">"job"</span><span class="token builtin class-name">:</span> <span class="token string">"host_node_exporter"</span>    <span class="token punctuation">&#125;</span>,    <span class="token punctuation">&#123;</span>      <span class="token string">"__name__"</span><span class="token builtin class-name">:</span> <span class="token string">"up"</span>,      <span class="token string">"hostname"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab_k8s_05"</span>,      <span class="token string">"idc"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab"</span>,      <span class="token string">"instance"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.35:19523"</span>,      <span class="token string">"ip"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.35:19523"</span>,      <span class="token string">"job"</span><span class="token builtin class-name">:</span> <span class="token string">"host_node_exporter"</span>    <span class="token punctuation">&#125;</span>    <span class="token punctuation">..</span>.  <span class="token punctuation">]</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>通过 VictoriaMetrics 的 API 查询：</p><blockquote><p>此时还没对接监控写入，可以后续再来查询</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">curl</span> <span class="token string">'http://127.0.0.1:8481/select/386383640/prometheus/api/v1/series'</span> --data-urlencode <span class="token string">'match[]=up&#123;&#125;'</span> <span class="token operator">|</span>jq<span class="token punctuation">&#123;</span>  <span class="token string">"status"</span><span class="token builtin class-name">:</span> <span class="token string">"success"</span>,  <span class="token string">"data"</span><span class="token builtin class-name">:</span> <span class="token punctuation">[</span>    <span class="token punctuation">..</span>.    <span class="token punctuation">&#123;</span>      <span class="token string">"__name__"</span><span class="token builtin class-name">:</span> <span class="token string">"up"</span>,      <span class="token string">"hostname"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab_k8s_03"</span>,      <span class="token string">"idc"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab"</span>,      <span class="token string">"instance"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.33:19523"</span>,      <span class="token string">"ip"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.33:19523"</span>,      <span class="token string">"job"</span><span class="token builtin class-name">:</span> <span class="token string">"host_node_exporter"</span>    <span class="token punctuation">&#125;</span>,    <span class="token punctuation">&#123;</span>      <span class="token string">"__name__"</span><span class="token builtin class-name">:</span> <span class="token string">"up"</span>,      <span class="token string">"hostname"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab_k8s_04"</span>,      <span class="token string">"idc"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab"</span>,      <span class="token string">"instance"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.34:19523"</span>,      <span class="token string">"ip"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.34:19523"</span>,      <span class="token string">"job"</span><span class="token builtin class-name">:</span> <span class="token string">"host_node_exporter"</span>    <span class="token punctuation">&#125;</span>,    <span class="token punctuation">&#123;</span>      <span class="token string">"__name__"</span><span class="token builtin class-name">:</span> <span class="token string">"up"</span>,      <span class="token string">"hostname"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab_k8s_05"</span>,      <span class="token string">"idc"</span><span class="token builtin class-name">:</span> <span class="token string">"homelab"</span>,      <span class="token string">"instance"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.35:19523"</span>,      <span class="token string">"ip"</span><span class="token builtin class-name">:</span> <span class="token string">"192.168.7.35:19523"</span>,      <span class="token string">"job"</span><span class="token builtin class-name">:</span> <span class="token string">"host_node_exporter"</span>    <span class="token punctuation">&#125;</span>    <span class="token punctuation">..</span>.  <span class="token punctuation">]</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><blockquote><ul><li>每个 accountID 和 projectID 由范围 [0 … 2^32) 中的任意 32 位整数标识。如果不指定，则默自动分配为 0.</li><li>当第一个数据点写入给定租户时，会自动创建租户</li><li>所有租户的数据均匀分布在可用的 vmstorage 节点中。这保证了当不同租户具有不同的数据量和不同的查询负载时，vmstorage 节点之间的负载均匀</li><li>数据库性能依赖于租户的数量，主要取决于所有租户中活动的时间序列的总数.</li><li>VictoriaMetrics 不支持在单个请求中查询多个租户</li></ul></blockquote><p>vm-components.nestealin.com.conf</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">upstream</span>  vmselect</span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">server</span>  192.168.7.33:8481 weight=5</span> <span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server</span>  192.168.7.34:8481 weight=5</span> <span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token directive"><span class="token keyword">upstream</span> vminsert</span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">server</span>  192.168.7.33:8480 weight=5</span> <span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server</span>  192.168.7.34:8480 weight=5</span> <span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span> <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span> vm-select.nestealin.com</span><span class="token punctuation">;</span>    <span class="token comment">#auth_basic "authentication";                # 开启基本认证</span>    <span class="token comment">#auth_basic_user_file conf.d/.htpasswd;      # 密码文件</span>    <span class="token directive"><span class="token keyword">include</span> firewall.conf</span><span class="token punctuation">;</span>      <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">proxy_pass</span> http://vmselect/select/386383640/prometheus/</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span> <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span> vm-insert.nestealin.com</span><span class="token punctuation">;</span>    <span class="token comment">#auth_basic "authentication";                # 开启基本认证</span>    <span class="token comment">#auth_basic_user_file conf.d/.htpasswd;      # 密码文件</span>    <span class="token directive"><span class="token keyword">include</span> firewall.conf</span><span class="token punctuation">;</span>      <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">proxy_pass</span> http://vminsert/insert/386383640/prometheus/</span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="监控对接"><a href="#监控对接" class="headerlink" title="监控对接"></a>监控对接</h3><p>Prometheus通过remote_write写入vm集群</p><blockquote><p>官方文档：<a href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write">https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write</a></p></blockquote><pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token key atrule">remote_write</span><span class="token punctuation">:</span><span class="token comment"># 通过负载均衡地址</span><span class="token punctuation">-</span> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"http://vm-insert.nestealin.com/api/v1/write"</span><span class="token comment"># 直接连接vminsert组件</span><span class="token comment"># - url: "http://192.168.7.33:8480/insert/386383640/prometheus/api/v1/write"</span>  <span class="token comment"># basic_auth:</span>    <span class="token comment"># username: admin</span>    <span class="token comment"># password: 123456</span>  <span class="token key atrule">remote_timeout</span><span class="token punctuation">:</span> 30s  <span class="token key atrule">tls_config</span><span class="token punctuation">:</span>    <span class="token key atrule">insecure_skip_verify</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>  <span class="token key atrule">queue_config</span><span class="token punctuation">:</span>    <span class="token key atrule">capacity</span><span class="token punctuation">:</span> <span class="token number">2500</span>    <span class="token key atrule">max_shards</span><span class="token punctuation">:</span> <span class="token number">200</span>    <span class="token key atrule">min_shards</span><span class="token punctuation">:</span> <span class="token number">1</span>    <span class="token key atrule">max_samples_per_send</span><span class="token punctuation">:</span> <span class="token number">500</span>    <span class="token key atrule">batch_send_deadline</span><span class="token punctuation">:</span> 5s    <span class="token key atrule">min_backoff</span><span class="token punctuation">:</span> 30ms    <span class="token key atrule">max_backoff</span><span class="token punctuation">:</span> 5s<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h4 id="UI验证"><a href="#UI验证" class="headerlink" title="UI验证"></a>UI验证</h4><blockquote><p>使用PromQL语法查询，地址格式: <code>http://$&#123;vmselect服务IP&#125;:$&#123;vmselect服务端口&#125;/select/$&#123;accountID&#125;/$&#123;suffix&#125;</code></p></blockquote><p><a href="http://192.168.7.33:8481/select/386383640/vmui/?g0.range_input=5m&amp;g0.end_input=2022-09-12T15:53:49&amp;g0.step_input=0.586&amp;g0.relative_time=last_5_minutes&amp;g0.tab=chart&amp;g0.expr=up%7B%7D">http://192.168.7.33:8481/select/386383640/vmui/?g0.range_input=5m&amp;g0.end_input=2022-09-12T15%3A53%3A49&amp;g0.step_input=0.586&amp;g0.relative_time=last_5_minutes&amp;g0.tab=chart&amp;g0.expr=up%7B%7D</a></p><img src="/7dbee069/1f51448a72a39fad4dc4ee6162c098b2.png" class=""><h4 id="写入验证"><a href="#写入验证" class="headerlink" title="写入验证"></a>写入验证</h4><p>查看vmstorage日志验证写入信息</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">Sep <span class="token number">12</span> <span class="token number">23</span>:43:35 homelab-k8s-03 vmstorage-prod<span class="token punctuation">[</span><span class="token number">27403</span><span class="token punctuation">]</span>: <span class="token number">2022</span>-09-12T23:43:35.759+0800        info        VictoriaMetrics/lib/storage/partition.go:211        creating a partition <span class="token string">"2022_09"</span> with <span class="token assign-left variable">smallPartsPath</span><span class="token operator">=</span><span class="token string">"/data1/vmstorage_data/data/small/2022_09"</span>, <span class="token assign-left variable">bigPartsPath</span><span class="token operator">=</span><span class="token string">"/data1/vmstorage_data/data/big/2022_09"</span>Sep <span class="token number">12</span> <span class="token number">23</span>:43:35 homelab-k8s-03 vmstorage-prod<span class="token punctuation">[</span><span class="token number">27403</span><span class="token punctuation">]</span>: <span class="token number">2022</span>-09-12T23:43:35.769+0800        info        VictoriaMetrics/lib/storage/partition.go:227        partition <span class="token string">"2022_09"</span> has been createdSep <span class="token number">12</span> <span class="token number">23</span>:43:41 homelab-k8s-03 vmstorage-prod<span class="token punctuation">[</span><span class="token number">27403</span><span class="token punctuation">]</span>: <span class="token number">2022</span>-09-12T23:43:41.787+0800        info        VictoriaMetrics/lib/vmselectapi/server.go:132        accepted vmselect conn from <span class="token number">192.168</span>.7.33:51060Sep <span class="token number">12</span> <span class="token number">23</span>:43:41 homelab-k8s-03 vmstorage-prod<span class="token punctuation">[</span><span class="token number">27403</span><span class="token punctuation">]</span>: <span class="token number">2022</span>-09-12T23:43:41.793+0800        info        VictoriaMetrics/lib/vmselectapi/server.go:175        processing vmselect conn from <span class="token number">192.168</span>.7.33:51060<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><h4 id="Grafana配置数据源"><a href="#Grafana配置数据源" class="headerlink" title="Grafana配置数据源"></a>Grafana配置数据源</h4><blockquote><p>如果有配置HTTP用户认证，请开启 <code>Basic auth</code> 选项。</p></blockquote><p>填入查询URL: <a href="http://vm-select.nestealin.com/">http://vm-select.nestealin.com</a> ，其余保持默认即可。</p><img src="/7dbee069/0a3bb92444747f4193d5e2a633108ed.png" class=""><p>查询相关监控指标 </p><img src="/7dbee069/80b1642292b72603794a34aaf3b2ff12.png" class=""><p>至此，已完成基本的 VM 分布式数据集群部署。</p><p>如有生产要求的，可根据模块拆分，将无状态的服务放到 K8S 中运行，对数据节点进行磁盘性能及数据高可用优化。</p><hr><h2 id="相关文档"><a href="#相关文档" class="headerlink" title="相关文档"></a>相关文档</h2><ul><li>官网：<a href="https://victoriametrics.com/">https://victoriametrics.com</a></li><li>官方文档：<a href="https://docs.victoriametrics.com/">https://docs.victoriametrics.com</a></li><li>GitHub：<a href="https://github.com/VictoriaMetrics/VictoriaMetrics">https://github.com/VictoriaMetrics/VictoriaMetrics</a></li><li>集群模式详细文档：<a href="https://p8s.io/docs/victoriametrics/cluster/">https://p8s.io/docs/victoriametrics/cluster/</a></li><li>基于VictoriaMetrics的大规模监控实战: <a href="https://zahui.fan/posts/e59d8e32/">https://zahui.fan/posts/e59d8e32/</a></li><li>Victoria Metrics 学习: <a href="https://www.lijiaocn.com/%E9%A1%B9%E7%9B%AE/2020/02/24/prometheus-scale-out-2.html">https://www.lijiaocn.com/项目/2020/02/24/prometheus-scale-out-2.html</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;当前单节点Prometheus集中存储多个集群数据，数据单点且索引性能低下，官方架构问题无法横向扩展优化。&lt;/p&gt;
&lt;h2 id=&quot;目的&quot;&gt;</summary>
      
    
    
    
    <category term="linux" scheme="https://nestealin.com/categories/linux/"/>
    
    
    <category term="Prometheus" scheme="https://nestealin.com/tags/Prometheus/"/>
    
    <category term="VictoriaMetrics" scheme="https://nestealin.com/tags/VictoriaMetrics/"/>
    
    <category term="分布式数据存储" scheme="https://nestealin.com/tags/%E5%88%86%E5%B8%83%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8/"/>
    
  </entry>
  
  <entry>
    <title>小心Alias引发的静态资源目录穿越</title>
    <link href="https://nestealin.com/caf822db/"/>
    <id>https://nestealin.com/caf822db/</id>
    <published>2022-07-15T04:53:58.000Z</published>
    <updated>2024-06-29T07:26:38.975Z</updated>
    
    <content type="html"><![CDATA[<h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>Nginx是一个高性能的HTTP和反向代理服务器，经常被做为反向代理，动态的部分被proxy_pass传递给后端端口，而静态文件需要Nginx来处理。</p><p>而本次提及的漏洞是出现在服务器的静态文件中。</p><ul><li><p>什么是 Nginx alias 目录穿越？</p><p>如果静态文件存储在 <code>/home/</code> 目录下，而该目录在url中名字为files，那么就需要用alias设置目录的别名。</p><p>Nginx在配置别名(Alias)的时候，如果忘记加 <code>/</code> ，将造成一个目录穿越漏洞。</p></li></ul><hr><h3 id="目的"><a href="#目的" class="headerlink" title="目的"></a>目的</h3><ol><li>目录穿越如何产生/复现/实现原理？</li><li>实现目录穿越后，对应的相对目录是什么？</li><li>如何修复？</li></ol><hr><h3 id="环境描述"><a href="#环境描述" class="headerlink" title="环境描述"></a>环境描述</h3><ul><li><p>静态资源目录: <code>/data1/web_static/test_file</code></p></li><li><p>正常静态资源文件: <code>/data1/web_static/test_file/index.html</code></p><pre class="line-numbers language-html" data-language="html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>zh-CN<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>   Hello.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></li><li><p>直接上层静态资源1（目录穿越后验证）: /data1/web_static/test.html</p><pre class="line-numbers language-html" data-language="html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>zh-CN<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>    Bravo!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></li><li><p>隔级上层静态资源2（目录穿越后验证）: /data1/test2.html</p><pre class="line-numbers language-html" data-language="html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>zh-CN<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>    Aloha!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre></li><li><p>Nginx配置</p></li></ul><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span>  <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span>  alias-test.nestealin.com</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">charset</span> utf-8</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">access_log</span>  logs/alias.nestealin.com.access.main.log  main</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">error_log</span>  logs/alias.nestealin.com.error.log error</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">location</span> /file</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">alias</span> /data1/web_static/test_file/</span> <span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    <span class="token directive"><span class="token keyword">location</span> /</span> <span class="token punctuation">&#123;</span>      <span class="token directive"><span class="token keyword">add_header</span> Content-Type application/json</span> <span class="token punctuation">;</span>      <span class="token directive"><span class="token keyword">return</span> <span class="token number">200</span> <span class="token string">'&#123;"remote_addr":"<span class="token variable">$remote_addr</span>","remote_port":"<span class="token variable">$remote_port</span>","clientRealIp":"<span class="token variable">$clientRealIp</span>","time_local":"<span class="token variable">$time_local</span>"&#125;'</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><ul><li><p>Nginx进程运行用户</p><ul><li>主进程为 root 用户</li><li>worker进程为 www 用户</li></ul><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># ps -ef | grep nginx</span>root       <span class="token number">643</span>     <span class="token number">1</span>  <span class="token number">0</span> Jul07 ?        00:00:00 nginx: master process <span class="token punctuation">..</span>/<span class="token punctuation">..</span>/sbin/nginxwww       <span class="token number">8513</span>   <span class="token number">643</span>  <span class="token number">0</span> <span class="token number">12</span>:45 ?        00:00:00 nginx: worker processwww       <span class="token number">8514</span>   <span class="token number">643</span>  <span class="token number">0</span> <span class="token number">12</span>:45 ?        00:00:00 nginx: worker process<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre></li></ul><hr><h3 id="场景复现"><a href="#场景复现" class="headerlink" title="场景复现"></a>场景复现</h3><p>在如下配置中设置目录别名时 <code>/file</code> 配置为 /data1/web_static/test_file/ 的别名，那么当我们访问 <code>/file../</code> 时，nginx实际处理的路径时 <code>/data1/web_static/test_file/../</code>，从而实现了穿越目录。</p><h4 id="正常请求"><a href="#正常请求" class="headerlink" title="正常请求"></a>正常请求</h4><p>访问 <code>http://alias-test.nestealin.com/file/index.html</code> </p><img src="/caf822db/5bfdb3ba25544929acae91e6040a2299.png" class=""><p>请求日志 <code>$request</code> : <code>GET /file/index.html HTTP/1.1</code></p><h4 id="尝试穿越至直接上层"><a href="#尝试穿越至直接上层" class="headerlink" title="尝试穿越至直接上层"></a>尝试穿越至直接上层</h4><p>访问 <code>http://alias-test.nestealin.com/file../test.html</code> 成功</p><img src="/caf822db/23967d5351ad475abd4ed93e21e0cf51.png" class=""><ul><li>请求日志 <code>$request</code> : <code>&quot;GET /file../test.html HTTP/1.1</code></li></ul><h4 id="尝试穿越至隔级上层"><a href="#尝试穿越至隔级上层" class="headerlink" title="尝试穿越至隔级上层"></a>尝试穿越至隔级上层</h4><p>访问 <code>http://alias-test.nestealin.com/file../../test.html</code> 跳转至默认 location </p><img src="/caf822db/963a8f0916374afcadda0d136fb5e15d.png" class=""><ul><li>请求日志 <code>$request</code> : <code>GET /test2.html HTTP/1.1</code></li></ul><hr><h3 id="穿越后目录用户验证"><a href="#穿越后目录用户验证" class="headerlink" title="穿越后目录用户验证"></a>穿越后目录用户验证</h3><p>将穿越后目标 html 文件 修改属主权限为 root 用户只读</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">chmod</span> <span class="token number">400</span> /data1/web_static/test.html<span class="token function">chown</span> root.root /data1/web_static/test.html<span class="token comment"># 验证权限</span><span class="token comment"># ll /data1/web_static/test.html</span>-r-------- <span class="token number">1</span> root root <span class="token number">45</span> Jul  <span class="token number">7</span> <span class="token number">12</span>:51 /data1/web_static/test.html<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>尝试访问目录穿越文件 <code>http://alias-test.nestealin.com/file../test.html</code> 提示 403 。 </p><img src="/caf822db/422c44e1db414f0cb5ad7efb2a26f71b.png" class=""><p>修改属主权限为 www 用户只读</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># chown www.www /data1/web_static/test.html</span><span class="token comment"># ll /data1/web_static/test.html</span>-r-------- <span class="token number">1</span> www www <span class="token number">45</span> Jul  <span class="token number">7</span> <span class="token number">12</span>:51 /data1/web_static/test.html<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>尝试访问目录穿越文件 <code>http://alias-test.nestealin.com/file../test.html</code> 访问成功 。</p><img src="/caf822db/4ddeb4710a0b487eaa04635e4a321892.png" class=""><p>所以，执行目录文件读取的均为 Nginx 的 worker 进程，符合预期。</p><hr><h3 id="修复方式"><a href="#修复方式" class="headerlink" title="修复方式"></a>修复方式</h3><p>将 <code>/file</code> 这个 location 指令闭环即可。</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">location</span> /file/</span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">alias</span> /data1/web_static/test_file/</span> <span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><p>验证<strong>常规</strong>页面访问 <code>http://alias-test.nestealin.com/file/index.html</code> </p><img src="/caf822db/d083a64728104369b5b719eeec64a40b.png" class=""><p><strong>正常</strong>，常规页面访问未受影响。</p><p>验证<strong>穿越</strong>页面访问 <code>http://alias-test.nestealin.com/file../test.html</code> </p><img src="/caf822db/12008e453ed0441cbc7fc34c76d6397c.png" class=""><p><strong>符合预期</strong>，跳转至默认 location ，漏洞修复。</p><hr><h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><h4 id="1-目录穿越如何产生-复现-实现原理？"><a href="#1-目录穿越如何产生-复现-实现原理？" class="headerlink" title="1. 目录穿越如何产生/复现/实现原理？"></a>1. 目录穿越如何产生/复现/实现原理？</h4><p>由于 location 中目标路径未闭合导致相对路径穿越</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">location</span> /file</span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">alias</span> /data1/web_static/test_file/</span> <span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h4 id="2-实现目录穿越后，对应的相对目录是什么？"><a href="#2-实现目录穿越后，对应的相对目录是什么？" class="headerlink" title="2. 实现目录穿越后，对应的相对目录是什么？"></a>2. 实现目录穿越后，对应的相对目录是什么？</h4><p>目录穿越后，是 Alias 目标目录的上一层，<strong>并且只能穿越一层目录</strong>。</p><h4 id="3-如何修复？"><a href="#3-如何修复？" class="headerlink" title="3. 如何修复？"></a>3. 如何修复？</h4><p>闭合 location 路径即可。</p><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">location</span> /file/</span> <span class="token punctuation">&#123;</span>      <span class="token directive"><span class="token keyword">alias</span> /data1/web_static/test_file/</span> <span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h4 id="4-危害程度"><a href="#4-危害程度" class="headerlink" title="4. 危害程度"></a>4. 危害程度</h4><ol><li>目标路径是否有其它敏感资源</li><li>相对目录是否均为 Nginx worker 进程可读</li><li>如果开了 <code>autoindex</code> 会将目录结构直接暴露在他人之下</li><li>复杂用法下，同样要注意执行 <code>rewrite</code> 、<code>try_files</code> 时是否会触及该漏洞</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h3&gt;&lt;p&gt;Nginx是一个高性能的HTTP和反向代理服务器，经常被做为反向代理，动态的部分被proxy_pass传递给后端端口，而静态文件需要Ngin</summary>
      
    
    
    
    <category term="nginx" scheme="https://nestealin.com/categories/nginx/"/>
    
    
    <category term="目录穿越" scheme="https://nestealin.com/tags/%E7%9B%AE%E5%BD%95%E7%A9%BF%E8%B6%8A/"/>
    
    <category term="漏洞" scheme="https://nestealin.com/tags/%E6%BC%8F%E6%B4%9E/"/>
    
  </entry>
  
  <entry>
    <title>LookingGlass服务端网络探测工具部署</title>
    <link href="https://nestealin.com/bcb1d8c6/"/>
    <id>https://nestealin.com/bcb1d8c6/</id>
    <published>2022-07-02T15:15:13.000Z</published>
    <updated>2024-06-29T07:26:38.818Z</updated>
    
    <content type="html"><![CDATA[<h2 id="项目背景"><a href="#项目背景" class="headerlink" title="项目背景"></a>项目背景</h2><p>由于原始项目： <a href="https://github.com/telephone/LookingGlass/">https://github.com/telephone/LookingGlass/</a></p><p>原作者已有数年未更新维护且项目仅为英文版 ( 最新版本号: v1.3.0 ) ，所以本次采用国人基于原项目 v1.3.0 进行一些汉化及优化版本。</p><ul><li>Fork后的修改:</li></ul><ol><li>修改IPv4下的路由追踪，结果将包含由IPIP提供的IP地理信息数据</li><li>修改configure.sh文件测试文件生成方式，改由DD命令生成测试文件</li><li>汉化index.php文件，并适度修改底部作者信息</li><li>添加英文页面，调整路由追踪结果语言</li><li>修改IPv6下的路由追踪，结果将包含由IPIP提供的IP地理信息数据</li></ol><p>项目地址：<a href="https://github.com/ILLKX/LookingGlass">https://github.com/ILLKX/LookingGlass</a></p><hr><h2 id="部署流程"><a href="#部署流程" class="headerlink" title="部署流程"></a>部署流程</h2><h3 id="环境要求"><a href="#环境要求" class="headerlink" title="环境要求"></a>环境要求</h3><ul><li>PHP &gt;= 5.3</li><li>PHP PDO with SQLite driver (required for rate-limit)</li><li>SSH/Terminal access (able to install commands/functions if non-existent)</li></ul><h3 id="环境安装"><a href="#环境安装" class="headerlink" title="环境安装"></a>环境安装</h3><blockquote><p>此处忽略Nginx安装，请自行准备</p></blockquote><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">rpm</span> -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm<span class="token function">rpm</span> -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpmyum <span class="token function">install</span> -y php55w-fpm php55w-pdo<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre><h3 id="项目包准备"><a href="#项目包准备" class="headerlink" title="项目包准备"></a>项目包准备</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">mkdir</span> /opt/web_static<span class="token builtin class-name">cd</span> /opt/web_static/<span class="token function">wget</span> https://github.com/ILLKX/LookingGlass/archive/master.zip<span class="token function">unzip</span> master.zipLookingGlass-master/LookingGlass<span class="token comment"># 执行安装，脚本会自行安装相关依赖及编译</span>./configure.sh<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p><em>在安装最后会有如下提示指引你做初始配置</em></p><p>配置流程:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token comment">###                    ###</span><span class="token comment"># Starting configuration #</span><span class="token comment">###                    ###</span>Running setup:Enter your website name <span class="token punctuation">(</span>Header/Logo<span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>: NesNodeEnter the public URL to this LG <span class="token punctuation">(</span>including http://<span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>: https://looking-glass.nestealin.comEnter the servers location <span class="token punctuation">[</span><span class="token punctuation">]</span>: AUS-SYD-1-NodeEnter the <span class="token builtin class-name">test</span> IPv4 address <span class="token punctuation">[</span><span class="token punctuation">]</span>: <span class="token number">8.8</span>.8.8Enter the <span class="token builtin class-name">test</span> IPv6 address <span class="token punctuation">(</span>Re-enter everytime this script is run<span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>:Enter the size of <span class="token builtin class-name">test</span> files <span class="token keyword">in</span> MB <span class="token punctuation">(</span>Example: <span class="token number">25</span> <span class="token number">50</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>: <span class="token number">25</span>Do you wish to <span class="token builtin class-name">enable</span> rate limiting of network commands? <span class="token punctuation">(</span>y/n<span class="token punctuation">)</span>: yEnter the <span class="token comment"># of commands allowed per hour (per IP) []: 5</span>Removing old <span class="token builtin class-name">test</span> files:Creating new <span class="token builtin class-name">test</span> files:Creating 25MB <span class="token builtin class-name">test</span> <span class="token function">file</span>Would you like to choose a different theme? <span class="token punctuation">(</span>y/n<span class="token punctuation">)</span>: nCreating Config.php<span class="token punctuation">..</span>.Creating SQLite database<span class="token punctuation">..</span>.Enter the username of your webserver <span class="token punctuation">(</span>E.g. www-data<span class="token punctuation">)</span>: wwwEnter the user group of your webserver <span class="token punctuation">(</span>E.g. www-data<span class="token punctuation">)</span>: wwwFixing MTR permissions<span class="token punctuation">..</span>.Fixing besttrace permissions<span class="token punctuation">..</span>.Installation is complete<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h3 id="PHP-FPM配置"><a href="#PHP-FPM配置" class="headerlink" title="PHP-FPM配置"></a>PHP-FPM配置</h3><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">vi</span> /etc/php-fpm.d/www.conf<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre><p>将 <code>listen</code> 、 <code>user</code> 、 <code>group</code> 三个参数注释，并添加如下配置：</p><pre class="line-numbers language-ini" data-language="ini"><code class="language-ini"><span class="token key attr-name">listen</span> <span class="token punctuation">=</span> <span class="token value attr-value">/var/run/php5-fpm.sock</span><span class="token key attr-name">listen.owner</span> <span class="token punctuation">=</span> <span class="token value attr-value">www</span><span class="token key attr-name">listen.owner</span> <span class="token punctuation">=</span> <span class="token value attr-value">www</span><span class="token key attr-name">user</span> <span class="token punctuation">=</span> <span class="token value attr-value">www</span><span class="token key attr-name">group</span> <span class="token punctuation">=</span> <span class="token value attr-value">www</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>用于对接Nginx，<strong>请确保Nginx与PHP-FPM运行的系统用户一致</strong>。</p><h3 id="Nginx配置参考"><a href="#Nginx配置参考" class="headerlink" title="Nginx配置参考"></a>Nginx配置参考</h3><pre class="line-numbers language-nginx" data-language="nginx"><code class="language-nginx"><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span>  <span class="token number">80</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span> lookingglass.nestealin.com</span> <span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">rewrite</span> ^(.*)$  https://<span class="token variable">$host</span><span class="token variable">$1</span> permanent</span><span class="token punctuation">;</span><span class="token punctuation">&#125;</span><span class="token directive"><span class="token keyword">server</span></span> <span class="token punctuation">&#123;</span>    <span class="token directive"><span class="token keyword">listen</span>    <span class="token number">443</span> ssl</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">server_name</span>  lookingglass.nestealin.com</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">access_log</span>  logs/<span class="token variable">$http_host.access.main.log</span>  main</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">error_log</span>  logs/lookingglass.nestealin.com.error.log error</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">ssl_certificate</span>      keys/server.cer</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">ssl_certificate_key</span>  keys/server.key</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">ssl_session_timeout</span>  <span class="token number">5m</span></span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">ssl_protocols</span> TLSv1 TLSv1.1 TLSv1.2</span> <span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">root</span> /opt/web_static/LookingGlass-master</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">set</span> <span class="token variable">$cgi_pass</span> <span class="token string">'unix:/var/run/php5-fpm.sock'</span></span><span class="token punctuation">;</span>    <span class="token comment">############# DO NOT EDIT BELOW THIS LINE #############</span>    <span class="token comment"># Do not send Nginx version</span>    <span class="token directive"><span class="token keyword">server_tokens</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>    <span class="token comment"># Set index and use UTF-8</span>    <span class="token directive"><span class="token keyword">index</span> index.php</span><span class="token punctuation">;</span>    <span class="token directive"><span class="token keyword">charset</span> utf-8</span><span class="token punctuation">;</span>    <span class="token comment"># Avoid clickjacking. If you need to allow [i]frames, you can use SAMEORIGIN</span>    <span class="token comment"># or even set an uri with ALLOW-FROM uri</span>    <span class="token directive"><span class="token keyword">add_header</span> X-Frame-Options DENY</span><span class="token punctuation">;</span>    <span class="token comment"># This header enables the Cross-site scripting (XSS) filter built into most</span>    <span class="token comment"># recent web browsers. It's usually enabled by default anyway, so the role</span>    <span class="token comment"># of this header is to re-enable the filter</span>    <span class="token directive"><span class="token keyword">add_header</span> X-XSS-Protection <span class="token string">"1; mode=block"</span></span><span class="token punctuation">;</span>    <span class="token comment"># Validate request type</span>    <span class="token directive"><span class="token keyword">if</span> (<span class="token variable">$request_method</span> !~ ^(GET|HEAD|POST)$ )</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">return</span> <span class="token number">403</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    <span class="token comment"># Disable log for favicon.ico</span>    <span class="token directive"><span class="token keyword">location</span> = /favicon.ico</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">log_not_found</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">access_log</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    <span class="token comment"># Disable log for robots.txt</span>    <span class="token directive"><span class="token keyword">location</span> = /robots.txt</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">allow</span> all</span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">log_not_found</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">access_log</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    <span class="token comment"># Deny access to private folder/s</span>    <span class="token comment"># Assumes LookingGlass is on a root install</span>    <span class="token directive"><span class="token keyword">location</span> ~ ^/LookingGlass</span> <span class="token punctuation">&#123;</span>       <span class="token directive"><span class="token keyword">deny</span> all</span><span class="token punctuation">;</span>       <span class="token directive"><span class="token keyword">return</span> <span class="token number">404</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    <span class="token comment"># Deny access to hidden files/folders</span>    <span class="token directive"><span class="token keyword">location</span> ~ /\.</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">deny</span> all</span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">access_log</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">log_not_found</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">return</span> <span class="token number">404</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    <span class="token comment"># CSS/IMG/JS caching policy. Access log is turned off by default</span>    <span class="token directive"><span class="token keyword">location</span> ~* \.(?:css|js|gif|jpe?g|png)$</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">access_log</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">expires</span> <span class="token number">30d</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">add_header</span> Cache-Control public</span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">break</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    <span class="token comment"># Disable Gzip for test files</span>    <span class="token directive"><span class="token keyword">location</span> ~* \.test$</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">gzip</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">sendfile</span> <span class="token boolean">on</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span>    <span class="token comment"># Full PHP setup. No includes necessary</span>    <span class="token directive"><span class="token keyword">location</span> ~ \.php$</span> <span class="token punctuation">&#123;</span>        <span class="token directive"><span class="token keyword">fastcgi_pass</span> <span class="token variable">$cgi_pass</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_index</span> index.php</span><span class="token punctuation">;</span>        <span class="token comment"># FastCGI params</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   SCRIPT_FILENAME         <span class="token variable">$document_root</span><span class="token variable">$fastcgi_script_name</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   QUERY_STRING            <span class="token variable">$query_string</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   REQUEST_METHOD          <span class="token variable">$request_method</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   CONTENT_TYPE            <span class="token variable">$content_type</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   CONTENT_LENGTH          <span class="token variable">$content_length</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   SCRIPT_FILENAME         <span class="token variable">$request_filename</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   SCRIPT_NAME             <span class="token variable">$fastcgi_script_name</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   REQUEST_URI             <span class="token variable">$request_uri</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   DOCUMENT_URI            <span class="token variable">$document_uri</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   DOCUMENT_ROOT           <span class="token variable">$document_root</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   SERVER_PROTOCOL         <span class="token variable">$server_protocol</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   GATEWAY_INTERFACE       CGI/1.1</span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   SERVER_SOFTWARE         nginx</span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   REMOTE_ADDR             <span class="token variable">$remote_addr</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   REMOTE_PORT             <span class="token variable">$remote_port</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   SERVER_ADDR             <span class="token variable">$server_addr</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   SERVER_PORT             <span class="token variable">$server_port</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   SERVER_NAME             <span class="token variable">$server_name</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   HTTPS                   <span class="token variable">$https</span> if_not_empty</span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_param</span>   REDIRECT_STATUS         <span class="token number">200</span></span><span class="token punctuation">;</span>        <span class="token comment"># Enable output buffering</span>        <span class="token directive"><span class="token keyword">try_files</span> <span class="token variable">$uri</span> = <span class="token number">404</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_buffering</span>          <span class="token boolean">on</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_buffer_size</span>        <span class="token number">1k</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_buffers</span>            <span class="token number">128</span> <span class="token number">1k</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">fastcgi_max_temp_file_size</span> <span class="token number">0</span></span><span class="token punctuation">;</span>        <span class="token directive"><span class="token keyword">gzip</span> <span class="token boolean">off</span></span><span class="token punctuation">;</span>    <span class="token punctuation">&#125;</span><span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>启动 PHP-FPM 及 reload Nginx 即可完成部署</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">service</span> php-fpm start<span class="token function">chkconfig</span> php-fpm on<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><hr><h2 id="访问验证"><a href="#访问验证" class="headerlink" title="访问验证"></a>访问验证</h2><p>访问地址：<a href="https://lookingglass.nestealin.com/">https://lookingglass.nestealin.com/</a></p><h3 id="Host"><a href="#Host" class="headerlink" title="Host"></a>Host</h3><p>用于获取域名DNS解析 <img src="/bcb1d8c6/dfcf1f89b89a4fffa804142a0d191c91.png" class="" title="Host功能"></p><h3 id="MTR"><a href="#MTR" class="headerlink" title="MTR"></a>MTR</h3><p>用于检测远程主机到目标主机的时延信息 <img src="/bcb1d8c6/8ef118f7e2ea466493e6852e3e07245a.png" class="" title="MTR功能"></p><h3 id="Traceroute-Besttrace"><a href="#Traceroute-Besttrace" class="headerlink" title="Traceroute/Besttrace"></a>Traceroute/Besttrace</h3><p>用于检测远程主机到目标主机的路由线路走向 <img src="/bcb1d8c6/5d3b2758aa244b36ac6e74fc799bdd96.png" class="" title="Traceroute功能"></p><h3 id="触发限频"><a href="#触发限频" class="headerlink" title="触发限频"></a>触发限频</h3><img src="/bcb1d8c6/5dc33458831544a783dc6e27f8771fdc.png" class="" title="触发限频"><hr><h2 id="可能遇到的问题"><a href="#可能遇到的问题" class="headerlink" title="可能遇到的问题"></a>可能遇到的问题</h2><ol><li><p>执行traceroute时没有反应</p><p>请确保运行 PHP-FPM 的系统用户有权限执行besttrace命令； 如果本机已存在besttrace也请确保有相关执行权限。</p><p>解决方式参考:</p><pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token function">chown</span> root.root /usr/local/besttrace/besttrace<span class="token function">chmod</span> +s /usr/local/besttrace/besttrace<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre></li></ol><hr><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>暴雪战网的Looking-Glass： <a href="https://looking-glass.battlenet.com.cn/?lang=zh_Hans_CN">https://looking-glass.battlenet.com.cn/?lang=zh_Hans_CN</a></p><p>Vultr的Looking-Glass: <a href="https://sgp-ping.vultr.com/">https://sgp-ping.vultr.com/</a></p><p>Bandwagon的Looking-Glass: <a href="https://dc3.bwg.net/lg/">https://dc3.bwg.net/lg/</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;项目背景&quot;&gt;&lt;a href=&quot;#项目背景&quot; class=&quot;headerlink&quot; title=&quot;项目背景&quot;&gt;&lt;/a&gt;项目背景&lt;/h2&gt;&lt;p&gt;由于原始项目： &lt;a href=&quot;https://github.com/telephone/LookingGlass/&quot;&gt;h</summary>
      
    
    
    
    <category term="network" scheme="https://nestealin.com/categories/network/"/>
    
    
    <category term="mtr" scheme="https://nestealin.com/tags/mtr/"/>
    
    <category term="traceroute" scheme="https://nestealin.com/tags/traceroute/"/>
    
    <category term="besttrace" scheme="https://nestealin.com/tags/besttrace/"/>
    
    <category term="回程路由" scheme="https://nestealin.com/tags/%E5%9B%9E%E7%A8%8B%E8%B7%AF%E7%94%B1/"/>
    
    <category term="回程线路" scheme="https://nestealin.com/tags/%E5%9B%9E%E7%A8%8B%E7%BA%BF%E8%B7%AF/"/>
    
  </entry>
  
</feed>
